/*
 * Copyright (C) 2008,2009  OMRON SOFTWARE Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 * test message
 */

package com.hiroshica.android.input.nicownn2.JAJP;

import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.inputmethodservice.Keyboard;
import android.util.Log;
import android.view.View;
import android.content.SharedPreferences;

import android.preference.PreferenceManager;


import java.util.HashMap;
import java.util.Locale;
import java.util.List;

import com.hiroshica.android.input.nicownn2.*;

/**
 * The default Software Keyboard class for Japanese IME.
 *
 * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
 */
public class DefaultSoftKeyboardNico extends DefaultSoftKeyboard {

	/** Enable English word prediction on half-width alphabet mode */
	private static final boolean USE_ENGLISH_PREDICT = true;

	/** Key code for switching to full-width alphabet mode */
	private static final int KEYCODE_SWITCH_FULL_ALPHABET = -303;

	/** Key code for switching to full-width number mode */
	private static final int KEYCODE_SWITCH_FULL_NUMBER = -304;

	/** Key code for switching to half-width alphabet mode */
	private static final int KEYCODE_SWITCH_HALF_ALPHABET = -307;

	/** Key code for switching to half-width number mode */
	private static final int KEYCODE_SWITCH_HALF_NUMBER = -308;

	/** Key code for case toggle key */
	private static final int KEYCODE_SELECT_CASE = -309;

	/** Key code for EISU-KANA conversion */
	private static final int KEYCODE_EISU_KANA = -305;

	/** Key code for switching to full-width Nicotouch mode */
	private static final int KEYCODE_SWITCH_FULL_NICO = -400;

	/** Key code for NOP (no-operation) */
	private static final int KEYCODE_NOP = -310;


	/** Input mode toggle cycle table */
	private static final int[] JP_MODE_CYCLE_TABLE = {
		KEYMODE_JA_FULL_NICO, KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER,
	};

	/** Definition for {@code mInputType} (toggle) */
	private static final int INPUT_TYPE_TOGGLE = 1;

	/** Definition for {@code mInputType} (commit instantly) */
	private static final int INPUT_TYPE_INSTANT = 2;

	/** Max key number of the 12 key keyboard (depends on the definition of keyboards) */
	private static final int KEY_NUMBER_12KEY = 20;

	/** Toggle cycle table for full-width alphabet */
	private static final String[][] JP_FULL_ALPHABET_CYCLE_TABLE = {
		{"\uff0e", "\uff20", "\uff0d", "\uff3f", "\uff0f", "\uff1a", "\uff5e", "\uff11"},
		{"\uff41", "\uff42", "\uff43", "\uff21", "\uff22", "\uff23", "\uff12"},
		{"\uff44", "\uff45", "\uff46", "\uff24", "\uff25", "\uff26", "\uff13"},
		{"\uff47", "\uff48", "\uff49", "\uff27", "\uff28", "\uff29", "\uff14"},
		{"\uff4a", "\uff4b", "\uff4c", "\uff2a", "\uff2b", "\uff2c", "\uff15"},
		{"\uff4d", "\uff4e", "\uff4f", "\uff2d", "\uff2e", "\uff2f", "\uff16"},
		{"\uff50", "\uff51", "\uff52", "\uff53", "\uff30", "\uff31", "\uff32", "\uff33", "\uff17"},
		{"\uff54", "\uff55", "\uff56", "\uff34", "\uff35", "\uff36", "\uff18"},
		{"\uff57", "\uff58", "\uff59", "\uff5a", "\uff37", "\uff38", "\uff39", "\uff3a", "\uff19"},
		{"\uff0d", "\uff10"},
		{"\uff0c", "\uff0e", "\uff1f", "\uff01", "\u30fb", "\u3000"}
	};

	/** Replace table for full-width alphabet */
	private static final HashMap<String,String> JP_FULL_ALPHABET_REPLACE_TABLE = new HashMap<String,String>() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
	{
			put("\uff21", "\uff41"); put("\uff22", "\uff42"); put("\uff23", "\uff43"); put("\uff24", "\uff44"); put("\uff25", "\uff45"); 
			put("\uff41", "\uff21"); put("\uff42", "\uff22"); put("\uff43", "\uff23"); put("\uff44", "\uff24"); put("\uff45", "\uff25"); 
			put("\uff26", "\uff46"); put("\uff27", "\uff47"); put("\uff28", "\uff48"); put("\uff29", "\uff49"); put("\uff2a", "\uff4a"); 
			put("\uff46", "\uff26"); put("\uff47", "\uff27"); put("\uff48", "\uff28"); put("\uff49", "\uff29"); put("\uff4a", "\uff2a"); 
			put("\uff2b", "\uff4b"); put("\uff2c", "\uff4c"); put("\uff2d", "\uff4d"); put("\uff2e", "\uff4e"); put("\uff2f", "\uff4f"); 
			put("\uff4b", "\uff2b"); put("\uff4c", "\uff2c"); put("\uff4d", "\uff2d"); put("\uff4e", "\uff2e"); put("\uff4f", "\uff2f"); 
			put("\uff30", "\uff50"); put("\uff31", "\uff51"); put("\uff32", "\uff52"); put("\uff33", "\uff53"); put("\uff34", "\uff54"); 
			put("\uff50", "\uff30"); put("\uff51", "\uff31"); put("\uff52", "\uff32"); put("\uff53", "\uff33"); put("\uff54", "\uff34"); 
			put("\uff35", "\uff55"); put("\uff36", "\uff56"); put("\uff37", "\uff57"); put("\uff38", "\uff58"); put("\uff39", "\uff59"); 
			put("\uff55", "\uff35"); put("\uff56", "\uff36"); put("\uff57", "\uff37"); put("\uff58", "\uff38"); put("\uff59", "\uff39"); 
			put("\uff3a", "\uff5a"); 
			put("\uff5a", "\uff3a"); 
		}};

	/** Toggle cycle table for half-width alphabet */
	private static final String[][] JP_HALF_ALPHABET_CYCLE_TABLE = {
		{".", "@", "-", "_", "/", ":", "~", "1"},
		{"a", "b", "c", "A", "B", "C", "2"},
		{"d", "e", "f", "D", "E", "F", "3"},
		{"g", "h", "i", "G", "H", "I", "4"},
		{"j", "k", "l", "J", "K", "L", "5"},
		{"m", "n", "o", "M", "N", "O", "6"},
		{"p", "q", "r", "s", "P", "Q", "R", "S", "7"},
		{"t", "u", "v", "T", "U", "V", "8"},
		{"w", "x", "y", "z", "W", "X", "Y", "Z", "9"},
		{"-", "0"},
		{",", ".", "?", "!", ";", " "}
	};
	private static final String[][][] JP_FLICK_HALF_ALPHABET_CYCLE_TABLE = {
		{ {"."}, {"@"}, {"-"}, {"_"}, {"/"}, {":"}, {"~"}, {"1"}},
		{ {"a"}, {"b"}, {"c"}, {"A"}, {"B"}, {"C"}, {"2"}},
		{ {"d"}, {"e"}, {"f"}, {"D"}, {"E"}, {"F"}, {"3"}},
		{ {"g"}, {"h"}, {"i"}, {"G"}, {"H"}, {"I"}, {"4"}},
		{ {"j"}, {"k"}, {"l"}, {"J"}, {"K"}, {"L"}, {"5"}},
		{ {"m"}, {"n"}, {"o"}, {"M"}, {"N"}, {"O"}, {"6"}},
		{ {"p"}, {"q"}, {"r"}, {"s"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"7"}},
		{ {"t"}, {"u"}, {"v"}, {"T"}, {"U"}, {"V"}, {"8"}},
		{ {"w"}, {"x"}, {"y"}, {"z"}, {"W"}, {"X"}, {"Y"}, {"Z"}, {"9"}},
		{ {"-"}, {"0"}},
		{ {","}, {"."}, {"?"}, {"!"}, {";"}, {" "}}
	};

	/** Replace table for half-width alphabet */
	private static final HashMap<String,String> JP_HALF_ALPHABET_REPLACE_TABLE = new HashMap<String,String>() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
	{
			put("A", "a"); put("B", "b"); put("C", "c"); put("D", "d"); put("E", "e"); 
			put("a", "A"); put("b", "B"); put("c", "C"); put("d", "D"); put("e", "E"); 
			put("F", "f"); put("G", "g"); put("H", "h"); put("I", "i"); put("J", "j"); 
			put("f", "F"); put("g", "G"); put("h", "H"); put("i", "I"); put("j", "J"); 
			put("K", "k"); put("L", "l"); put("M", "m"); put("N", "n"); put("O", "o"); 
			put("k", "K"); put("l", "L"); put("m", "M"); put("n", "N"); put("o", "O"); 
			put("P", "p"); put("Q", "q"); put("R", "r"); put("S", "s"); put("T", "t"); 
			put("p", "P"); put("q", "Q"); put("r", "R"); put("s", "S"); put("t", "T"); 
			put("U", "u"); put("V", "v"); put("W", "w"); put("X", "x"); put("Y", "y"); 
			put("u", "U"); put("v", "V"); put("w", "W"); put("x", "X"); put("y", "Y"); 
			put("Z", "z"); 
			put("z", "Z"); 
		}};
	/**
	 * change map
	 */
	private static final int flickAlphabetChangeMap[][] = {
		{  0,  7,  4,  1,  5 }, // .
		{  0,  6,  1,  2, -1 }, // ABC
		{  0,  6,  1,  2, -1 }, // DEF
		{  0,  6,  1,  2, -1 }, // GHI
		{  0,  6,  1,  2, -1 }, // JKL
		{  0,  6,  1,  2, -1 }, // MNO
		{  0,  8,  1,  2,  3 }, // PQRS
		{  0,  6,  1,  2, -1 }, // TUV
		{  0,  8,  1,  2,  3 }, // WXYZ
		{  0, -1, -1,  1, -1 }, // -
		{  0, -1,  1,  2,  3 }, // #
	};
	/* */
	SetupKeyboard              mSetupKeyboard;
	String[][][]               mCycleTable;
	HashMap<String, String>    mReplaceTable;
	
	/** Character table for full-width number */
	private static final char[] INSTANT_CHAR_CODE_FULL_NUMBER = 
		"\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19\uff10\uff03\uff0a".toCharArray();

	/** Character table for half-width number */
	private static final char[] INSTANT_CHAR_CODE_HALF_NUMBER = 
		"1234567890#*".toCharArray();

	/** The constant for mFixedKeyMode. It means that input mode is not fixed. */
	private static final int INVALID_KEYMODE = -1;

	/** KeyIndex of "Moji" key on 12 keyboard (depends on the definition of keyboards) */
	private static final int KEY_INDEX_CHANGE_MODE_12KEY = 15;
    
	/** KeyIndex of "Moji" key on QWERTY keyboard (depends on the definition of keyboards) */
	private static final int KEY_INDEX_CHANGE_MODE_QWERTY = 29;

	/** Type of input mode */
	private int mInputType = INPUT_TYPE_TOGGLE;


	private static final NicoWnnEvent mEventTouchOtherKey    = new NicoWnnEvent(NicoWnnEvent.TOUCH_OTHER_KEY);
	private static final NicoWnnEvent mEventCommitText       = new NicoWnnEvent(NicoWnnEvent.COMMIT_COMPOSING_TEXT);
	private static final NicoWnnEvent mEventConvert          = new NicoWnnEvent(NicoWnnEvent.CONVERT);

	private static final NicoWnnEvent mEventChangeMode12Key    = new NicoWnnEvent(NicoWnnEvent.CHANGE_MODE, NicoWnnJAJP.ENGINE_MODE_OPT_TYPE_12KEY);
	private static final NicoWnnEvent mEventChangeModeQwerty   = new NicoWnnEvent(NicoWnnEvent.CHANGE_MODE, NicoWnnJAJP.ENGINE_MODE_OPT_TYPE_QWERTY);
	private static final NicoWnnEvent mEventChangeModeSymbol   = new NicoWnnEvent(NicoWnnEvent.CHANGE_MODE, NicoWnnJAJP.ENGINE_MODE_SYMBOL);
	private static final NicoWnnEvent mEventChangeModeDocomo   = new NicoWnnEvent(NicoWnnEvent.CHANGE_MODE, NicoWnnJAJP.ENGINE_MODE_DOCOMOSYMBOL);
	private static final NicoWnnEvent mEventChangeModeEisuKana = new NicoWnnEvent(NicoWnnEvent.CHANGE_MODE, NicoWnnJAJP.ENGINE_MODE_EISU_KANA);

	private static final NicoWnnEvent mEventInputShiftLeft   = new NicoWnnEvent(NicoWnnEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT));

	private static final NicoWnnEvent mEventInputKeyDel      = new NicoWnnEvent(NicoWnnEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
	private static final NicoWnnEvent mEventInputEnter       = new NicoWnnEvent(NicoWnnEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
	private static final NicoWnnEvent mEventInputBack        = new NicoWnnEvent(NicoWnnEvent.INPUT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
	private static final NicoWnnEvent mEventInputDpadLeft    = new NicoWnnEvent(NicoWnnEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
	private static final NicoWnnEvent mEventInputDpadRight   = new NicoWnnEvent(NicoWnnEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));


	/**
	 * Character table to input when mInputType becomes INPUT_TYPE_INSTANT.
	 * (Either INSTANT_CHAR_CODE_FULL_NUMBER or INSTANT_CHAR_CODE_HALF_NUMBER)
	 */
	private char[] mCurrentInstantTable = null;

	/** Input mode that is not able to be changed. If ENABLE_CHANGE_KEYMODE is set, input mode can change. */
	private int[] mLimitedKeyMode = null;

	/** Input mode that is given the first priority. If ENABLE_CHANGE_KEYMODE is set, input mode can change. */
	private int mPreferenceKeyMode = INVALID_KEYMODE;

	/** The last input type */
	private int mLastInputType = 0;

	/** Auto caps mode */
	private boolean mEnableAutoCaps = true;

	/** PopupResId of "Moji" key (this is used for canceling long-press) */
	private int mPopupResId = 0;
    
	/** Whether the InputType is null */
	private boolean mIsInputTypeNull = false;
    
	/** {@code SharedPreferences} for save the keyboard type */
	private SharedPreferences.Editor mPrefEditor = null;
    
	/** "Moji" key (this is used for canceling long-press) */
	private Keyboard.Key mChangeModeKey = null;
    
	private Keyboard[][] mNicoKeyboard;

	private boolean mGetNoFlipScreen = false;
	private boolean mNoFlipScreen = false;

	/** option keyboard type */
	private int     mHookStockKeyType;

	/** change eisu change mode **/
	private boolean mChange12keyQwertyMode = false;
	private final int[] m12keyTable = {
		KEYBOARD_12KEY,  KEYBOARD_12KEY, KEYBOARD_QWERTY, KEYBOARD_QWERTY,  KEYBOARD_12KEY, KEYBOARD_QWERTY, KEYBOARD_QWERTY,  KEYBOARD_12KEY,  KEYBOARD_12KEY
	};
	/** option bell type **/
	private final int ALPHAMODE_SMALL = 0;
	private final int ALPHAMODE_BIG   = 1;
	private int mChangeAlphaBigMode = ALPHAMODE_SMALL;

	private static int selectOtherKeyTable[][] = {
		/* small */
		{
			R.xml.keyboard_12key_phone,
			R.xml.keyboard_12key_full_alphabet, R.xml.keyboard_12key_full_alphabet_input,
			R.xml.keyboard_12key_full_num,
			R.xml.keyboard_12key_half_alphabet, R.xml.keyboard_12key_half_alphabet_input,
			R.xml.keyboard_12key_half_num,
		},
		/* middle */
		{
			R.xml.mid_keyboard_12key_phone,
			R.xml.mid_keyboard_12key_full_alphabet, R.xml.mid_keyboard_12key_full_alphabet_input,
			R.xml.mid_keyboard_12key_full_num,
			R.xml.mid_keyboard_12key_half_alphabet, R.xml.mid_keyboard_12key_half_alphabet_input,
			R.xml.mid_keyboard_12key_half_num,
		},
		/* large */
		{
			R.xml.large_keyboard_12key_phone,
			R.xml.large_keyboard_12key_full_alphabet, R.xml.large_keyboard_12key_full_alphabet_input,
			R.xml.large_keyboard_12key_full_num,
			R.xml.large_keyboard_12key_half_alphabet, R.xml.large_keyboard_12key_half_alphabet_input,
			R.xml.large_keyboard_12key_half_num,
		},
	};
	private static int selectLandOtherKeyTable[][] = {
		/* small */
		{
			R.xml.keyboard_12key_phone_land,
			R.xml.keyboard_12key_full_alphabet_land, R.xml.keyboard_12key_full_alphabet_input_land,
			R.xml.keyboard_12key_full_num_land,
			R.xml.keyboard_12key_half_alphabet_land, R.xml.keyboard_12key_half_alphabet_input_land,
			R.xml.keyboard_12key_half_num_land,
		},
		/* middle */
		{
			R.xml.mid_keyboard_12key_phone_land,
			R.xml.mid_keyboard_12key_full_alphabet_land, R.xml.mid_keyboard_12key_full_alphabet_input_land,
			R.xml.mid_keyboard_12key_full_num_land,
			R.xml.mid_keyboard_12key_half_alphabet_land, R.xml.mid_keyboard_12key_half_alphabet_input_land,
			R.xml.mid_keyboard_12key_half_num_land,
		},
		/* large */
		{
			R.xml.large_keyboard_12key_phone_land,
			R.xml.large_keyboard_12key_full_alphabet_land, R.xml.large_keyboard_12key_full_alphabet_input_land,
			R.xml.large_keyboard_12key_full_num_land,
			R.xml.large_keyboard_12key_half_alphabet_land, R.xml.large_keyboard_12key_half_alphabet_input_land,
			R.xml.large_keyboard_12key_half_num_land,
		},
	};


	/******************************************************************************************/
	/******************************************************************************************/
	/** Default constructor */
	public DefaultSoftKeyboardNico(SetupKeyboard keyboard) {
		mSetupKeyboard       = keyboard;
		mCycleTable   = keyboard.SetupCycleTable();
		mReplaceTable = keyboard.SetupReplaceTable();

		mCurrentLanguage     = LANG_JA;
		mCurrentKeyboardType = KEYBOARD_12KEY;
		mHookStockKeyType    = KEYBOARD_12KEY;
		mShiftOn             = KEYBOARD_SHIFT_OFF;
		mCurrentKeyMode      = KEYMODE_JA_FULL_NICO;
		mCurrentSlide        = NICO_SLIDE_MODE_TOP;
	}

	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#createKeyboards */
	@Override protected void createKeyboards(NicoWnn parent) {

		/* Keyboard[# of Languages][portrait/landscape][# of keyboard type][shift off/on][max # of key-modes][noinput/input] */
		mKeyboard = new Keyboard[3][2][4][2][9][2];

		SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(parent);
		mChange12keyQwertyMode = pref.getBoolean("change_12key_qwerty", false);
		boolean getalphamode  = pref.getBoolean("change_alphamode", false);
		mGetNoFlipScreen       = pref.getBoolean("no_flip_screen", false);
		//mHiddenSoftKeyboard    = pref.getBoolean("hidden_softkeyboard", false);
		
		if (false == getalphamode) {
			mChangeAlphaBigMode = ALPHAMODE_SMALL;
		}
		else{
			mChangeAlphaBigMode = ALPHAMODE_BIG;
		}

		if (true == mGetNoFlipScreen) {
			mNoFlipScreen = true;
		}
		else{
			mNoFlipScreen = false;
		}
		
		/* Create the suitable keyboard object */
		if (mDisplayMode == DefaultSoftKeyboard.PORTRAIT) {
			//mCurrentKeyboardType = KEYBOARD_12KEY;
			createKeyboardsPortrait(parent);
		} else {
			//mCurrentKeyboardType = KEYBOARD_QWERTY;
			createKeyboardsLandscape(parent);
		}
			
		if (mCurrentKeyboardType == KEYBOARD_12KEY) {
			mWnn.onEvent(mEventChangeMode12Key);
		} else {
			mWnn.onEvent(mEventChangeModeQwerty);
		}
	}

	/**
	 *
	 */
	@Override public void checkHiddenKeyboard() {
		super.checkHiddenKeyboard();
	}

	/**
	 * Commit the pre-edit string for committing operation that is not explicit
	 * (ex. when a candidate is selected)
	 */
	private void commitText() {
		if (!mNoInput) {
			mWnn.onEvent(mEventCommitText);
		}
	}

	/**
	 * Change input mode
	 * <br>
	 * @param keyMode   The type of input mode
	 */
	public void changeKeyMode(int keyMode) {
		int targetMode = filterKeyMode(keyMode);
		if (targetMode == INVALID_KEYMODE) {
			return;
		}
        
		commitText();

		if (mCapsLock) {
			mWnn.onEvent(mEventInputShiftLeft);
			mCapsLock = false;
		}
		mShiftOn = KEYBOARD_SHIFT_OFF;
		Keyboard kbd = getModeChangeKeyboard(targetMode);
		mCurrentKeyMode = targetMode;
		mPrevInputKeyCode = 0;
		mCurrentSlide = 0;
        
		int mode = NicoWnnEvent.Mode.DIRECT;
        
		switch (targetMode) {
		case KEYMODE_JA_HALF_ALPHABET:
			if (USE_ENGLISH_PREDICT) {
				mInputType = INPUT_TYPE_TOGGLE;
				mode = NicoWnnEvent.Mode.NO_LV1_CONV;
			} else {
				mInputType = INPUT_TYPE_TOGGLE;
				mode = NicoWnnEvent.Mode.DIRECT;
			}
			break;
            
		case KEYMODE_JA_FULL_NUMBER:
			mInputType = INPUT_TYPE_INSTANT;
			mode = NicoWnnEvent.Mode.DIRECT;
			mCurrentInstantTable = INSTANT_CHAR_CODE_FULL_NUMBER;
			break;
            
		case KEYMODE_JA_HALF_NUMBER:
			mInputType = INPUT_TYPE_INSTANT;
			mode = NicoWnnEvent.Mode.DIRECT;
			mCurrentInstantTable = INSTANT_CHAR_CODE_HALF_NUMBER;
			break;
			
		case KEYMODE_JA_FULL_ALPHABET:
			mInputType = INPUT_TYPE_TOGGLE;
			mode = NicoWnnEvent.Mode.DIRECT;
			break;
			
		case KEYMODE_JA_FULL_NICO:
			mInputType = INPUT_TYPE_TOGGLE;
			mode = NicoWnnEvent.Mode.DEFAULT;
			mNicoFirst = false;
			mNicoFlick = false;
			break;

		default:
			break;
		}
        
		setStatusIcon();
		changeKeyboard(kbd);
		mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.CHANGE_MODE, mode));
		if (mChange12keyQwertyMode == true) {
			changeKeyboardType(m12keyTable[targetMode]);
		}
	}

	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#initView */
	@Override public View initView(NicoWnn parent, int width, int height) {
		View view = super.initView(parent, width, height);
		changeKeyboard(mKeyboard[mCurrentLanguage][mDisplayMode][mCurrentKeyboardType][mShiftOn][mCurrentKeyMode][0]);
		return view;
	}

	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#changeKeyboard */
	@Override protected boolean changeKeyboard(Keyboard keyboard) {

		if (keyboard != null) {
			if (mIsInputTypeNull) {
				mChangeModeKey.popupResId = mPopupResId;
			}

			List<Keyboard.Key> keys = keyboard.getKeys();
			int keyIndex = (KEY_NUMBER_12KEY < keys.size())
				? KEY_INDEX_CHANGE_MODE_QWERTY : KEY_INDEX_CHANGE_MODE_12KEY;
			mChangeModeKey = keys.get(keyIndex);

			if (mIsInputTypeNull) {
				mPopupResId = mChangeModeKey.popupResId;
				mChangeModeKey.popupResId = 0;
			}
		}
		return super.changeKeyboard(keyboard);
	}

	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#changeKeyboardType */
	@Override public void changeKeyboardType(int type) {
		commitText();
		Keyboard kbd = getTypeChangeKeyboard(type);
		if (kbd != null) {
			mCurrentKeyboardType = type;
			mPrefEditor.putBoolean("opt_enable_qwerty", type == KEYBOARD_QWERTY);
			mPrefEditor.commit();
			changeKeyboard(kbd);
		}
		if (type == KEYBOARD_12KEY) {
			mWnn.onEvent(mEventChangeMode12Key);
		} else {
			mWnn.onEvent(mEventChangeModeQwerty);
		}
	}
	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#setPreferences */
	@Override public void setPreferences(SharedPreferences pref, EditorInfo editor) {
		mPrefEditor = pref.edit();
		boolean isQwerty = pref.getBoolean("opt_enable_qwerty", false);
		if (isQwerty && (mCurrentKeyboardType != KEYBOARD_QWERTY)) {
			changeKeyboardType(KEYBOARD_QWERTY);
		}

		super.setPreferences(pref, editor);

		int inputType = editor.inputType;
		if (mHardKeyboardHidden) {
			if (inputType == EditorInfo.TYPE_NULL) {
				if (!mIsInputTypeNull) {
					mIsInputTypeNull = true;
					mPopupResId = mChangeModeKey.popupResId;
					mChangeModeKey.popupResId = 0;
				}
				return;
			}
            
			if (mIsInputTypeNull) {
				mIsInputTypeNull = false;
				mChangeModeKey.popupResId = mPopupResId;
			}
		}

		mEnableAutoCaps = pref.getBoolean("auto_caps", true);
		mLimitedKeyMode = null;
		mPreferenceKeyMode = INVALID_KEYMODE;
		mNoInput = true;
		mDisableKeyInput = false;
		mCapsLock = false;

		switch (inputType & EditorInfo.TYPE_MASK_CLASS) {

		case EditorInfo.TYPE_CLASS_NUMBER:
		case EditorInfo.TYPE_CLASS_DATETIME:
			mPreferenceKeyMode = KEYMODE_JA_HALF_NUMBER;
			break;

		case EditorInfo.TYPE_CLASS_PHONE:
			if (mHardKeyboardHidden) {
				//mLimitedKeyMode = new int[] {KEYMODE_JA_FULL_NICO};
				mPreferenceKeyMode = KEYMODE_JA_FULL_NICO;
			} else {
				//mLimitedKeyMode = new int[] {KEYMODE_JA_HALF_ALPHABET};
				mPreferenceKeyMode = KEYMODE_JA_FULL_NICO;
			}
			break;

		case EditorInfo.TYPE_CLASS_TEXT:
			switch (inputType & EditorInfo.TYPE_MASK_VARIATION) {

			case EditorInfo.TYPE_TEXT_VARIATION_PASSWORD:
				//mLimitedKeyMode = new int[] {KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER};
				break;

			case EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS:
				//mLimitedKeyMode = new int[] {KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER};
				break;
			case EditorInfo.TYPE_TEXT_VARIATION_URI:
				//mPreferenceKeyMode = KEYMODE_JA_HALF_ALPHABET;
				mPreferenceKeyMode = KEYMODE_JA_FULL_NICO;
				break;

			default:
				break;
			}
			break;

		default:
			break;
		}

		boolean restartkey = false;
		boolean old12keyqwerty = mChange12keyQwertyMode;

		mChange12keyQwertyMode = pref.getBoolean("change_12key_qwerty", false);
		boolean getalphamode  = pref.getBoolean("change_alphamode", false);
		mGetNoFlipScreen       = pref.getBoolean("no_flip_screen", false);
		//mHiddenSoftKeyboard    = pref.getBoolean("hidden_softkeyboard", false);
		
		if (false == getalphamode) {
			mChangeAlphaBigMode = ALPHAMODE_SMALL;
		}
		else{
			mChangeAlphaBigMode = ALPHAMODE_BIG;
		}
		
		if (true == mGetNoFlipScreen) {
			mNoFlipScreen = true;
		}
		else{
			mNoFlipScreen = false;
		}

		if (old12keyqwerty != mChange12keyQwertyMode) {
			restartkey = true;
			if (false == mChange12keyQwertyMode) {
				mCurrentKeyboardType = mHookStockKeyType; // change last keyboard type.
			}
		}

		if (inputType != mLastInputType) {
			setDefaultKeyboard();
			mLastInputType = inputType;
		}
		else if (true == restartkey) {
			setDefaultKeyboard();
		}

		setStatusIcon();
		setShiftByEditorInfo();
	}

	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#onUpdateState */
	@Override public void onUpdateState(NicoWnn parent) {
		super.onUpdateState(parent);
		if (!mCapsLock) {
			setShiftByEditorInfo();
			if (true == mNoInput && true == mNicoFirst) {
				resetNicoKeyboard();
			}
		}
	}
	/**
	 * Change the keyboard to default
	 */
	@Override public void setDefaultKeyboard() {
		Locale locale = Locale.getDefault();
		int keymode = KEYMODE_JA_FULL_NICO;


		if (mPreferenceKeyMode != INVALID_KEYMODE) {
			keymode = mPreferenceKeyMode;
		} else if (mLimitedKeyMode != null) {
			keymode = mLimitedKeyMode[0];
		} else {
			if (!locale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
				keymode = KEYMODE_JA_HALF_ALPHABET;
			}
		}

		changeKeyMode(keymode);
	}

    
	/**
	 * Change to the next input mode
	 */
	@Override public void nextKeyMode() {
		/* Search the current mode in the toggle table */
		boolean found = false;
		int index;
		for (index = 0; index < JP_MODE_CYCLE_TABLE.length; index++) {
			if (JP_MODE_CYCLE_TABLE[index] == mCurrentKeyMode) {
				found = true;
				break;
			}
		}

		if (!found) {
			/* If the current mode not exists, set the default mode */
			setDefaultKeyboard();
		} else {
			/* If the current mode exists, set the next input mode */
			int size = JP_MODE_CYCLE_TABLE.length;
			int keyMode = INVALID_KEYMODE;
			for (int i = 0; i < size; i++) {
				index = (++index) % size;

				keyMode = filterKeyMode(JP_MODE_CYCLE_TABLE[index]);
				if (keyMode != INVALID_KEYMODE) {
					break;
				}
			}

			if (keyMode != INVALID_KEYMODE) {
				changeKeyMode(keyMode);
			}
		}
	}

	/**
	 * Create the keyboard for portrait mode
	 * <br>
	 * @param parent  The context
	 */
	private void createKeyboardsPortrait(NicoWnn parent) {
		Keyboard[][] keyList;
		/* qwerty shift_off (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_QWERTY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_alphabet);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_symbols);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_alphabet);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_symbols);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new Keyboard(parent, R.xml.keyboard_12key_phone);
		keyList[KEYMODE_JA_FULL_NICO][0]     = new Keyboard(parent, R.xml.keyboard_qwerty_jp);

		/* qwerty shift_on (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_QWERTY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_alphabet_shift);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_symbols_shift);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_alphabet_shift);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_symbols_shift);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_QWERTY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_PHONE][0];
		keyList[KEYMODE_JA_FULL_NICO][0]     = new Keyboard(parent, R.xml.keyboard_qwerty_jp_shift);

		/* 12-keys shift_off (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][0]);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][1]);
		keyList[KEYMODE_JA_FULL_ALPHABET][1] = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][2]);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][3]);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][4]);
		keyList[KEYMODE_JA_HALF_ALPHABET][1] = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][5]);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new Keyboard(parent, selectOtherKeyTable[mInputViewHeightIndex][6]);

		/* 12-keys shift_on (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_HALF_PHONE]    = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_PHONE];

		keyList[KEYMODE_JA_FULL_ALPHABET] = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_ALPHABET];
		keyList[KEYMODE_JA_FULL_NUMBER]   = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_NUMBER];
		keyList[KEYMODE_JA_HALF_ALPHABET] = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_ALPHABET];;
		keyList[KEYMODE_JA_HALF_NUMBER]   = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_NUMBER];

		mNicoKeyboard = mSetupKeyboard.SetupSoftKeyboard(parent, PORTRAIT, mInputViewHeightIndex);
		
		Keyboard[][] keyListOn;
		keyList   = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyListOn = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_NICO]     = mNicoKeyboard[NICO_SLIDE_MODE_TOP];
		keyListOn[KEYMODE_JA_FULL_NICO]   = mNicoKeyboard[NICO_SLIDE_MODE_A];
	}

	/**
	 * Create the keyboard for landscape mode
	 * <br>
	 * @param parent  The context
	 */
	private void createKeyboardsLandscape(NicoWnn parent) {
		//if ((true == isHardQwertyOnLandscape()) && (true == mHiddenSoftKeyboard)) {
		if (true == isHardQwertyOnLandscape()) {
			return;				// not create soft keyboard
		}

		Keyboard[][] keyList;
		/* qwerty shift_off (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_QWERTY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_alphabet_land);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_symbols_land);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_alphabet_land);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_symbols_land);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new Keyboard(parent, R.xml.keyboard_12key_phone_land);
		keyList[KEYMODE_JA_FULL_NICO][0]     = new Keyboard(parent, R.xml.keyboard_qwerty_jp_land);

		/* qwerty shift_on (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_QWERTY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_alphabet_shift_land);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_full_symbols_shift_land);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_alphabet_shift_land);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new Keyboard(parent, R.xml.keyboard_qwerty_jp_half_symbols_shift_land);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_QWERTY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_PHONE][0];
		keyList[KEYMODE_JA_FULL_NICO][0]     = new Keyboard(parent, R.xml.keyboard_qwerty_jp_shift_land);

		/* 12-keys shift_off (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][0]);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][1]);
		keyList[KEYMODE_JA_FULL_ALPHABET][1] = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][2]);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][3]);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][4]);
		keyList[KEYMODE_JA_HALF_ALPHABET][1] = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][5]);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new Keyboard(parent, selectLandOtherKeyTable[mInputViewHeightIndex][6]);

		/* 12-keys shift_on (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_HALF_PHONE]    = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_PHONE];
		keyList[KEYMODE_JA_FULL_ALPHABET] = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_ALPHABET];
		keyList[KEYMODE_JA_FULL_NUMBER]   = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_NUMBER];
		keyList[KEYMODE_JA_HALF_ALPHABET] = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_ALPHABET];;
		keyList[KEYMODE_JA_HALF_NUMBER]   = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_NUMBER];

		mNicoKeyboard = mSetupKeyboard.SetupSoftKeyboard(parent, LANDSCAPE, mInputViewHeightIndex);
		
		Keyboard[][] keyListOn;
		keyList   = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyListOn = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_NICO]     = mNicoKeyboard[NICO_SLIDE_MODE_TOP];
		keyListOn[KEYMODE_JA_FULL_NICO]   = mNicoKeyboard[NICO_SLIDE_MODE_A];
	}

	/**
	 * Convert the key code to the index of table
	 * <br>
	 * @param index     The key code
	 * @return          The index of the toggle table for input
	 */
	@Override public int getTableIndex(int keyCode) {
		int index =
			(keyCode == KEYCODE_JP12_1)     ?  0 :
			(keyCode == KEYCODE_JP12_2)     ?  1 :
			(keyCode == KEYCODE_JP12_3)     ?  2 :
			(keyCode == KEYCODE_JP12_4)     ?  3 :
			(keyCode == KEYCODE_JP12_5)     ?  4 :
			(keyCode == KEYCODE_JP12_6)     ?  5 :
			(keyCode == KEYCODE_JP12_7)     ?  6 :
			(keyCode == KEYCODE_JP12_8)     ?  7 :
			(keyCode == KEYCODE_JP12_9)     ?  8 :
			(keyCode == KEYCODE_JP12_0)     ?  9 :
			(keyCode == KEYCODE_JP12_SHARP) ? 10 :
			(keyCode == KEYCODE_JP12_ASTER) ? 11 :
			0;

		return index;
	}
	private int checkTableIndex(int keyCode) {
		int index =
			(keyCode == KEYCODE_JP12_1)     ?  0 :
			(keyCode == KEYCODE_JP12_2)     ?  1 :
			(keyCode == KEYCODE_JP12_3)     ?  2 :
			(keyCode == KEYCODE_JP12_4)     ?  3 :
			(keyCode == KEYCODE_JP12_5)     ?  4 :
			(keyCode == KEYCODE_JP12_6)     ?  5 :
			(keyCode == KEYCODE_JP12_7)     ?  6 :
			(keyCode == KEYCODE_JP12_8)     ?  7 :
			(keyCode == KEYCODE_JP12_9)     ?  8 :
			(keyCode == KEYCODE_JP12_0)     ?  9 :
			-1;
		return index;
	}

	/**
	 * Get the toggle table for input that is appropriate in current mode.
	 * 
	 * @return      The toggle table for input
	 */
	private String[][] getCycleTable() {
		String[][] cycleTable = null;
		switch (mCurrentKeyMode) {
		case KEYMODE_JA_FULL_ALPHABET:
			cycleTable = JP_FULL_ALPHABET_CYCLE_TABLE;
			break;

		case KEYMODE_JA_FULL_NUMBER:
		case KEYMODE_JA_HALF_NUMBER:
			/* Because these modes belong to direct input group, No toggle table exists */ 
			break;

		case KEYMODE_JA_HALF_ALPHABET:
			cycleTable = JP_HALF_ALPHABET_CYCLE_TABLE;
			break;

		case KEYMODE_JA_FULL_NICO:
			cycleTable = mCycleTable[mChangeAlphaBigMode];
			break;

		default:
			break;
		}
		return cycleTable;
	}

	/**
	 * Get the replace table that is appropriate in current mode.
	 * 
	 * @return      The replace table
	 */
	private HashMap<String,String> getReplaceTable() {
		HashMap<String,String> hashTable = null;
		switch (mCurrentKeyMode) {
		case KEYMODE_JA_FULL_ALPHABET:
			hashTable = JP_FULL_ALPHABET_REPLACE_TABLE;
			break;

		case KEYMODE_JA_FULL_NUMBER:
		case KEYMODE_JA_HALF_NUMBER:
			/* Because these modes belong to direct input group, No replacing table exists */ 
			break;

		case KEYMODE_JA_HALF_ALPHABET:
			hashTable = JP_HALF_ALPHABET_REPLACE_TABLE;
			break;

		case KEYMODE_JA_FULL_NICO:
			hashTable = mReplaceTable;
			break;

		default:
			break;
		}
		return hashTable;
	}
    
	/**
	 * Set the status icon that is appropriate in current mode
	 */
	private void setStatusIcon() {
		int icon = 0;

		switch (mCurrentKeyMode) {
		case KEYMODE_JA_FULL_ALPHABET:
			icon = R.drawable.immodeic_full_alphabet;
			break;
		case KEYMODE_JA_FULL_NUMBER:
			icon = R.drawable.immodeic_full_number;
			break;
		case KEYMODE_JA_HALF_ALPHABET:
			icon = R.drawable.immodeic_half_alphabet;
			break;
		case KEYMODE_JA_HALF_NUMBER:
		case KEYMODE_JA_HALF_PHONE:
			icon = R.drawable.immodeic_half_number;
			break;
		case KEYMODE_JA_FULL_NICO:
			icon = mSetupKeyboard.SetupIcon();
			break;

		default:
			break;
		}

		mWnn.showStatusIcon(icon);
	}

	/**
	 * Get the shift key state from the editor.
	 * <br>
	 * @param editor    The editor information
	 * @return          The state id of the shift key (0:off, 1:on)
	 */
	protected int getShiftKeyState(EditorInfo editor) {
		InputConnection connection = mWnn.getCurrentInputConnection();
		if (connection != null) {
			int caps = connection.getCursorCapsMode(editor.inputType);
			return (caps == 0) ? 0 : 1;
		} else {
			return 0;
		}
	}

	/**
	 * Set the shift key state from {@link EditorInfo}.
	 */
	private void setShiftByEditorInfo() {
		if (mEnableAutoCaps && (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET)) {
			int shift = getShiftKeyState(mWnn.getCurrentInputEditorInfo());
            
			mShiftOn = shift;
			changeKeyboard(getShiftChangeKeyboard(shift));
		}
	}

	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#setHardKeyboardHidden */
	@Override public void setHardKeyboardHidden(boolean hidden, boolean qwerty) {
		if (mWnn != null) {
			if (!hidden) {
				mWnn.onEvent(mEventChangeModeQwerty);
			}

			if (mHardKeyboardHidden != hidden) {
				if ((mLimitedKeyMode != null)
				    || ((mCurrentKeyMode != KEYMODE_JA_FULL_NICO) && (mCurrentKeyMode != KEYMODE_JA_HALF_ALPHABET))) {
					
					mLastInputType = EditorInfo.TYPE_NULL;
					if (mWnn.isInputViewShown()) {
						setDefaultKeyboard();
					}
				}
			}
		}
		super.setHardKeyboardHidden(hidden, qwerty);
	}

	/**
	 * Change the key-mode to the allowed one which is restricted
	 *  by the text input field or the type of the keyboard.
	 * @param keyMode The key-mode
	 * @return the key-mode allowed
	 */
	private int filterKeyMode(int keyMode) {
		int targetMode = keyMode;
		int[] limits = mLimitedKeyMode;

/*
		if (!mHardKeyboardHidden) { // for hardware keyboard
			if ((targetMode != KEYMODE_JA_FULL_NICO) && (targetMode != KEYMODE_JA_HALF_ALPHABET)) {
				Locale locale = Locale.getDefault();
				int keymode = KEYMODE_JA_HALF_ALPHABET;
				if (locale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
					switch (targetMode) {
					case KEYMODE_JA_FULL_NICO:
						// hiromitsu-s!!! 2009-09-23 12:47:08
						//keymode = KEYMODE_JA_FULL_NICO;
						break;
					default:
						// half-alphabet
						break;
					}
				}
				targetMode = keymode;
			}
		} 
*/

		/* restrict by the type of the text field */
		if (limits != null) {
			boolean hasAccepted = false;
			boolean hasRequiredChange = true;
			int size = limits.length;
			int nowMode = mCurrentKeyMode;

			for (int i = 0; i < size; i++) {
				if (targetMode == limits[i]) {
					hasAccepted = true;
					break;
				}
				if (nowMode == limits[i]) {
					hasRequiredChange = false;
				}
			}

			if (!hasAccepted) {
				if (hasRequiredChange) {
					targetMode = mLimitedKeyMode[0];
				} else {
					targetMode = INVALID_KEYMODE;
				}
			}
		}

		return targetMode;
	}



	/*****************************************
	 * onkey (normal)
	 */
	/** @see com.hiroshica.android.input.nicownn2.DefaultSoftKeyboard#onKey */
	@Override public void onKey(int primaryCode, int[] keyCodes) {
		if (mDisableKeyInput) {
			return;
		}

		if (mCurrentKeyMode == KEYMODE_JA_FULL_NICO) {
			if (true == onKeyNico(primaryCode, keyCodes)) {
				/* update shift key's state */
				if (!mCapsLock && (primaryCode != DefaultSoftKeyboard.KEYCODE_QWERTY_SHIFT)) {
					setShiftByEditorInfo();
				}
				return;
			}
		}

		int getFlickCode = checkFlickKeyCode(true);
		if (getFlickCode >= 0) {
			// get flick keydata
			int col = getTableIndex(mPrevInputKeyCode);
			int row = getFlickCode;
			String[][] cycleTable = JP_FLICK_HALF_ALPHABET_CYCLE_TABLE[col];
			mWnn.onEvent(mEventTouchOtherKey);
			mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.TOGGLE_CHAR, cycleTable[row]));
			mNicoFirst = false;
			mNicoFlick = false;
			return;
		}

		switch (primaryCode) {
		case KEYCODE_JP12_TOGGLE_MODE:
		case KEYCODE_QWERTY_TOGGLE_MODE:
			if (!mIsInputTypeNull) {
				nextKeyMode();
			}
			break;

		case DefaultSoftKeyboard.KEYCODE_QWERTY_BACKSPACE:
		case KEYCODE_JP12_BACKSPACE:
			mWnn.onEvent(mEventInputKeyDel);
			break;

		case DefaultSoftKeyboard.KEYCODE_QWERTY_SHIFT:
			toggleShiftLock();
			break;
            
		case DefaultSoftKeyboard.KEYCODE_QWERTY_ALT:
			processAltKey();
			break;

		case KEYCODE_QWERTY_ENTER:
		case KEYCODE_JP12_ENTER:
			mWnn.onEvent(mEventInputEnter);
			break;

		case KEYCODE_JP12_REVERSE:
			if (!mNoInput) {
				mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.TOGGLE_REVERSE_CHAR, mCurrentCycleTable));
			}
			break;

		case KEYCODE_QWERTY_KBD:
			changeKeyboardType(KEYBOARD_12KEY);
			mHookStockKeyType = KEYBOARD_12KEY;
			break;
            
		case KEYCODE_JP12_KBD:
			changeKeyboardType(KEYBOARD_QWERTY);
			mHookStockKeyType = KEYBOARD_QWERTY;
			break;

		case KEYCODE_JP12_EMOJI:
		case KEYCODE_QWERTY_EMOJI:
			commitText();
			mWnn.onEvent(mEventChangeModeSymbol);
			break;

		case KEYCODE_JP12_1:
		case KEYCODE_JP12_2:
		case KEYCODE_JP12_3:
		case KEYCODE_JP12_4:
		case KEYCODE_JP12_5:
		case KEYCODE_JP12_6:
		case KEYCODE_JP12_7:
		case KEYCODE_JP12_8:
		case KEYCODE_JP12_9:
		case KEYCODE_JP12_0:
		case KEYCODE_JP12_SHARP:
			/* Processing to input by ten key */
			if (mInputType == INPUT_TYPE_INSTANT) {
				/* Send a input character directly if instant input type is selected */
				commitText();
				mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.INPUT_CHAR, mCurrentInstantTable[getTableIndex(primaryCode)]));
			} else {
				if ((mPrevInputKeyCode != primaryCode)) {
					mWnn.onEvent(mEventTouchOtherKey);
					if ((mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET)
					    && (primaryCode == KEYCODE_JP12_SHARP)) {
						/* Commit text by symbol character (',' '.') when alphabet input mode is selected */
						commitText();
					}
				}

				/* Convert the key code to the table index and send the toggle event with the table index */
				String[][] cycleTable = getCycleTable();
				if (cycleTable == null) {
					Log.e("NicoWnn", "not founds cycle table");
				} else {
					int index = getTableIndex(primaryCode);
					mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.TOGGLE_CHAR, cycleTable[index]));
					mCurrentCycleTable = cycleTable[index];
				}
				mPrevInputKeyCode = primaryCode;
			}
			break;

		case KEYCODE_JP12_ASTER:
			if (mInputType == INPUT_TYPE_INSTANT) {
				commitText();
				mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.INPUT_CHAR, mCurrentInstantTable[getTableIndex(primaryCode)]));
			} else {
				if (!mNoInput) {
					/* Processing to toggle Dakuten, Handakuten, and capital */
					HashMap<String,String> replaceTable = getReplaceTable();
					if (replaceTable == null) {
						Log.e("NicoWnn", "not founds replace table");
					} else {
						mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.REPLACE_CHAR, replaceTable));
						mPrevInputKeyCode = primaryCode;
					}
				}
			}
			break;

		case KEYCODE_SWITCH_FULL_ALPHABET:
			/* Change mode to Full width alphabet */
			changeKeyMode(KEYMODE_JA_FULL_ALPHABET);
			break;

		case KEYCODE_SWITCH_FULL_NUMBER:
			/* Change mode to Full width numeric */
			changeKeyMode(KEYMODE_JA_FULL_NUMBER);
			break;

		case KEYCODE_SWITCH_HALF_ALPHABET: 
			/* Change mode to Half width alphabet */
			changeKeyMode(KEYMODE_JA_HALF_ALPHABET);
			break;

		case KEYCODE_SWITCH_HALF_NUMBER:
			/* Change mode to Half width numeric */
			changeKeyMode(KEYMODE_JA_HALF_NUMBER);
			break;

		case KEYCODE_SWITCH_FULL_NICO:
			/* Change mode to Full width nicotouch */
			changeKeyMode(KEYMODE_JA_FULL_NICO);
			break;

		case KEYCODE_SELECT_CASE:
			int shifted = (mShiftOn == 0) ? 1 : 0;
			Keyboard newKeyboard = getShiftChangeKeyboard(shifted);
			if (newKeyboard != null) {
				mShiftOn = shifted;
				changeKeyboard(newKeyboard);
			}
			break;

		case KEYCODE_JP12_SPACE:
			if ((mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) && !mNoInput) {
				mWnn.onEvent(mEventConvert);
			}
			else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO) && !mNoInput) {
				mWnn.onEvent(mEventConvert);
				
			}
			else {
				mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.INPUT_CHAR, ' '));
			}
			break;

		case KEYCODE_EISU_KANA:
			mWnn.onEvent(mEventChangeModeEisuKana);
			break;

		case KEYCODE_JP12_CLOSE:
			mWnn.onEvent(mEventInputBack);
			break;
            
		case KEYCODE_JP12_LEFT:
			mWnn.onEvent(mEventInputDpadLeft);
			break;
            
		case KEYCODE_JP12_RIGHT:
			mWnn.onEvent(mEventInputDpadRight);
			break;
		case KEYCODE_NOP:
			break;

		default:
			if (primaryCode >= 0) {
				if (mKeyboardView.isShifted()) {
					primaryCode = Character.toUpperCase(primaryCode);
				}
				mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.INPUT_CHAR, (char)primaryCode));
			}
			break;
		}

		/* update shift key's state */
		if (!mCapsLock && (primaryCode != DefaultSoftKeyboard.KEYCODE_QWERTY_SHIFT)) {
			setShiftByEditorInfo();
		}
	}


	/*****************************************
	 * onkey nicotouch
	 */
	private boolean onKeyNico(int primaryCode, int[] keyCodes) {
		Keyboard newKeyboard = null;
		boolean retcode = false;
		
		int getFlickCode = checkFlickKeyCode(false);
		if (getFlickCode >= 0) {
			// get flick keydata
			int col = getTableIndex(mPrevInputKeyCode);
			int row = getFlickCode;
			String[][] cycleTable = getCycleTable();
			if (cycleTable == null) {
				Log.e("NicoWnn", "not founds cycle table");
			}
			else{
				mWnn.onEvent(mEventTouchOtherKey);
				mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.TOGGLE_CHAR, cycleTable[col * 10 + row]));
			}
			mNicoFirst = false;
			mNicoFlick = false;
			return true;
		}

		switch (primaryCode) {
		case DefaultSoftKeyboard.KEYCODE_QWERTY_BACKSPACE:
		case KEYCODE_JP12_BACKSPACE:
			if (mNicoFirst == true) {
				resetNicoKeyboard();
			}
			else {
				mWnn.onEvent(mEventInputKeyDel);
			}
			retcode = true;
			break;
		case KEYCODE_QWERTY_ENTER:
		case KEYCODE_JP12_ENTER:
			if (mNicoFirst == false) {
				mWnn.onEvent(mEventInputEnter);
			}
			retcode = true;
			break;

		case KEYCODE_JP12_REVERSE:
			if (mNicoFirst == true) {
				resetNicoKeyboard();
			}
			//mWnn.mashUp();
			retcode = true;
			break;

		case KEYCODE_QWERTY_KBD:
		case KEYCODE_JP12_KBD:
			resetNicoKeyboard();
			break;

		case KEYCODE_JP12_EMOJI:
		case KEYCODE_QWERTY_EMOJI:
			if (mNicoFirst == false) {
				commitText();
				mWnn.onEvent(mEventChangeModeSymbol);
			}
			retcode = true;
			break;

		case KEYCODE_JP12_SHARP:
			if (mNicoFirst == false && mNoInput) {
				commitText();
				mWnn.onEvent(mEventChangeModeDocomo);
			}
			retcode = true;
			break;

		case KEYCODE_JP12_1:
		case KEYCODE_JP12_2:
		case KEYCODE_JP12_3:
		case KEYCODE_JP12_4:
		case KEYCODE_JP12_5:
		case KEYCODE_JP12_6:
		case KEYCODE_JP12_7:
		case KEYCODE_JP12_8:
		case KEYCODE_JP12_9:
		case KEYCODE_JP12_0:
			if (mNicoFirst == false) {
				mWnn.onEvent(mEventTouchOtherKey);
				if (NICOFLICK_NONE == mFlickNicoInput) {
					mPrevInputKeyCode = primaryCode;
				}
				else{
					if (-1 == checkTableIndex(mPrevInputKeyCode)) {
						mPrevInputKeyCode = primaryCode;
					}
				}
				mNicoFirst = true;

				/* change keymap */
				int index = getTableIndex(mPrevInputKeyCode);
				Keyboard[][] keyList = mKeyboard[LANG_JA][mDisplayMode][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];

				keyList[KEYMODE_JA_FULL_NICO] = mNicoKeyboard[index+1];
				if (false == mNoFlipScreen) {
					newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_ON);
					mShiftOn = KEYBOARD_SHIFT_ON;
					changeKeyboard(newKeyboard);
				}
			}
			else{
				if (false == mNoFlipScreen) {
					newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_OFF);
					mShiftOn = KEYBOARD_SHIFT_OFF;
					changeKeyboard(newKeyboard);
				}
				int col = getTableIndex(mPrevInputKeyCode);
				int row = getTableIndex(primaryCode);
				String[][] cycleTable = getCycleTable();
				if (cycleTable == null) {
					Log.e("NicoWnn", "not founds cycle table");
				}
				else{
					mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.TOGGLE_CHAR, cycleTable[col * 10 + row]));
				}
				mNicoFirst = false;
				mNicoFlick = false;
			}
			retcode = true;
			break;

		case KEYCODE_JP12_ASTER:
			if (mNicoFirst == true) {
				resetNicoKeyboard();
			}
			if (mNicoFirst == false && !mNoInput) {
				/* Processing to toggle Dakuten, Handakuten, and capital */
				HashMap<String,String> replaceTable = getReplaceTable();
				if (replaceTable == null) {
					Log.e("NicoWnn", "not founds replace table");
				} else {
					mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.REPLACE_CHAR, replaceTable));
					mPrevInputKeyCode = primaryCode;
				}
			}
			retcode = true;
			break;

		case KEYCODE_JP12_SPACE:
			if (mNicoFirst == false) {
				if ((mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				}
				else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				}
				else {
					mWnn.onEvent(new NicoWnnEvent(NicoWnnEvent.INPUT_CHAR, ' '));
				}
			}
			retcode = true;
			break;

		case KEYCODE_EISU_KANA:
			if (mNicoFirst == false) {
				mWnn.onEvent(mEventChangeModeEisuKana);
			}
			retcode = true;
			break;

		case KEYCODE_JP12_CLOSE:
			mWnn.onEvent(mEventInputBack);
			retcode = true;
			break;
            
		case KEYCODE_JP12_LEFT:
			if (mNicoFirst == false) {
				mWnn.onEvent(mEventInputDpadLeft);
			}
			retcode = true;
			break;
		case KEYCODE_JP12_RIGHT:
			if (mNicoFirst == false) {
				mWnn.onEvent(mEventInputDpadRight);
			}
			retcode = true;
			break;
		}
		return retcode;
	} // onKeyNico
	/*
	 * reset nicotouch keyboard
	 */
	@Override public void resetNicoKeyboard() {
		Keyboard newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_OFF);
		if (newKeyboard != null) {
			mShiftOn = KEYBOARD_SHIFT_OFF;
			changeKeyboard(newKeyboard);
		}
		mNicoFirst = false;
		mNicoFlick = false;
	} // resetNicoKeyboard

	/**
	 */
	@Override public void onPress(int primaryCode) {
		super.onPress(primaryCode);
	}
	/**
	 */
	@Override public void onRelease(int primaryCode) {
		super.onRelease(primaryCode);
	} // onRelease
	/**
	 */
	@Override public int convertModeFlick(int prev, int key) {
		if (mCurrentKeyMode == KEYMODE_JA_FULL_NICO) {
			return mSetupKeyboard.GetFlickKeyCode(prev, key);
		}
		else if (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET) {
			return flickAlphabetChangeMap[prev][key];
		}
		return -1;
	}
}
