/*
	Tsuikyo 1.0.0 - Typing Game Lib for Javascript
	
	Copyright (c) 2009 Shutaro Takimoto (dvorak.jp)
*/

function Tsuikyo() {
	return this.initialize.apply(this, arguments);
}
function TsuikyoWord() {
	return this.initialize.apply(this, arguments);
}

Tsuikyo.prototype = {
	table: {
		roma: {		// compatible with MS-IME
			maxConvLength: 3,
			
			'あ':['a'],
			'ぁ':['xa','la'],
			'い':['i','yi'],
			'いぇ':['ye'],
			'ぃ':['xi','li','xyi','lyi'],
			'う':['u','wu','whu'],
			'うぁ':['wha'],
			'うぃ':['wi','whi'],
			'うぇ':['we','whe'],
			'うぉ':['who'],
			'ぅ':['xu','lu'],
			'ヴ':['vu'],
			'ヴぁ':['va'],
			'ヴぃ':['vi','vyi'],
			'ヴぇ':['ve','vye'],
			'ヴぉ':['vo'],
			'ヴゃ':['vya'],
			'ヴゅ':['vyu'],
			'ヴょ':['vyo'],
			'え':['e'],
			'ぇ':['xe','le','lye','xye'],
			'お':['o'],
			'ぉ':['xo','lo'],
			'か':['ka','ca'],
			'ヵ':['lka','xka'],
			'が':['ga'],
			'き':['ki'],
			'きゃ':['kya'],
			'きぃ':['kyi'],
			'きゅ':['kyu'],
			'きぇ':['kye'],
			'きょ':['kyo'],
			'ぎ':['gi'],
			'ぎゃ':['gya'],
			'ぎぃ':['gyi'],
			'ぎゅ':['gyu'],
			'ぎぇ':['gye'],
			'ぎょ':['gyo'],
			'く':['ku','cu','qu'],
			'くぁ':['qa','qwa','kwa'],
			'くぃ':['qi','qwi','qyi'],
			'くぅ':['qwu'],
			'くぇ':['qe','qye','qwe'],
			'くぉ':['qo','qwo'],
			'くゃ':['qya'],
			'くゅ':['qyu'],
			'くょ':['qyo'],
			'ぐ':['gu'],
			'ぐぁ':['gwa'],
			'ぐぃ':['gwi'],
			'ぐぅ':['gwu'],
			'ぐぇ':['gwe'],
			'ぐぉ':['gwo'],
			'け':['ke'],
			'ヶ':['lke','xke'],
			'げ':['ge'],
			'こ':['ko','co'],
			'ご':['go'],
			'さ':['sa'],
			'ざ':['za'],
			'し':['si','ci','shi'],
			'しゃ':['sya','sha'],
			'しぃ':['syi'],
			'しゅ':['syu','shu'],
			'しぇ':['sye','she'],
			'しょ':['syo','sho'],
			'じ':['zi','ji'],
			'じゃ':['ja','jya','zya'],
			'じぃ':['jyi','zyi'],
			'じゅ':['ju','jyu','zyu'],
			'じぇ':['je','jye','zye'],
			'じょ':['jo','jyo','zyo'],
			'す':['su'],
			'すぁ':['swa'],
			'すぃ':['swi'],
			'すぅ':['swu'],
			'すぇ':['swe'],
			'すぉ':['swo'],
			'ず':['zu'],
			'せ':['se','ce'],
			'ぜ':['ze'],
			'そ':['so'],
			'ぞ':['zo'],
			'た':['ta'],
			'だ':['da'],
			'ち':['ti','chi'],
			'ちゃ':['tya','cha','cya'],
			'ちぃ':['tyi','cyi'],
			'ちゅ':['tyu','cyu','chu'],
			'ちぇ':['tye','che','cye'],
			'ちょ':['tyo','cyo','cho'],
			'ぢ':['di'],
			'ぢゃ':['dya'],
			'ぢぃ':['dyi'],
			'ぢゅ':['dyu'],
			'ぢぇ':['dye'],
			'ぢょ':['dyo'],
			'つ':['tu','tsu'],
			'つぁ':['tsa'],
			'つぃ':['tsi'],
			'つぇ':['tse'],
			'つぉ':['tso'],
			'づ':['du'],
			'っ':['xtu','ltu','ltsu'],
			'て':['te'],
			'てぃ':['thi'],
			'てぇ':['the'],
			'てゃ':['tha'],
			'てゅ':['thu'],
			'てょ':['tho'],
			'で':['de'],
			'でぃ':['dhi'],
			'でぇ':['dhe'],
			'でゃ':['dha'],
			'でゅ':['dhu'],
			'でょ':['dho'],
			'と':['to'],
			'とぁ':['twa'],
			'とぃ':['twi'],
			'とぅ':['twu'],
			'とぇ':['twe'],
			'とぉ':['two'],
			'ど':['do'],
			'どぁ':['dwa'],
			'どぃ':['dwi'],
			'どぅ':['dwu'],
			'どぇ':['dwe'],
			'どぉ':['dwo'],
			'な':['na'],
			'に':['ni'],
			'にゃ':['nya'],
			'にぃ':['nyi'],
			'にゅ':['nyu'],
			'にぇ':['nye'],
			'にょ':['nyo'],
			'ぬ':['nu'],
			'ね':['ne'],
			'の':['no'],
			'は':['ha'],
			'ば':['ba'],
			'ぱ':['pa'],
			'ひ':['hi'],
			'ひゃ':['hya'],
			'ひぃ':['hyi'],
			'ひゅ':['hyu'],
			'ひぇ':['hye'],
			'ひょ':['hyo'],
			'び':['bi'],
			'びゃ':['bya'],
			'びぃ':['byi'],
			'びゅ':['byu'],
			'びぇ':['bye'],
			'びょ':['byo'],
			'ぴ':['pi'],
			'ぴゃ':['pya'],
			'ぴぃ':['pyi'],
			'ぴゅ':['pyu'],
			'ぴぇ':['pye'],
			'ぴょ':['pyo'],
			'ふ':['hu','fu'],
			'ふぁ':['fa','fwa'],
			'ふぃ':['fi','fwi','fyi'],
			'ふぅ':['fwu'],
			'ふぇ':['fe','fwe'],
			'ふぉ':['fo','fwo'],
			'ふゃ':['fya'],
			'ふゅ':['fyu'],
			'ふょ':['fyo'],
			'ぶ':['bu'],
			'ぷ':['pu'],
			'へ':['he'],
			'べ':['be'],
			'ぺ':['pe'],
			'ほ':['ho'],
			'ぼ':['bo'],
			'ぽ':['po'],
			'ま':['ma'],
			'み':['mi'],
			'みゃ':['mya'],
			'みぃ':['myi'],
			'みゅ':['myu'],
			'みぇ':['mye'],
			'みょ':['myo'],
			'む':['mu'],
			'め':['me'],
			'も':['mo'],
			'や':['ya'],
			'ゃ':['xya','lya'],
			'ゆ':['yu'],
			'ゅ':['xyu','lyu'],
			'よ':['yo'],
			'ょ':['xyo','lyo'],
			'ら':['ra'],
			'り':['ri'],
			'りゃ':['rya'],
			'りぃ':['ryi'],
			'りゅ':['ryu'],
			'りぇ':['rye'],
			'りょ':['ryo'],
			'る':['ru'],
			'れ':['re'],
			'ろ':['ro'],
			'わ':['wa'],
			'ゎ':['xwa','lwa'],
			'を':['wo'],
			'ん':['nn','xn'],
			'ー':['-'],
			'－':['-'],
			'～':['~'],
			'〜':['~'],
			'。':['.'],
			'．':['.'],
			'、':[','],
			'，':[','],
			'！':['!'],
			'？':['?'],
			'「':['['],
			'」':[']'],
			'１':['1'],
			'２':['2'],
			'３':['3'],
			'４':['4'],
			'５':['5'],
			'６':['6'],
			'７':['7'],
			'８':['8'],
			'９':['9'],
			'０':['0'],
			'＠':['@'],
			'＃':['#'],
			'＄':['$'],
			'％':['%'],
			'＾':['^'],
			'＆':['&'],
			'＊':['*'],
			'（':['('],
			'）':[')'],
			'｛':['{'],
			'｝':['}'],
			'・':['/'],
			'＝':['='],
			'＋':['+'],
			'＿':['_'],
			'＼':['\\'],
			'￥':['\\'],
			'｜':['|'],
			'‘':['`'],
			'｀':['`'],
			'”':['"'],
			'’':["'"],
			'＜':['<'],
			'＞':['>'],
			'：':[':'],
			'；':[';'],
			'っい':[{key:'y',cont:'い'}],
			'っヴ':[{key:'v',cont:'ヴ'}],
			'っが':[{key:'g',cont:'が'}],
			'っき':[{key:'k',cont:'き'}],
			'っぎ':[{key:'g',cont:'ぎ'}],
			'っぐ':[{key:'g',cont:'ぐ'}],
			'っけ':[{key:'k',cont:'け'}],
			'っげ':[{key:'g',cont:'げ'}],
			'っご':[{key:'g',cont:'ご'}],
			'っさ':[{key:'s',cont:'さ'}],
			'っざ':[{key:'z',cont:'ざ'}],
			'っす':[{key:'s',cont:'す'}],
			'っず':[{key:'z',cont:'ず'}],
			'っぜ':[{key:'z',cont:'ぜ'}],
			'っそ':[{key:'s',cont:'そ'}],
			'っぞ':[{key:'z',cont:'ぞ'}],
			'った':[{key:'t',cont:'た'}],
			'っだ':[{key:'d',cont:'だ'}],
			'っぢ':[{key:'d',cont:'ぢ'}],
			'っつ':[{key:'t',cont:'つ'}],
			'っづ':[{key:'d',cont:'づ'}],
			'って':[{key:'t',cont:'て'}],
			'っで':[{key:'d',cont:'で'}],
			'っと':[{key:'t',cont:'と'}],
			'っど':[{key:'d',cont:'ど'}],
			'っな':[{key:'n',cont:'な'}],
			'っに':[{key:'n',cont:'に'}],
			'っぬ':[{key:'n',cont:'ぬ'}],
			'っね':[{key:'n',cont:'ね'}],
			'っの':[{key:'n',cont:'の'}],
			'っは':[{key:'h',cont:'は'}],
			'っば':[{key:'b',cont:'ば'}],
			'っぱ':[{key:'p',cont:'ぱ'}],
			'っひ':[{key:'h',cont:'ひ'}],
			'っび':[{key:'b',cont:'び'}],
			'っぴ':[{key:'p',cont:'ぴ'}],
			'っぶ':[{key:'b',cont:'ぶ'}],
			'っぷ':[{key:'p',cont:'ぷ'}],
			'っへ':[{key:'h',cont:'へ'}],
			'っべ':[{key:'b',cont:'べ'}],
			'っぺ':[{key:'p',cont:'ぺ'}],
			'っほ':[{key:'h',cont:'ほ'}],
			'っぼ':[{key:'b',cont:'ぼ'}],
			'っぽ':[{key:'p',cont:'ぽ'}],
			'っま':[{key:'m',cont:'ま'}],
			'っみ':[{key:'m',cont:'み'}],
			'っむ':[{key:'m',cont:'む'}],
			'っめ':[{key:'m',cont:'め'}],
			'っも':[{key:'m',cont:'も'}],
			'っや':[{key:'y',cont:'や'}],
			'っゆ':[{key:'y',cont:'ゆ'}],
			'っよ':[{key:'y',cont:'よ'}],
			'っら':[{key:'r',cont:'ら'}],
			'っり':[{key:'r',cont:'り'}],
			'っる':[{key:'r',cont:'る'}],
			'っれ':[{key:'r',cont:'れ'}],
			'っろ':[{key:'r',cont:'ろ'}],
			'っわ':[{key:'w',cont:'わ'}],
			'っを':[{key:'w',cont:'を'}],
			'っぁ':['xxa','lla'],
			'っぃ':['xxi','lli','xxyi','llyi'],
			'っう':['wwhu','wwu'],
			'っうぃ':['wwi','wwhi'],
			'っうぇ':['wwe','wwhe'],
			'っうぉ':['wwho'],
			'っうぁ':['wwha'],
			'っぅ':['xxu','llu'],
			'っぇ':['xxe','lle','xxye','llye'],
			'っぉ':['xxo','llo'],
			'っか':['kka','cca'],
			'っヵ':['llka','xxka'],
			'っく':['kku','ccu','qqu'],
			'っくぁ':['qqa','qqwa','kkwa'],
			'っくぃ':['qqi','qqwi','qqyi'],
			'っくぅ':['qqwu'],
			'っくぇ':['qqe','qqye','qqwe'],
			'っくぉ':['qqo','qqwo'],
			'っくゃ':['qqya'],
			'っくゅ':['qqyu'],
			'っくょ':['qqyo'],
			'っヶ':['llke','xxke'],
			'っこ':['kko','cco'],
			'っし':['ssi','cci','sshi'],
			'っしゃ':['ssya','ssha'],
			'っしぃ':['ssyi'],
			'っしゅ':['ssyu','sshu'],
			'っしぇ':['ssye','sshe'],
			'っしょ':['ssyo','ssho'],
			'っじ':['zzi','jji'],
			'っじゃ':['jja','jjya','zzya'],
			'っじぃ':['jjyi','zzyi'],
			'っじゅ':['jju','jjyu','zzyu'],
			'っじぇ':['jje','jjye','zzye'],
			'っじょ':['jjo','jjyo','zzyo'],
			'っせ':['sse','cce'],
			'っち':['tti','cchi'],
			'っちゃ':['ttya','ccha','ccya'],
			'っちぃ':['ttyi','ccyi'],
			'っちゅ':['ttyu','ccyu','cchu'],
			'っちぇ':['ttye','cche','ccye'],
			'っちょ':['ttyo','ccyo','ccho'],
			'っふ':['hhu','ffu'],
			'っふぁ':['ffa','ffwa'],
			'っふぃ':['ffi','ffwi','ffyi'],
			'っふぅ':['ffwu'],
			'っふぇ':['ffe','ffwe'],
			'っふぉ':['ffo','ffwo'],
			'っふゃ':['ffya'],
			'っふゅ':['ffyu'],
			'っふょ':['ffyo'],
			'っゃ':['xxya','llya'],
			'っゅ':['xxyu','llyu'],
			'っょ':['xxyo','llyo'],
			'っゎ':['xxwa','llwa'],
			'んぁ':[{key:'n',cont:'ぁ'}],
			'んぃ':[{key:'n',cont:'ぃ'}],
			'んぅ':[{key:'n',cont:'ぅ'}],
			'んヴ':[{key:'n',cont:'ヴ'}],
			'んぇ':[{key:'n',cont:'ぇ'}],
			'んぉ':[{key:'n',cont:'ぉ'}],
			'んか':[{key:'n',cont:'か'}],
			'んヵ':[{key:'n',cont:'ヵ'}],
			'んが':[{key:'n',cont:'が'}],
			'んき':[{key:'n',cont:'き'}],
			'んぎ':[{key:'n',cont:'ぎ'}],
			'んく':[{key:'n',cont:'く'}],
			'んぐ':[{key:'n',cont:'ぐ'}],
			'んけ':[{key:'n',cont:'け'}],
			'んヶ':[{key:'n',cont:'ヶ'}],
			'んげ':[{key:'n',cont:'げ'}],
			'んこ':[{key:'n',cont:'こ'}],
			'んご':[{key:'n',cont:'ご'}],
			'んさ':[{key:'n',cont:'さ'}],
			'んざ':[{key:'n',cont:'ざ'}],
			'んし':[{key:'n',cont:'し'}],
			'んじ':[{key:'n',cont:'じ'}],
			'んす':[{key:'n',cont:'す'}],
			'んず':[{key:'n',cont:'ず'}],
			'んせ':[{key:'n',cont:'せ'}],
			'んぜ':[{key:'n',cont:'ぜ'}],
			'んそ':[{key:'n',cont:'そ'}],
			'んぞ':[{key:'n',cont:'ぞ'}],
			'んた':[{key:'n',cont:'た'}],
			'んだ':[{key:'n',cont:'だ'}],
			'んち':[{key:'n',cont:'ち'}],
			'んぢ':[{key:'n',cont:'ぢ'}],
			'んつ':[{key:'n',cont:'つ'}],
			'んづ':[{key:'n',cont:'づ'}],
			'んっ':[{key:'n',cont:'っ'}],
			'んて':[{key:'n',cont:'て'}],
			'んで':[{key:'n',cont:'で'}],
			'んと':[{key:'n',cont:'と'}],
			'んど':[{key:'n',cont:'ど'}],
			'んは':[{key:'n',cont:'は'}],
			'んば':[{key:'n',cont:'ば'}],
			'んぱ':[{key:'n',cont:'ぱ'}],
			'んひ':[{key:'n',cont:'ひ'}],
			'んび':[{key:'n',cont:'び'}],
			'んぴ':[{key:'n',cont:'ぴ'}],
			'んふ':[{key:'n',cont:'ふ'}],
			'んぶ':[{key:'n',cont:'ぶ'}],
			'んぷ':[{key:'n',cont:'ぷ'}],
			'んへ':[{key:'n',cont:'へ'}],
			'んべ':[{key:'n',cont:'べ'}],
			'んぺ':[{key:'n',cont:'ぺ'}],
			'んほ':[{key:'n',cont:'ほ'}],
			'んぼ':[{key:'n',cont:'ぼ'}],
			'んぽ':[{key:'n',cont:'ぽ'}],
			'んま':[{key:'n',cont:'ま'}],
			'んみ':[{key:'n',cont:'み'}],
			'んむ':[{key:'n',cont:'む'}],
			'んめ':[{key:'n',cont:'め'}],
			'んも':[{key:'n',cont:'も'}],
			'んゃ':[{key:'n',cont:'ゃ'}],
			'んゅ':[{key:'n',cont:'ゅ'}],
			'んょ':[{key:'n',cont:'ょ'}],
			'んら':[{key:'n',cont:'ら'}],
			'んり':[{key:'n',cont:'り'}],
			'んる':[{key:'n',cont:'る'}],
			'んれ':[{key:'n',cont:'れ'}],
			'んろ':[{key:'n',cont:'ろ'}],
			'んわ':[{key:'n',cont:'わ'}],
			'んゎ':[{key:'n',cont:'ゎ'}],
			'んを':[{key:'n',cont:'を'}],
			'んー':[{key:'n',cont:'ー'}],
			'ん－':[{key:'n',cont:'ー'}],
			'ん～':[{key:'n',cont:'～'}],
			'ん。':[{key:'n',cont:'。'}],
			'ん、':[{key:'n',cont:'、'}],
			'ん．':[{key:'n',cont:'。'}],
			'ん，':[{key:'n',cont:'、'}],
			'ん！':[{key:'n',cont:'！'}],
			'ん？':[{key:'n',cont:'？'}],
			'ん「':[{key:'n',cont:'「'}],
			'ん」':[{key:'n',cont:'」'}],
			'ん１':[{key:'n',cont:'１'}],
			'ん２':[{key:'n',cont:'２'}],
			'ん３':[{key:'n',cont:'３'}],
			'ん４':[{key:'n',cont:'４'}],
			'ん５':[{key:'n',cont:'５'}],
			'ん６':[{key:'n',cont:'６'}],
			'ん７':[{key:'n',cont:'７'}],
			'ん８':[{key:'n',cont:'８'}],
			'ん９':[{key:'n',cont:'９'}],
			'ん０':[{key:'n',cont:'０'}],
			'ん＠':[{key:'n',cont:'＠'}],
			'ん＃':[{key:'n',cont:'＃'}],
			'ん＄':[{key:'n',cont:'＄'}],
			'ん％':[{key:'n',cont:'％'}],
			'ん＾':[{key:'n',cont:'＾'}],
			'ん＆':[{key:'n',cont:'＆'}],
			'ん＊':[{key:'n',cont:'＊'}],
			'ん（':[{key:'n',cont:'（'}],
			'ん）':[{key:'n',cont:'）'}],
			'ん｛':[{key:'n',cont:'｛'}],
			'ん｝':[{key:'n',cont:'｝'}],
			'ん・':[{key:'n',cont:'・'}],
			'ん＝':[{key:'n',cont:'＝'}],
			'ん＋':[{key:'n',cont:'＋'}],
			'ん＿':[{key:'n',cont:'＿'}],
			'ん＼':[{key:'n',cont:'＼'}],
			'ん￥':[{key:'n',cont:'￥'}],
			'ん｜':[{key:'n',cont:'｜'}],
			'ん〜':[{key:'n',cont:'～'}],
			'ん～':[{key:'n',cont:'～'}],
			'ん‘':[{key:'n',cont:'｀'}],
			'ん”':[{key:'n',cont:'”'}],
			'ん’':[{key:'n',cont:'’'}],
			'ん＜':[{key:'n',cont:'＜'}],
			'ん＞':[{key:'n',cont:'＞'}],
			'ん：':[{key:'n',cont:'：'}],
			'ん；':[{key:'n',cont:'；'}],
			'んう':['nwhu','nwu'],
			'んうぃ':['nwi','nwhi'],
			'んうぇ':['nwe','nwhe'],
			'んうぉ':['nwho'],
			'んうぁ':['nwha'],
			'んん':['nxn']
		}
	},
	
	words: [],
	gtable: null,
	gid: -1,
	gflex: -1,
	
	initialize: function(conv, flex) {
		this.words = new Array();
		this.gid = -1;
		
		if(conv == undefined) conv = "roma";	// default input mode: 'roma'
		if(!this.setDefaultConversion(conv)){
			this.gtable = this.table.roma;
		}
		if(flex == undefined) flex = 2;		// default input flexibility: 'cancelable'
		if(!this.setDefaultFlex(flex)){
			this.gflex = 2;
		}
	},
	
	outConv : function(){
		var ret = "";
		for(var k in this.table){
			ret = ret + "'" + k + "':[";
			var t = this.table[k];
			for(var i = 0; i < t.length; i++){
				var ti = t[i];
				if(ti.cont){
					ret = ret + "{key:'" + ti.key + "',cont:'" + ti.cont + "'}";
				}else{
					ret = ret + "'" + ti.key + "'";
				}
				if(i != t.length - 1){
					ret = ret + ",";
				}
			}
			ret = ret + "],\n";
		}
		
		return ret;
	},
	
	parse: function(hstr, conv, flag){
		conv = conv || this.gtable;
		flag = flag || false;
		var hstrLength = hstr.length;
		var ret = new Array(hstrLength);
		
		for(var i = 0; i < hstrLength; i++){
			ret[i] = new Array();
			var rr = ret[i];
			
			for(var j = 1; j <= conv.maxConvLength && i + j <= hstrLength; j++){
				var pstr = hstr.substr(i, j);
				var t = conv[pstr];
				if(t){
					var tLength = t.length;
					for(var l = 0; l < tLength; l++){
						var tl = t[l];
						var tlcont, tlkey;
						if(typeof(tl) == "string"){
							tlkey = tl;
							tlcont = null;
						}else{
							tlcont = tl.cont;
							tlkey = tl.key;
						}
						if(tlcont){
							var tmpw = this.parse(tlcont + hstr.substr(i + j), conv, true);
							
							var tmpwLength = tmpw[0].length;
							for(var n = 0; n < tmpwLength; n++){
								var a = new Object();
								var b = tmpw[0][n];
								
								a.key = tlkey + b.key;
								a.prog = b.prog;
								a.prog.unshift(j - tlcont.length);
								a.progpos = b.progpos;
								a.progpos.unshift(tlkey.length + 1);
								
								var aProgLength = a.prog.length;
								for(var m = 1; m < aProgLength; m++){
									a.prog[m] += a.prog[0];
									a.progpos[m] += a.progpos[0] - 1;
								}
								
								rr.push(a);
							}
						}else{
							var a = new Object();
							a.key = tlkey;
							a.prog = [j];
							a.progpos = [tlkey.length];
							
							rr.push(a);
						}
					}
				}
			}
			
			// not match (maybe ascii char)
			if(rr.length == 0){
				rr.push({key: hstr.charAt(i), prog: [1], progpos: [1]});
			}
			if(flag){
				break;
			}
		}
		
		return ret;
	},
	
	add: function (hstr, sstr, conv, flex){
		if(conv != undefined){
			conv = this.table[conv];
		}
		if(flex == undefined){
			flex = this.gflex;
		}
		var id = this.words.length;
		var w = new TsuikyoWord(hstr, sstr, this.parse(hstr, conv), flex, id);
		
		this.words.push(w);
		return this.words[this.words.length - 1];
	},
	
	clear: function() {
		this.words.length = 0;
		this.gid = -1;
	},
	
	setTarget: function(id) {
		if(id == undefined){
			this.gid = this.words.length - 1;
			return this.words[this.gid];
		}else if(id <= this.words.length){
			this.gid = id;
			return this.words[id];
		}else{
			return false;
		}
	},
	
	setDefaultConversion: function(conv){
		if(this.table[conv]){
			this.gtable = this.table[conv];
			return true;
		}else{
			return false;
		}
	},
	
	setDefaultFlex: function(level){
		switch(level){
			case 0:
			case "fixed":
				this.gflex = 0;
				break;
			case 1:
			case "flex":
				this.gflex = 1;
				break;
			case 2:
			case "cancelable":
				this.gflex = 2;
				break;
			default:
				return false;
		}
		
		return true;
	},
	
	init: function(id) {
		id = this.idConv(id);
		return this.words[id].init();
	},
	stroke: function(key, id){
		id = this.idConv(id);
		return this.words[id].stroke(key);
	},
	strokeTest: function(key, id){
		id = this.idConv(id);
		return this.words[id].strokeTest(key);
	},
	prog: function(id){
		id = this.idConv(id);
		return this.words[id].prog();
	},
	getShowString: function(id){
		id = this.idConv(id);
		return this.words[id].getShowString();
	},
	getHiraganaString: function(id){
		id = this.idConv(id);
		return this.words[id].getHiraganaString();
	},
	getKeyString: function(id){
		id = this.idConv(id);
		return this.words[id].getKeyString();
	},
	getInputKeyString: function(id){
		id = this.idConv(id);
		return this.words[id].getInputKeyString();
	},
	getShowPos: function(id){
		id = this.idConv(id);
		return this.words[id].getShowPos();
	},
	getHiraganaPos: function(id){
		id = this.idConv(id);
		return this.words[id].getHiraganaPos();
	},
	getKeyPos: function(id){
		id = this.idConv(id);
		return this.words[id].getKeyPos();
	},
	getMissCount: function(id) {
		id = this.idConv(id);
		return this.words[id].getMissCount();
	},
	getNextKeys: function(id) {
		id = this.idConv(id);
		return this.words[id].getNextKeys();
	},
	setFlex: function(level, id){
		id = this.idConv(id);
		return this.words[id].setFlex(level);
	},
	
	idConv: function(id) {
		if(id == undefined){
			return this.gid;
		}else{
			return id;
		}
	},
	
	nodeToString: function(id) {
		id = this.idConv(id);
		var ns = this.words[id].nodes;
		
		var str = "";
		var nsLength = ns.length;
		for(var i = 0; i < nsLength; i++){
			var n = ns[i];
			str += "[" + n.key.substr(0, n.kpos) + "_" + n.key.substr(n.kpos) + " @ " + n.hpos + "] ";
		}
		
		return str;
	},
	
	datToString: function(id) {
		id = this.idConv(id);
		var w = this.words[id].dat;
		
		var str = "[\n";
		var wLength = w.length;
		for(var i = 0; i < wLength; i++){
			str += "\t[";
			var ww = w[i];
			var wwLength = ww.length;
			for(var j = 0; j < wwLength; j++){
				var www = ww[j];
				str += www.key;
				str += "(";
				
				var wwwProgLength = www.prog.length;
				for(var l = 0; l < wwwProgLength; l++){
					str += www.prog[l] + "@" + www.progpos[l];
					if(l != wwwProgLength - 1){
						str += ", ";
					}
				}
				str += ")";
				if(j != wwLength - 1){
					str += ", ";
				}
			}
			str += "]\n";
		}
		str += "]";
		
		return str;
	}
};


TsuikyoWord.prototype = {
	initialize: function(hstr, sstr, dat, flex, id) {
		this.dat = dat;
		this.shutFlags = this.calcShutPos(dat);
		this.sstr = sstr;
		this.hstr = hstr;
		this.hlen = hstr.length;
		this.flex = flex;
		this.id = id;
		this.init();
	},
	
	init: function() {
		this.spos = 0;
		this.inputKeys = "";
		this.allCount = 0;
		this.tmpCount = 0;
		this.missCount = 0;
		this.correctCount = 0;
		this.nodes = new Array();
		var len = this.dat[0].length;
		
		for(var i = 0; i < len; i++){
			var a = new Object();
			a.key = this.dat[0][i].key;
			a.keyhead = a.key.charAt(0);
			a.prog = parseInt(this.dat[0][i].prog[this.dat[0][i].prog.length - 1]);
			a.kpos = 0;
			a.hpos = 0;
			this.nodes.push(a);
		}
		
		this.activeNode = this.selectNode(this.nodes);
		if(this.flex == 0){		// when the input flexibility is 'fixed'
			// only activeNode remain
			this.nodes = [this.activeNode];
		}
		
		return true;
	},
	
	setFlex: function(level){
		switch(level){
			case 0:
			case "fixed":
				this.flex = 0;
				break;
			case 1:
			case "flex":
				this.flex = 1;
				break;
			case 2:
			case "cancelable":
				this.flex = 2;
				break;
			default:
				return false;
		}
		
		return true;
	},
	
	getShowString: function() {
		return this.sstr;
	},
	getHiraganaString: function() {
		return this.hstr;
	},
	getKeyString: function() {
		return this.selectNodeToTail(this.activeNode).key;
	},
	getShowPos: function() {
		return 0;
	},
	getHiraganaPos: function() {
		return this.activeNode.hpos;
	},
	getKeyPos: function() {
		return this.activeNode.kpos;
	},
	getInputKeyString: function() {
		return this.inputKeys;
	},
	getMissCount: function() {
		return this.missCount;
	},
	getNextKeys: function() {
		var ret = new Array();
		var ns = this.nodes;
		var len = ns.length;
		
		for(var i = 0; i < len; i++){
			var n = ns[i];
			ret.push(n.keyhead);
		}
		
		return ret;
	},
	
	stroke: function(k) {
		if(!k) return -1;
		if(typeof(k) == "number"){
			k = String.fromCharCode(k);
		}
		
		var ret = 0;
		if(k.length > 1){
			var ret = new Array();
			var len = k.length;
			for(var i = 0; i < len; i++){
					ret.push(this.stroke(k.charAt(i)));
			}
			
			return ret;
		}
		
		this.inputKeys += k;
		
		var ns = this.nodes;
		var nsLength = ns.length;
		var goodNodes = new Array();
		var concatNodes = new Array();
		var shutNodes = new Array();
		
		for(var i = 0; i < nsLength; i++){
			var n = ns[i];
			
			if(n.keyhead == k){
				if(++(n.kpos) == n.key.length){
					var shutLimit = n.hpos + n.prog;
					if(this.shutFlags[shutLimit]){
						concatNodes.push({dat: n, pos: i});
					}else{
						shutNodes.push({dat: n, pos: i});
					}
				}else{
					n.keyhead = n.key.charAt(n.kpos);
					goodNodes.push(n);
				}
			}
		}
		
		var concatNodesLength = concatNodes.length;
		var shutNodesLength = shutNodes.length;
		var goodNodesLength = goodNodes.length;
		if(shutNodesLength == 0 && concatNodesLength == 0){
			// type
			if(goodNodesLength > 0){
				if(this.flex == 1){		// when the input flexibility is 'flex'
					// delete unaccepted nodes
					this.nodes = goodNodes;
				}
				this.activeNode = this.selectNode(goodNodes);
				this.tmpCount++;
				ret = 1;
			}else{
				// miss
				this.missCount++;
				ret = 0;
			}
		}else if(shutNodesLength == 0 && concatNodesLength != 0){
			// concat
			var posFix = 0;
			var max = 0;
			
			if(this.flex == 1){		// when the input flexibility is 'flex'
				// delete unaccepted nodes
				this.nodes = concatNodes.slice();
				ns = this.nodes;
			}
			
			for(var i = 0; i < concatNodesLength; i++){
				var n = concatNodes[i].dat;
				if(n.key.length > max){
					max = n.key.length;
				}
				
				ns.splice(concatNodes[i].pos + posFix--, 1);
				var ppos = n.hpos + n.prog;
				var suffixNodes = this.dat[ppos];
				
				var suffixNodesLength = suffixNodes.length;
				for(var j = 0; j < suffixNodesLength; j++){
					var m = new Object();
					var suf = suffixNodes[j];
					
					m.key = n.key + suf.key;
					m.keyhead = suf.key.charAt(0);
					m.prog = suf.prog[suf.prog.length - 1];
					m.kpos = n.kpos;
					m.hpos = ppos;
					ns.splice(concatNodes[i].pos + ++posFix, 0, m);
				}
			}
			this.missCount += ++(this.tmpCount) - max;
			this.activeNode = this.selectNode(ns);
			if(this.flex == 0){		// when the input flexibility is 'fixed'
				// only activeNode remain
				this.nodes = [this.activeNode];
			}
			
			ret = 2;
		}else if(shutNodesLength != 0){
			// shut
			var max = 0;
			var n;
			var len = nsLength;
			for(var i = 0; i < shutNodesLength; i++){
				var snd = shutNodes[i].dat;
				var kl = snd.key.length;
				if(max < kl){
					max = kl;
					n = snd;
				}
			}
			
			var ppos = n.hpos + n.prog;
			if(ppos < this.hlen){
				var suffixNodes = this.dat[ppos];
				var suffixNodesLength = suffixNodes.length;
				for(var j = 0; j < suffixNodesLength; j++){
					var m = new Object();
					var suf = suffixNodes[j];
					
					m.key = n.key + suf.key;
					m.keyhead = suf.key.charAt(0);
					m.prog = suf.prog[suf.prog.length - 1];
					m.kpos = n.kpos;
					m.hpos = ppos;
					ns.push(m);
				}
				ns.splice(0, len);
				ret = 3;
			}else{
				// finish
				n.hpos += n.prog;
				n.prog = 0;
				n.keyhead = "";
				ns.length = 0;
				ns.push(n);
				ret = 4;
			}
			
			this.activeNode = this.selectNode(ns);
			if(this.flex == 0){		// when the input flexibility is 'fixed'
				// only activeNode remain
				this.nodes = [this.activeNode];
			}
			this.missCount += (++this.tmpCount) - max;
		}
		
		this.allCount++;
		
		return ret;
	},
	
	strokeTest: function(k) {
		if(!k) return -1;
		if(typeof(k) == "number"){
			k = String.fromCharCode(k);
		}
		
		var ret = 0;
		if(k.length > 1){
			/*
			var ret = new Array();
			var len = k.length;
			for(var i = 0; i < len; i++){
					ret.push(this.test(k.charAt(i)));
			}
			
			return ret; */
			
			// temporary
			k = k.charAt(0);
		}
		
		var ns = this.nodes;
		var nsLength = ns.length;
		var goodNodes = new Array();
		var concatNodes = new Array();
		var shutNodes = new Array();
		
		for(var i = 0; i < nsLength; i++){
			var n = ns[i];
			
			if(n.keyhead == k){
				if(n.kpos + 1 == n.key.length){
					var shutLimit = n.hpos + n.prog;
					if(this.shutFlags[shutLimit]){
						concatNodes.push({dat: n, pos: i});
					}else{
						shutNodes.push({dat: n, pos: i});
					}
				}else{
					goodNodes.push(n);
				}
			}
		}
		
		var concatNodesLength = concatNodes.length;
		var shutNodesLength = shutNodes.length;
		var goodNodesLength = goodNodes.length;
		if(shutNodesLength == 0 && concatNodesLength == 0){
			// type
			if(goodNodesLength > 0){
				ret = 1;
			}else{
				ret = 0;
			}
		}else if(shutNodesLength == 0 && concatNodesLength != 0){
			// concat
			ret = 2;
		}else if(shutNodesLength != 0){
			// shut
			var max = 0;
			var n;
			var len = nsLength;
			for(var i = 0; i < shutNodesLength; i++){
				var snd = shutNodes[i].dat;
				var kl = snd.key.length;
				if(max < kl){
					max = kl;
					n = snd;
				}
			}
			
			var ppos = n.hpos + n.prog;
			if(ppos < this.hlen){
				ret = 3;
			}else{
				// finish
				ret = 4;
			}
		}
		
		return ret;
	},
	
	prog: function() {
		var n = this.activeNode;
		return this.stroke(n.key.charAt(n.kpos));
	},
	
	selectNode: function(ns) {
		if(ns.length == 0) return false;
		if(ns.length == 1) return ns[0];
		var tmpNodes = ns;
		var tmp;
		var tmp2;
		var max = -1;
		
		var nodesLength = tmpNodes.length;
		for(var i = 0; i < nodesLength; i++){
			var nodesHpos = tmpNodes[i].hpos;
			if(max < nodesHpos){
				max = nodesHpos;
				tmp = [tmpNodes[i]];
			}else if(max == nodesHpos){
				tmp.push(tmpNodes[i]);
			}
		}
		
		
		max = 0;
		var tmpLength = tmp.length;
		if(tmpLength == 1) return tmp[0];
		for(var i = 0; i < tmpLength; i++){
			var tmpProg = tmp[i].prog;
			if(max < tmpProg){
				max = tmpProg;
				tmp2 = [tmp[i]];
			}else if(max == tmpProg){
				tmp2.push(tmp[i]);
			}
		}
		
		var ret;
		var min = 255;
		var tmp2Length = tmp2.length;
		if(tmp2Length == 1) return tmp2[0];
		for(var i = 0; i < tmp2Length; i++){
			var tmp2keyLength = tmp2[i].key.length;
			if(min > tmp2keyLength){
				min = tmp2keyLength;
				ret = [tmp2[i]];
			}else if(min == tmp2keyLength){
				ret.push(tmp2[i]);
			}
		}
		
		return ret[0];
	},
	
	selectNodeToTail: function(startNode){
		var n = startNode;
		var t = new Array();
		while(n.hpos + n.prog < this.hlen){
			var nextNodes = this.dat[n.hpos + n.prog];
			var nextNodesLength = nextNodes.length;
			for(var j = 0; j < nextNodesLength; j++){
				var m = new Object();
				m.key = n.key + nextNodes[j].key;
				m.prog = nextNodes[j].prog[nextNodes[j].prog.length - 1];
				m.kpos = n.kpos;
				m.hpos = n.hpos + n.prog;
				t.push(m);
			}
			
			n = this.selectNode(t);
		}
		
		return n;
	},
	
	calcShutPos: function(d){
		var ret = new Array();
		ret.length = d.length;
		
		var dlen = d.length;
		for(var i = 0; i < dlen; i++){
			var t = d[i];
			var tlen = t.length;
			for(var j = 0; j < tlen; j++){
				var prog = t[j].prog;
				var p = prog[prog.length - 1];
				for(var l = i + 1; l < i + p; l++){
					ret[l] = true;
				}
			}
		}
		
		return ret;
	}
}

