/*vietuni.js - V.1.618 - R.11.11.01 @QDJTGSLLA@P*Veni*Vidi*Vici*

* Originally published and documented at http://www.avys.de/

* You may use this code without fee on noncommercial web sites.

* You may NOT alter the code and then call it another name and/or resell it.

* The copyright notice must remain intact on srcipts.

*/

/*Under prior consent of TRAN Anh Tuan, this copy of VietUni has been modified

**by NGUYEN Ba Thanh [btnguyen2k@yahoo.com] for use with DDTHForum::TreXanhBB.

**This modification of VietUni must be distibuted with DDTHForum::TreXanhBB ONLY

**Other uses of *this* modified VietUni outside DDTHForum::TreXanhBB must have

**permissions both from TRAN Anh Tuan (yes, to use VietUni)

**and NGUYEN Ba Thanh (to use the modifications).

**

*/



var supported = (document.all || document.getElementById);

var disabled = false;

var charmapid = 1;

var keymodeid = 0;

var linebreak = 0;

var theTyper = null;



	var ddth_arrHookKeydown = null;

	var ddth_arrHookPageload = null;

	var ddth_arrHookMouseover = null;

	var ddth_arrHookMouseout = null;

	var ddth_arrHookMouseup = null;

	var ddth_arrHookMousedown = null;





reset = function(){}

initTyper = telexingVietUC;

function _displayKeymodeInfo() {

	var keymode = 'Off';

	switch (keymodeid) {

		case 1: keymode = 'Telex'; break;

		case 2: keymode = 'VNI'; break;

		case 3: keymode = 'VIQR'; break;

	}

	window.status = 'Nhan F9 de doi kieu go tieng Viet! Kieu go hien tai: ' + keymode;

}



function _switchKeymode() {

	setTypingMode((keymodeid+1)%4);

}



function setTypingMode(mode) {

  keymodeid = mode;

  if (theTyper) theTyper.keymode= initKeys();

  if (!supported && !disabled) {

    alert("Xin loi, trinh duyet web cua ban khong cho phep dung VietTyping.\n");

    disabled = true;

  }

  	_displayKeymodeInfo();

	var e = new Date(); e.setTime(e.getTime() + 24*3600*1000*365);

	ddth_SetCookie(ddth_vCOOKIE_PREFIX+'_VK', keymodeid, e);

}



initCharMap = function() { return new CVietUniCodeMap(); }



initKeys = function() {

  switch (keymodeid) {

    case 1: return new CTelexKeys();

    case 2: return new CVniKeys();

    case 3: return new CViqrKeys();

    case 4: return new CAllKeys();

    default: return new CVKOff();

  }

}



function telexingVietUC (txtarea) {

  txtarea.vietarea= true;

  txtarea.onkeyup= null;

  if (!supported) return;

  txtarea.onkeypress= vietTyping;

  txtarea.getCurrentWord= getCurrentWord;

  txtarea.replaceWord= replaceWord;

  txtarea.onkeydown= onKeyDown;

  txtarea.onmousedown= onMouseDown;

  if(!theTyper) theTyper = new CVietString("");

}



function getEvt(evt, external) {

  if (external) return external.event.keyCode;

  if (typeof(evt)=='string') return evt.charCodeAt(0);

  return document.all? event.keyCode: (evt && evt.which)? evt.which: 0;

}



function onKeyDown(evt) {

  var c= getEvt(evt, this.win);

  if ((c==10) || (c==13)) { 

	reset(1); 

	linebreak= 1; 

  }

  else if ((c<49) && (c!=16) && (c!=20)) { linebreak= 0; reset(c==32); }

  return true;

}



function onMouseDown(evt) { reset(0); linebreak= 0; return true; }



function vietTyping(evt) {

  var c= getEvt(evt, this.win);

  theTyper.value= this.getCurrentWord();

  if (linebreak && !this.form) {

    linebreak= 0;

	if (this.win && this.win.document.codeMode){ 

		/*if (this.win.event.shiftKey) {

			this.win.document.execCommand('InsertParagraph');

			this.win.document.execCommand('Outdent');

		}

		else*/

		//this.replaceWord(theTyper.value+"\n");

		this.curword.text= theTyper.value+"\n "

		return false;

	}

  }

  var changed= ((c>32) && theTyper.typing(c));

  if (changed) this.replaceWord(theTyper.value);

  return !changed;

}



function getCurrentWord() {

  if(!document.all) return this.value;

  var caret= this.document.selection.createRange();

  if (caret.text) return null;

  var backward= -10;

  do {

    var caret2= caret.duplicate();

    caret2.moveStart("character", backward);

    outside= /[\x01-\x40]([^\x01-\x40]+)$/.exec(caret2.text);

    if (outside) backward = -outside[1].length;

  } while (outside && backward <0);

  this.curword= caret2.duplicate();

  return caret2.text;

}



function replaceWord(newword) {

  if(!document.all) { this.value= newword; return; }

  this.curword.text= newword;

  this.curword.collapse(false);

}

// end interface





// "class": CVietString

//

function CVietString(str) {

  this.value= str;

  this.keymode= initKeys();

  this.charmap= initCharMap();

  this.ctrlchar= '-';

  this.changed= 0;



  this.typing= typing;

  this.Compose= Compose;

  this.Correct= Correct;

  this.findCharToChange= findCharToChange;

  return this;

}



function typing(ctrl) {

  this.changed= 0;

  this.ctrlchar= String.fromCharCode(ctrl);

  this.keymode.getAction(this);

  this.Correct();

  return this.changed;

}



function Compose(type) {

  if(!this.value) return;

  var info= this.findCharToChange(type);

  if (!info || !info[0]) return;

  var telex;

  if (info[0]=='\\') telex= [1,this.ctrlchar,1];

  else if (type>6) telex= this.charmap.getAEOWD(info[0], type, info[3]);

  else telex= this.charmap.getDau(info[0], type);

  if (!(this.changed = telex[0])) return;

  this.value= this.value.replaceAt(info[1],telex[1],info[2]);

  if (!telex[2]) { spellerror= 1; this.value+= this.ctrlchar; }

}



function Correct() {

  if (this.charmap.maxchrlen || !document.all) return 0;

  var tmp= this.value;

  if ('nNcC'.indexOf(this.ctrlchar)>=0) tmp+= this.ctrlchar;

  var er= /[^\x01-\x7f](hn|hc|gn)$/i.exec(tmp);

  if (er) {

    this.value= tmp.substring(0,tmp.length-2)+er[1].charAt(1)+er[1].charAt(0);

    this.changed= 1;

  }

  else if(!this.changed) return 0;

  er= /\w([^\x01-\x7f])(\w*)([^\x01-\x7f])\S*$/.exec(this.value);

  if (!er) return 0;

  var i= this.charmap.isVowel(er[1]);

  var ri= (i-1)%24 + 1, ci= (i-ri)/24;

  var i2= this.charmap.isVowel(er[3]);

  if (!ci || !i2) return 0;

  var ri2= (i2-1)%24 + 1, ci2= (i2-ri2)/24;

  var nc= this.charmap.charAt(ri)+ er[2]+ this.charmap.charAt(ci*24+ri2);

  this.value= this.value.replace(new RegExp(er[1]+er[2]+er[3],'g'), nc);

}



function findCharToChange(type) {

  var lastchars= this.charmap.lastCharsOf(this.value, 5);

  var i= 0, c=lastchars[0][0], chr=0;

  if (c=='\\') return [c,this.value.length-1,1];

  if (type==15) while (!(chr=this.charmap.isVD(c))) {

    if ((c < 'A') || (i>=4) || !(c=lastchars[++i][0])) return null;

  }

  else while( "cghmnptCGHMNPT".indexOf(c)>=0) {

    if ((c < 'A') || (i>=2) || !(c=lastchars[++i][0])) return null;

  }

  c= lastchars[0][0].toLowerCase();

  var pc= lastchars[1][0].toLowerCase();

  var ppc= lastchars[2][0].toLowerCase();

  if (i==0 && type!=15) {

    if ( (chr=this.charmap.isVowel(lastchars[1][0]))

      && ("uyoia".indexOf(c)>=0) && !this.charmap.isUO(pc,c)

      && !((pc=='o' && c=='a') || (pc=='u' && c=='y'))

      && !((ppc=='q' && pc=='u') || (ppc=='g' && pc=='i')) ) ++i;

    if (c=='a' && (type==9 || type==7)) i= 0;

  }

  c= lastchars[i][0];

  if ((i==0 || chr==0) && type!=15) chr= this.charmap.isVowel(c);

  if (!chr) return null;

  var clen= lastchars[i][1], isuo=0;

  if ((i>0) && (type==7 || type==8 || type==11)) {

    isuo=this.charmap.isUO(lastchars[i+1][0],c);

    if (isuo) { chr=isuo; clen+=lastchars[++i][1]; isuo=1; }

  }

  var pos= this.value.length;

  for (var j=0; j<= i; j++) pos -= lastchars[j][1];

  return [chr, pos, clen, isuo];

}

// end CVietString





// character-map template

//

function CVietCharMap(){

  this.vietchars = null;

  this.length = 149;

  this.chr_cache = new Array(20);

  this.ind_cache = new Array(20);

  this.cptr = 0;

  this.caching= function(chr, ind) {

    this.chr_cache[this.cptr] = chr;

    this.ind_cache[this.cptr++] = ind;

    this.cptr %= 20;

  }

  return this;

}



CVietCharMap.prototype.charAt= function(ind){

  var chrcode= this.vietchars[ind];

  return chrcode ? String.fromCharCode(chrcode) : null;

}



CVietCharMap.prototype.isVowel= function(chr){

  var i= 0;

  while ((i<20) && (chr != this.chr_cache[i])) ++i;

  if (i<20) return this.ind_cache[i];



  i = this.length-5;

  while ((chr != this.charAt(i)) && i) --i;

  this.caching(chr, i);

  return i;

}



CVietCharMap.prototype.isVD= function (chr){

  var ind= this.length-5;

  while ((chr != this.charAt(ind)) && (ind < this.length)) ++ind;

  return (ind<this.length)? ind: 0;

}



CVietCharMap.prototype.isUO= function (c1, c2){

  if (!c1 || !c2) return 0;

  var ind1 = this.isVowel(c1);

  var ci = (ind1-1)%12;

  if ((ci!=9) && (ci!=10)) return 0;

  var ind2 = this.isVowel(c2);

  ci = (ind2-1)%12;

  if ((ci!=6) && (ci!=7) && (ci!=8)) return 0;

  return [ind1,ind2];

}



CVietCharMap.prototype.getDau= function (ind, type){

  var accented= (ind < 25)? 0: 1;

  var ind_i= (ind-1) % 24 +1;

  var charset= (type == 6)? 0 : type;

  if ((type== 6) && !accented) return [0];

  var newind= charset*24 + ind_i;

  if (newind == ind) newind= ind_i;

  var chr= this.charAt(newind);

  if (!chr) chr= this.lowerCaseOf(0,newind);

  return [1, chr, newind>24 || type==6];

}



var map=[

[7,7,7,8,8, 8,9,10,11,15],

[0,3,6,0,6, 9,0, 3, 6, 0],

[1,4,7,2,8,10,1, 4, 7, 1]

];

CVietCharMap.prototype.getAEOWD= function(ind, type, isuo) {

  var c=0, i1=isuo? ind[0]: ind;

  var vc1= (type==15)? (i1-1)%2 : (i1-1)%12;

  if (isuo) {

    var base= ind[1]-(ind[1]-1)%12;

    if (type==7 || type==11) c= this.charAt(i1-vc1+9)+this.charAt(base+7);

    else if (type==8) c= this.charAt(i1-vc1+10)+this.charAt(base+8);

    return [c!=0, c, 1];

  }

  var i= -1, shift= 0, del= 0;

  while (shift==0 && ++i<map[0].length) {

    if (map[0][i]==type) {

      if(map[1][i]==vc1) shift= map[2][i]-vc1;

      else if(map[2][i]==vc1) shift= map[1][i]-vc1;

    }

  }

  if (shift==0) {

    if (type==7 && (vc1==2 || vc1==8)) shift=-1;

    else if ((type==9 && vc1==2) || (type==11 && vc1==8)) shift=-1;

    else if (type==8 && (vc1==1 || vc1==7)) shift=1;

    del= 1;

  } else del=(shift>0);

  i1 += shift;

  var chr= this.charAt(i1);

  if (i1<145) this.caching(chr, i1);

  if (!chr) chr= this.lowerCaseOf(0, i1);

  return [shift!=0, chr, del];

}



CVietCharMap.prototype.lastCharsOf= function(str, num){

  if (!num) return [str.charAt(str.length-1),1];

  var vchars = new Array(num);

  for (var i=0; i< num; i++) { vchars[i]= [str.charAt(str.length-i-1),1]; }

  return vchars;

}

// end CVietCharMap prototype





String.prototype.replaceAt= function(i,newchr,clen){

  return this.substring(0,i)+ newchr + this.substring(i+clen);

}



// output map: class CVietUniCodeMap

//

function CVietUniCodeMap(){ var map= new CVietCharMap();

map.vietchars = new Array(

"UNICODE",

97, 226, 259, 101, 234, 105, 111, 244, 417, 117, 432, 121,

65, 194, 258, 69, 202, 73, 79, 212, 416, 85, 431, 89,

225, 7845, 7855, 233, 7871, 237, 243, 7889, 7899, 250, 7913, 253,

193, 7844, 7854, 201, 7870, 205, 211, 7888, 7898, 218, 7912, 221,

224, 7847, 7857, 232, 7873, 236, 242, 7891, 7901, 249, 7915, 7923,

192, 7846, 7856, 200, 7872, 204, 210, 7890, 7900, 217, 7914, 7922,

7841, 7853, 7863, 7865, 7879, 7883, 7885, 7897, 7907, 7909, 7921, 7925,

7840, 7852, 7862, 7864, 7878, 7882, 7884, 7896, 7906, 7908, 7920, 7924,

7843, 7849, 7859, 7867, 7875, 7881, 7887, 7893, 7903, 7911, 7917, 7927,

7842, 7848, 7858, 7866, 7874, 7880, 7886, 7892, 7902, 7910, 7916, 7926,

227, 7851, 7861, 7869, 7877, 297, 245, 7895, 7905, 361, 7919, 7929,

195, 7850, 7860, 7868, 7876, 296, 213, 7894, 7904, 360, 7918, 7928,

100, 273, 68, 272);

return map;

}



// input methods: class C...Keys

function CVietKeys() {

  this.getAction= function(typer){

    var i= this.keys.indexOf(typer.ctrlchar.toLowerCase());

    if(i>=0) typer.Compose(this.actions[i]);

  }

  return this;

}



function CVKOff() {

  this.off = true;

  this.getAction= function(){};

  return this;

}



function CTelexKeys() {

  var k= new CVietKeys();

  k.keys= "sfjrxzaeowd";

  k.actions= [1,2,3,4,5,6,9,10,11,8,15];

  k.istelex= true;

  return k;

}



function CVniKeys() {

  var k= new CVietKeys();

  k.keys= "0123456789";

  k.actions= [6,1,2,4,5,3,7,8,8,15];

  return k;

}



function CViqrKeys() {

  var k= new CVietKeys();

  k.keys= "\xB4/'\u2019`.?~-^(*+d";

  k.actions= [1,1,1,1,2,3,4,5,6,7,8,8,8,15];

  return k;

}



function CAllKeys() {

  var k= new CVietKeys();

  k.keys= "sfjrxzaeowd0123456789\xB4/'`.?~-^(*+d";

  k.actions= [1,2,3,4,5,6,9,10,11,8,15,6,1,2,4,5,3,7,8,8,15,1,1,1,2,3,4,5,6,7,8,8,8,15];

  k.istelex= true;

  return k;

}



// end vietuni.js







	function ddth_HookKeydown(funcHook) {

		if (ddth_arrHookKeydown == null) {

			ddth_arrHookKeydown = new Object();

			ddth_arrHookKeydown.next = null;

			ddth_arrHookKeydown.func = funcHook;

		} else {

			var save = ddth_arrHookKeydown;

			while (ddth_arrHookKeydown.next != null) {ddth_arrHookKeydown = ddth_arrHookKeydown.next;}

			var p = new Object();

			p.func = funcHook;

			p.next = null;

			ddth_arrHookKeydown.next = p;

			ddth_arrHookKeydown = save;

		}

	}

	function ddth_HookPageload(funcHook) {

		if (ddth_arrHookPageload == null) {

			ddth_arrHookPageload = new Object();

			ddth_arrHookPageload.next = null;

			ddth_arrHookPageload.func = funcHook;

		} else {

			var save = ddth_arrHookPageload;

			while (ddth_arrHookPageload.next != null) {ddth_arrHookPageload = ddth_arrHookPageload.next;}

			var p = new Object();

			p.func = funcHook;

			p.next = null;

			ddth_arrHookPageload.next = p;

			ddth_arrHookPageload = save;

		}

	}

	function ddth_HookMouseover(funcHook) {

		if (ddth_arrHookMouseover == null) {

			ddth_arrHookMouseover = new Object();

			ddth_arrHookMouseover.next = null;

			ddth_arrHookMouseover.func = funcHook;

		} else {

			var save = ddth_arrHookMouseover;

			while (ddth_arrHookMouseover.next != null) {ddth_arrHookMouseover = ddth_arrHookMouseover.next;}

			var p = new Object();

			p.func = funcHook;

			p.next = null;

			ddth_arrHookMouseover.next = p;

			ddth_arrHookMouseover = save;

		}

	}

	function ddth_HookMouseout(funcHook) {

		if (ddth_arrHookMouseout == null) {

			ddth_arrHookMouseout = new Object();

			ddth_arrHookMouseout.next = null;

			ddth_arrHookMouseout.func = funcHook;

		} else {

			var save = ddth_arrHookMouseout;

			while (ddth_arrHookMouseout.next != null) {ddth_arrHookMouseout = ddth_arrHookMouseout.next;}

			var p = new Object();

			p.func = funcHook;

			p.next = null;

			ddth_arrHookMouseout.next = p;

			ddth_arrHookMouseout = save;

		}

	}

	function ddth_HookMouseup(funcHook) {

		if (ddth_arrHookMouseup == null) {

			ddth_arrHookMouseup = new Object();

			ddth_arrHookMouseup.next = null;

			ddth_arrHookMouseup.func = funcHook;

		} else {

			var save = ddth_arrHookMouseup;

			while (ddth_arrHookMouseup.next != null) {ddth_arrHookMouseup = ddth_arrHookMouseup.next;}

			var p = new Object();

			p.func = funcHook;

			p.next = null;

			ddth_arrHookMouseup.next = p;

			ddth_arrHookMouseup = save;

		}

	}

	function ddth_HookMousedown(funcHook) {

		if (ddth_arrHookMousedown == null) {

			ddth_arrHookMousedown = new Object();

			ddth_arrHookMousedown.next = null;

			ddth_arrHookMousedown.func = funcHook;

		} else {

			var save = ddth_arrHookMousedown;

			while (ddth_arrHookMousedown.next != null) {ddth_arrHookMousedown = ddth_arrHookMousedown.next;}

			var p = new Object();

			p.func = funcHook;

			p.next = null;

			ddth_arrHookMousedown.next = p;

			ddth_arrHookMousedown = save;

		}

	}



	/* function that hooks keydown event */

	function ddth_keydown() {

		var p = ddth_arrHookKeydown;

		while (p != null) {

			if (p.func()) {return;}

			p = p.next;

		}

	}

	/* function that hooks pageload event */

	function ddth_pageload() {

		var p = ddth_arrHookPageload;

		while (p != null) {

			if (p.func()) {return;}

			p = p.next;

		}

	}

	/* functions that hook mouse events */

	function ddth_mouseover() {

		var p = ddth_arrHookMouseover;

		while (p != null) {

			if (p.func()) {return;}

			p = p.next;

		}

	}

	function ddth_mouseout() {

		var p = ddth_arrHookMouseout;

		while (p != null) {

			if (p.func()) {return;}

			p = p.next;

		}

	}

	function ddth_mouseup() {

		var p = ddth_arrHookMouseout;

		while (p != null) {

			if (p.func()) {return;}

			p = p.next;

		}

	}


	function ddth_mousedown() {

		var p = ddth_arrHookMouseout;

		while (p != null) {

			if (p.func()) {return;}

			p = p.next;

		}

	}



	function ddth_PopupWin(url) {

		var popup = window.open(url,'','toolbar=0,location=0,directories=0,status=1,menubar=0,scrollbars=1');

	}

	function ddth_SetCookie(name, value, expires) {

		document.cookie = name + '=' + escape(value) + ((expires != null) ? ';expires=' + expires.toGMTString() : '') + ';path=/';

	}

	function ddth_GetCookie(name) {

		var cname = name + '=';

		var dc = document.cookie;

		if (dc.length > 0) {

			begin = dc.indexOf(cname);

			if (begin != -1) {

				begin += cname.length;

				end = dc.indexOf(';', begin);

				if (end == -1) end = dc.length;

				return unescape(dc.substring(begin, end));

			}

		}

		return null;

	}



	/* some handy variables */

	ddth_vSCRIPT_SEARCH	= "search.cgi";

	ddth_vSCRIPT_MEMBER	= "member.cgi";

	ddth_vSCRIPT_FORUM	= "./";

	ddth_vSCRIPT_COOKIE	= "cookie.cgi";

	ddth_vCOOKIE_PREFIX	= "ddth_";

	ddth_vBOX		= "11";

	ddth_vMSG		= "";

	ddth_vPAGE		= "";

