package net.sf.jabref.export.layout.format;

import net.sf.jabref.export.layout.*;
import net.sf.jabref.Globals;

/**
 * Transform a LaTeX-String to RTF.
 * 
 * This method will:
 * 
 *   1.) Remove LaTeX-Command sequences.
 *   
 *   2.) Replace LaTeX-Special chars with RTF aquivalents.
 *   
 *   3.) Replace emph and textit and textbf with their RTF replacements.
 *   
 *   4.) Take special care to save all unicode characters correctly. 
 * 
 * @author $Author: coezbek $
 * @version $Revision: 1896 $ ($Date: 2007-01-19 01:12:49 +0100 (Fri, 19 Jan 2007) $)
 *
 */
public class RTFChars implements LayoutFormatter {

	public String format(String field) {

		StringBuffer sb = new StringBuffer("");
		StringBuffer currentCommand = null;
		boolean escaped = false, incommand = false;
		for (int i = 0; i < field.length(); i++) {
			char c = field.charAt(i);
			if (escaped && (c == '\\')) {
				sb.append('\\');
				escaped = false;
			}

			else if (c == '\\') {
				escaped = true;
				incommand = true;
				currentCommand = new StringBuffer();
			} else if (!incommand && (c == '{' || c == '}')) {
				// Swallow the brace.
			} else if (Character.isLetter((char) c)
				|| (Globals.SPECIAL_COMMAND_CHARS.indexOf("" + (char) c) >= 0)) {
				escaped = false;
				if (!incommand){
					sb.append((char) c);
				} else {
					// Else we are in a command, and should not keep the letter.
					currentCommand.append((char) c);

					testCharCom: if ((currentCommand.length() == 1)
						&& (Globals.SPECIAL_COMMAND_CHARS.indexOf(currentCommand.toString()) >= 0)) {
						// This indicates that we are in a command of the type
						// \^o or \~{n}
						if (i >= field.length() - 1)
							break testCharCom;

						String command = currentCommand.toString();
						i++;
						c = field.charAt(i);
						String combody;
						if (c == '{') {
							IntAndString part = getPart(field, i);
							i += part.i;
							combody = part.s;
						} else {
							combody = field.substring(i, i + 1);
						}
						String result = (String)Globals.RTFCHARS.get(command + combody);

						if (result != null)
							sb.append(result);

						incommand = false;
						escaped = false;
				
					}

				}

			} else {
				// if (!incommand || ((c!='{') && !Character.isWhitespace(c)))
				testContent: if (!incommand || (!Character.isWhitespace(c) && (c != '{')))
					sb.append((char) c);
				else {
					// First test if we are already at the end of the string.
					if (i >= field.length() - 1)
						break testContent;

					if (c == '{') {

						String command = currentCommand.toString();
						// Then test if we are dealing with a italics or bold
						// command. If so, handle.
						if (command.equals("emph") || command.equals("textit")) {
							IntAndString part = getPart(field, i);
							i += part.i;
							sb.append("}{\\i ").append(part.s).append("}{");
						} else if (command.equals("textbf")) {
							IntAndString part = getPart(field, i);
							i += part.i;
							sb.append("}{\\b ").append(part.s).append("}{");
						}
					} else
						sb.append((char) c);

				}
				incommand = false;
				escaped = false;
			}
		}

		char[] chars = sb.toString().toCharArray();
		sb = new StringBuffer();

		for (int i = 0; i < chars.length; i++) {
			char c = chars[i];

			if (c < 128) 
				sb.append(c);
			 else
				sb.append("\\u").append((long) c).append('?');
		}

		return sb.toString();
	}

	private IntAndString getPart(String text, int i) {
		char c;
		int count = 0;
		StringBuffer part = new StringBuffer();
		while ((count >= 0) && (i < text.length())) {
			i++;
			c = text.charAt(i);
			if (c == '}')
				count--;
			else if (c == '{')
				count++;

			part.append((char) c);
		}
		return new IntAndString(part.length(), format(part.toString()));
	}

	private class IntAndString {
		public int i;

		String s;

		public IntAndString(int i, String s) {
			this.i = i;
			this.s = s;
		}
	}
}
