var supported = (document.all || document.getElementById);
var disabled = false;
var charmapid = 1;
var keymodeid = 0;
var linebreak = 0;
var theTyper = null;

reset = function(){}
telexingVietUC = initTyper;

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;
  }

}

initCharMap = function() { return new CVietUniCodeMap(); }

initKeys = function() {
  switch (keymodeid) {
    case 1: return new CTelexKeys();
    case 2: return new CVniKeys();
    case 3: return new CViqrKeys();
    default: return new CVKOff();
  }
}

function initTyper(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;
}

function onKeyDown(evt) {
  var c= event? event.keyCode: evt.which? evt.which: 0;
  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= event? event.keyCode: evt.which? evt.which: 0;
  if(theTyper) theTyper.value= this.getCurrentWord();
  else theTyper= new CVietString(this.getCurrentWord());
  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();
  var backward = -17;
  do {
    var caret2 = caret.duplicate();
    caret2.moveStart("character", backward++);
  } while (caret2.parentElement() != this && 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.Dau= Dau;
  this.AEOWD= AEOWD;
  this.findCharToChange= findCharToChange;
  return this;
}

function typing(ctrl) {
  this.changed = 0;
  this.ctrlchar = String.fromCharCode(ctrl);
  if (linebreak) linebreak= 0; else this.keymode.getAction(this);
  return this.changed;
}

function AEOWD(type) {
  var lc = this.charmap.lastCharsOf(this.value);
  var telex = this.charmap.getAEOWD (lc[0], type);
  if (!(this.changed = telex[0])) return;
  this.value= this.value.replaceAt(this.value.length-lc[1],telex[1],lc[1]);
  if (!telex[2]) { spellerror= 1; this.value+= this.ctrlchar; }
}

function Dau(type) {
  var info = this.findCharToChange(type);
  if (!info) return;
  var 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 findCharToChange(type) {
  var lastchars= this.charmap.lastCharsOf(this.value, 3);
  var i=0, c=lastchars[0][0];
  if (c=='\\') return [c,this.value.length-1,1];
  while( !this.charmap.isVowel(c) ) {
     if ((c < 'A') || (i >= 2)) return null;
     if (!(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==2 && type!=6) {
    var tmp = pc + c;
    if ((tmp!="ng") && (tmp!="ch") && (tmp!="nh")) return null;
    if (tmp=="ch" && type!=1 && type!=3) return null;
  }
  else if (i==1 && type!=6) {
    if((c>='v') || ("bdfghjklqrs".indexOf(c) >= 0)) return null;
    else if ("cpt".indexOf(c) >=0 && type!=1 && type!=3) return null;
  }
  else if (this.charmap.isVowel(lastchars[1][0],0) && ("uyoia".indexOf(c)>=0)){
    if ( !(((pc=='o') && (c=='a')) || ((pc=='u') && (c=='y')))
      && !(((ppc=='q') && (pc=='u')) || ((ppc=='g') && (pc=='i'))) ) ++i;
  }
  var pos= this.value.length;
  for (var j=0; j<= i; j++) pos -= lastchars[j][1];
  return [lastchars[i][0], pos, lastchars[i][1]];
}
// end CVietString


// character-map template
//
function CVietCharMap() {
this.vietchars = null;
this.length = 149;
return this;
}

CVietCharMap.prototype.charAt = function(ind) {
  var chrcode = this.vietchars[ind];
  return chrcode ? String.fromCharCode(chrcode) : null;
}

CVietCharMap.prototype.isVowel = function (chr,isnumber) {
  var c = isnumber? String.fromcharCode(chr): chr;
  var ind = this.length-5;
  while ((c != this.charAt(ind)) && (ind > 0)) --ind;
  return ind;
}

CVietCharMap.prototype.getDau = function (vchr, type) {
  if(vchr=='\\') return (type==3)? [1,'.',1]: (type==4)? [1,'?',1]: [0];
  var ind= this.isVowel(vchr);
  if (!ind) return [0];
  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];
  if (accented & (charset*24+ind_i == ind)) charset= 0;
  return [1, this.charAt(charset*24+ind_i), charset];
}

CVietCharMap.prototype.getAEOWD = function (vchr, type) {
  var ind = 1, len = this.length;
  if (type==15) while (this.charAt(len-ind)!=vchr) {if (++ind>4) return [0];}
  else while ((ind < 25) && (vchr != this.charAt(ind))) { ind++; }
  if (ind >= 25) return [0];
  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]];
  var vc= (type==15)? (ind-1)%2: (ind-1)%12;
  var i= -1, shift= 0;
  while (shift==0 && ++i<10) {
    if (map[0][i]==type)
      if(map[1][i]==vc) shift= map[2][i]-vc;
      else if(map[2][i]==vc) shift= map[1][i]-vc;
  }
  if (shift==0) return [0];
  if(type==15){ind=len-(ind+shift); shift= -shift;} else ind+= shift;
  return [1, this.charAt(ind), (shift>0)];
}

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;
}


String.prototype.replaceAt= function(i,newchr,clen) {
  return this.substring(0,i)+ newchr + this.substring(i+clen);
}

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 ctrl= typer.ctrlchar.toLowerCase();
    var i= this.keys.indexOf(ctrl);
    if(i<0) return;
    var a= this.actions[i];
    if(a<=6) typer.Dau(a); else typer.AEOWD(a);
  }
  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/'`.?~-^(*+d";
  k.actions= [1,1,1,2,3,4,5,6,7,8,8,8,15];
  return k;
}

// end vietuni.js
