package tama.util;

import java.io.UnsupportedEncodingException;

/**
 * Character utilities.
 * 
 * @author sato.tatsuma
 *
 */
public class CharacterUtil {
	
	/**
	 * First character of KANJI in The UNICODE.
	 */
	private static final char UNICODE_FIRST_KANJI = '\u3400';
	
	/**
	 * Last character of KANJI in The UNICODE.
	 */
	private static final char UNICODE_LAST_KANJI = '\u9fff';
	
	/**
	 * First character of KANJI in the Shift_JIS The first level.
	 */
	private static final int SHIFT_JIS_FIRST_LEVEL_FIRST_KANJI = 0x889F;
	
	/**
	 * Last character of KANJI in the Shift_JIS The first level.
	 */
	private static final int SHIFT_JIS_FIRST_LEVEL_LAST_KANJI = 0x9872;
	
	/**
	 * First character of KANJI in the Shift_JIS The second level first block.
	 */
	private static final int SHIFT_JIS_SECOND_LEVEL_FIRST_BLOCK_FIRST_KANJI = 0x989F;
	
	/**
	 * Last character of KANJI in the Shift_JIS The second level first block.
	 */
	private static final int SHIFT_JIS_SECOND_LEVEL_FIRST_BLOCK_LAST_KANJI = 0x9FFC;
	
	/**
	 * First character of KANJI in the Shift_JIS The second level second block.
	 */
	private static final int SHIFT_JIS_SECOND_LEVEL_SECOND_BLOCK_FIRST_KANJI = 0xE040;
	
	/**
	 * Last character of KANJI in the Shift_JIS The second level second block.
	 */
	private static final int SHIFT_JIS_SECOND_LEVEL_SECOND_BLOCK_LAST_KANJI = 0xFC4B;
	
	/**
	 * name of Shift_JIS as a String in The Java.
	 */
	private static final String SHIFT_JIS = "Shift_JIS";
	
	/**
	 * Check UNICODE Kanji.
	 * 
	 * @param ch Evaluated for character.
	 * @return return true when ch is Kanji. otherwise return false.
	 */
	static public boolean isKanji(char ch) {
		if (ch < CharacterUtil.UNICODE_FIRST_KANJI
				|| CharacterUtil.UNICODE_LAST_KANJI < ch) {
			return false;
		}
		
		return true;
	}
	
	/**
	 * return JIS code.
	 * 
	 * @param ch Evaluated for character.
	 * @return JIS code.
	 * @throws UnsupportedEncodingException Encoding error or 
	 * @throws Exception not 2 bytes.
	 */
	static public int getJISCode(char ch) throws UnsupportedEncodingException, Exception {
		byte bytes[] = String.valueOf(ch).getBytes(CharacterUtil.SHIFT_JIS);
		
		// UNICODE KANJI is 2 byte character.
		// will never come 1 byte character. Cause check KANJI code at first in this function.
		if (2 != bytes.length) {
			throw new Exception();
		}
		
		int code, top, buttom;
		top = (bytes[0] << 8) & 0xff00;
		buttom = bytes[1] & 0x00ff;
		code = top | buttom;
		
		return code;
	}
	
	/**
	 * Check Shift_JIS Kanji.
	 * Is a Kanji is The first level?
	 * 
	 * @param ch Evaluated for character.
	 * @return return true if The first level. otherwise return false.
	 */
	static public boolean isJISTheFirstLevel(char ch) {
		if (!isKanji(ch)) {
			return false;
		}
		
		int code;
		try {
			code = CharacterUtil.getJISCode(ch);
		} catch (UnsupportedEncodingException e) {
			// encode error.
			return false;
		} catch (Exception e) {
			// byte error.
			return false;
		}

		if (CharacterUtil.SHIFT_JIS_FIRST_LEVEL_FIRST_KANJI <= code
				&& code <= CharacterUtil.SHIFT_JIS_FIRST_LEVEL_LAST_KANJI) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Check Shift_JIS Kanji.
	 * Is a Kanji is The second level?
	 * 
	 * @param ch Evaluated for character.
	 * @return return true when ch is The second level character. otherwise return false.
	 */
	static public boolean isJISTheSecondLevel(char ch) {
		if (!isKanji(ch)) {
			return false;
		}
		
		int code;
		try {
			code = CharacterUtil.getJISCode(ch);
		} catch (UnsupportedEncodingException e) {
			// encode error.
			return false;
		} catch (Exception e) {
			// byte error.
			return false;
		}

		if (CharacterUtil.SHIFT_JIS_SECOND_LEVEL_FIRST_BLOCK_FIRST_KANJI <= code
				&& code <= CharacterUtil.SHIFT_JIS_SECOND_LEVEL_FIRST_BLOCK_LAST_KANJI) {
			return true;
		} else if (CharacterUtil.SHIFT_JIS_SECOND_LEVEL_SECOND_BLOCK_FIRST_KANJI <= code
				&& code <= CharacterUtil.SHIFT_JIS_SECOND_LEVEL_SECOND_BLOCK_LAST_KANJI) {
			return true;
		}
		
		return false;
	}
	
}
