/*
 * Copyright (C) 2005-2006 Kouji Sugisawa. Ltd. All rights reserved.
 */

package jp.sourceforge.livez.lang;

/**
 * ボーダフォン用絵文字関連ユーティリティクラスです。<p>
 * 
 * @author 杉澤 浩二
 */
public final class VodafoneEmojiUtils {

	// ボーダフォン絵文字用シフトモード
	private static final int GI	= 1;	// ESC $ G
	private static final int G1I	= 2;	// ESC $ E
	private static final int G2I	= 3;	// ESC $ F
	private static final int G3I	= 4;	// ESC $ O
	private static final int G4I	= 5;	// ESC $ P
	private static final int G5I	= 6;	// ESC $ Q

	private static final char ESC	= '\u001B';	// ESC
	private static final char SI	= '\u000F';

	/**
	 * インスタンス化出来ない事を強制します。
	 */
	private VodafoneEmojiUtils() {}

	/**
	 * 指定された文字がボーダフォン絵文字かどうかを返します。<p>
	 * 
	 * @param c 文字
	 * @return ボーダフォン絵文字の場合 true を、それ以外の場合 false を返します。
	 */
	public static boolean isEmoji(final char c) {
		return ((c >= 0xE001 && c <= 0xE05A)
			|| (c >= 0xE101 && c <= 0xE15A)
			|| (c >= 0xE201 && c <= 0xE25A)
			|| (c >= 0xE301 && c <= 0xE34D)
			|| (c >= 0xE401 && c <= 0xE44C)
			|| (c >= 0xE501 && c <= 0xE539));
	}

	/**
	 * 指定された文字列からボーダフォン絵文字を削除して返します。<p>
	 * 指定された文字列が <code>null</code> の場合は、<code>null</code> を返します。
	 * 
	 * @param s 文字列
	 * @return ボーダフォン絵文字が削除された文字列。又は null
	 */
	public static String removeEmoji(final String s) {
		if (s == null)
			return null;

		StringBuilder result = new StringBuilder(s.length());

		for (int i = 0; i < s.length(); i++) {
			final char c = s.charAt(i);
			if (!isEmoji(c))
				result.append(c);
		}

		return result.toString();
	}

	/**
	 * 指定された文字列中のボーダフォン絵文字１〜３を、
	 * ボーダフォンライブウェブで表示可能な形式にエスケープします。<p>
	 * 
	 * @param s 文字列
	 * @return エスケープされた文字列
	 */
	public static String escapeWebCode123(final String s) {
		if (s == null)
			return null;

		StringBuilder result = new StringBuilder(s.length());
		int mode = 0;

		for (int i = 0; i < s.length(); i++) {
			final char c = s.charAt(i);
			// ボーダフォン絵文字１
			if (c >= 0xE001 && c <= 0xE05A) {
				if (mode != GI) {
					if (mode != 0)
						result.append(SI);
					mode = GI;
					result.append(renderShiftIn(mode));
				}
				result.append((char)(c - 0xDFE0));

			// ボーダフォン絵文字２
			} else if (c >= 0xE101 && c <= 0xE15A) {
				if (mode != G1I) {
					if (mode != 0)
						result.append(SI);
					mode = G1I;
					result.append(renderShiftIn(mode));
				}
				result.append((char)(c - 0xE0E0));
			// ボーダフォン絵文字３
			} else if (c >= 0xE201 && c <= 0xE25A) {
				if (mode != G2I) {
					if (mode != 0)
						result.append(SI);
					mode = G2I;
					result.append(renderShiftIn(mode));
				}
				result.append((char)(c - 0xE1E0));
			} else {
				if (mode != 0)
					result.append(SI);
				mode = 0;
				result.append(c);
			}
		}

		if (mode != 0)
			result.append(SI);

		return result.toString();
	}

	/**
	 * 指定された文字列中のボーダフォン絵文字４〜６を、
	 * ボーダフォンライブウェブで表示可能な形式にエスケープします。<p>
	 * 
	 * @param s 文字列
	 * @return エスケープされた文字列
	 */
	public static String escapeWebCode456(final String s) {
		if (s == null)
			return null;

		StringBuilder result = new StringBuilder(s.length());
		int mode = 0;

		for (int i = 0; i < s.length(); i++) {
			final char c = s.charAt(i);
			// ボーダフォン絵文字４
			if (c >= 0xE301 && c <= 0xE34D) {
				if (mode != G3I) {
					if (mode != 0)
						result.append(SI);
					mode = G3I;
					result.append(renderShiftIn(mode));
				}
				result.append((char)(c - 0xE2E0));
			// ボーダフォン絵文字５
			} else if (c >= 0xE401 && c <= 0xE44C) {
				if (mode != G4I) {
					if (mode != 0)
						result.append(SI);
					mode = G4I;
					result.append(renderShiftIn(mode));
				}
				result.append((char)(c - 0xE3E0));
			// ボーダフォン絵文字６
			} else if (c >= 0xE501 && c <= 0xE539) {
				if (mode != G5I) {
					if (mode != 0)
						result.append(SI);
					mode = G5I;
					result.append(renderShiftIn(mode));
				}
				result.append((char)(c - 0xE4E0));
			} else {
				if (mode != 0)
					result.append(SI);
				mode = 0;
				result.append(c);
			}
		}

		if (mode != 0)
			result.append(SI);

		return result.toString();
	}

	/**
	 * 指定された文字列中のボーダフォン絵文字を、
	 * ボーダフォンライブウェブで表示可能な形式にエスケープします。<p>
	 * 
	 * @param s 文字列
	 * @return エスケープされた文字列
	 */
	public static String escapeWebCode(final String s) {
		return escapeWebCode456(escapeWebCode123(s));
	}

	/**
	 * 指定された文字列中のボーダフォンライブウェブ絵文字を、
	 * ボーダフォン絵文字形式に非エスケープします。<p>
	 * 
	 * @param s 文字列
	 * @return 非エスケープされた文字列
	 */
	public static String unescapeWebCode(final String s) {
		if (s == null)
			return null;

		StringBuilder result = new StringBuilder(s.length());
		int mode = 0;

		for (int i = 0; i < s.length(); ) {
			final char c = s.charAt(i);
			if (c == ESC && (i + 1) < s.length()) {
				char c2 = s.charAt(i + 1);
				if (c2 == '$' && (i + 2) < s.length()) {
					char c3 = s.charAt(i + 2);
					boolean b =  (i + 3) < s.length();
					// ボーダフォン絵文字１
					if (c3 == 'G' && b) {
						result.append((char)(s.charAt(i + 3) + 0xDFE0));
						i = i + 4;
						mode = GI;
					// ボーダフォン絵文字２
					} else if (c3 == 'E' && b) {
						result.append((char)(s.charAt(i + 3) + 0xE0E0));
						i = i + 4;
						mode = G1I;
					// ボーダフォン絵文字３
					} else if (c3 == 'F' && b) {
						result.append((char)(s.charAt(i + 3) + 0xE1E0));
						i = i + 4;
						mode = G2I;
					// ボーダフォン絵文字４
					} else if (c3 == 'O' && b) {
						result.append((char)(s.charAt(i + 3) + 0xE2E0));
						i = i + 4;
						mode = G3I;
					// ボーダフォン絵文字５
					} else if (c3 == 'P' && b) {
						result.append((char)(s.charAt(i + 3) + 0xE3E0));
						i = i + 4;
						mode = G4I;
					// ボーダフォン絵文字６
					} else if (c3 == 'Q' && b) {
						result.append((char)(s.charAt(i + 3) + 0xE4E0));
						i = i + 4;
						mode = G5I;
					} else {
						result.append(c);
						result.append(c2);
						result.append(c3);
						i = i + 3;
						mode = 0;
					}
				} else {
					result.append(c);
					result.append(c2);
					i = i + 2;
					mode = 0;
				}
			} else if ((mode == GI || mode == G1I || mode == G2I || mode == G3I || mode == G4I || mode == G5I) && c == SI) {
				i = i + 1;
				mode = 0;
			} else {
				result.append(c);
				i = i + 1;
			}
		}

		return result.toString();
	}

	private static String renderShiftIn(final int mode) {
		StringBuilder result = new StringBuilder(3);

		switch (mode) {
			case GI:
				result.append(ESC);
				result.append('$');
				result.append('G');
				break;
			case G1I:
				result.append(ESC);
				result.append('$');
				result.append('E');
				break;
			case G2I:
				result.append(ESC);
				result.append('$');
				result.append('F');
				break;
			case G3I:
				result.append(ESC);
				result.append('$');
				result.append('O');
				break;
			case G4I:
				result.append(ESC);
				result.append('$');
				result.append('P');
				break;
			case G5I:
				result.append(ESC);
				result.append('$');
				result.append('Q');
				break;
		}

		return result.toString();
	}

}
