/******************************************************************************
 * Telugu Javascript Tool
 *   This script converts telugu RTS(Rice transliteration Standard) input
 *   into unicode telugu in WYSIWYG fashion.
 *
 * Author(s):
 * (C) 2006 Suresh Kolichala, suresh.kolichala@gmail.com
 * Web: http://www.eemaata.com/
 *
 * ThankYous: 
 * 1) This tool has been derived from Telugutoolbar (a Mozilla extension)
 *    written by Murali Nandula (http://www.sahiti.org/).
 * 2) Telugutoolbar was inspired by IndicIME for Mozilla based browsers
 *    by Surekha Sastry and  Srinivasa Raghavan.
 *
 * CHANGES:
 * 1.1 
 * ---
 * 1) BUGFIX: @h does not produce visarga
 * 2) ~1,~2,~3... produce telugu digits.
 *
 *
 ****************************************************************************/
/*
 gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
    .getService(Components.interfaces.nsIClipboardHelper);

 gTransferable = Components.classes["@mozilla.org/widget/transferable;1"]
    .createInstance(Components.interfaces.nsITransferable);

 gSupportString = Components.classes["@mozilla.org/supports-string;1"]
    .createInstance(Components.interfaces.nsISupportsString);

 clip = Components.classes["@mozilla.org/widget/clipboard;1"]
    .getService(Components.interfaces.nsIClipboard);
*/

var indicMode = true;
var isNavigator = false;
var uncommittedChar = null;
var log = '';
var txtControl;
var prevKeyCode;

// myToolbarName = 'Telugu Toolbar'; // name
// myToolbarId = 'telugutoolbar'; // <toolbar>'s id

//======================================================
//Reference: http://www.unicode.org/chatelugu/PDF/U0C00.pdf
//======================================================
 UTF_SIGN_CHANDRABINDU = 3073; //'\u0C01';
 UTF_SIGN_ANUSVARA = 3074; //'\u0C02';
 UTF_SIGN_VISARGA = 3075; //'\u0C03';

//VOWELS
 UTF_LETTER_A  = 3077; //'\u0C05';
 UTF_LETTER_AA = 3078; //'\u0C06';
 UTF_LETTER_I  = 3079; //'\u0C07';
 UTF_LETTER_II = 3080; //'\u0C08';
 UTF_LETTER_U  = 3081; //'\u0C09';
 UTF_LETTER_UU = 3082; //'\u0C0A';
 UTF_LETTER_VOCALIC_R = 3083; //'\u0C0B';
 UTF_LETTER_VOCALIC_L = 3084; //'\u0C0C';
 UTF_LETTER_E  = 3086; //'\u0C0E';
 UTF_LETTER_EE = 3087; //'\u0C0F';
 UTF_LETTER_AI = 3088; //'\u0C10';
 UTF_LETTER_EX = 3089; //'\u0C11';
 UTF_LETTER_O  = 3090; //'\u0C12';
 UTF_LETTER_OO = 3091; //'\u0C13';
 UTF_LETTER_AU = 3092; //'\u0C14';

//CONSONANTS
 UTF_LETTER_KA  = 3093; //'\u0C15';
 UTF_LETTER_KHA = 3094; //'\u0C16';
 UTF_LETTER_GA  = 3095; //'\u0C17';
 UTF_LETTER_GHA = 3096; //'\u0C18';
 UTF_LETTER_NGA = 3097; //'\u0C19';

 UTF_LETTER_CA  = 3098; //'\u0C1A';
 UTF_LETTER_CHA = 3099; //'\u0C1B';
 UTF_LETTER_JA  = 3100; //'\u0C1C';
 UTF_LETTER_JHA = 3101; //'\u0C1D';
 UTF_LETTER_NYA = 3102; //'\u0C1E';

 UTF_LETTER_TTA  = 3103; //'\u0C1F';
 UTF_LETTER_TTHA = 3104; //'\u0C20';
 UTF_LETTER_DDA  = 3105; //'\u0C21';
 UTF_LETTER_DDHA = 3106; //'\u0C22';
 UTF_LETTER_NNA  = 3107; //'\u0C23';

 UTF_LETTER_TA   = 3108; //'\u0C24';
 UTF_LETTER_THA  = 3109; //'\u0C25';
 UTF_LETTER_DA   = 3110; //'\u0C26';
 UTF_LETTER_DHA  = 3111; //'\u0C27';
 UTF_LETTER_NA   = 3112; //'\u0C28';
 UTF_LETTER_NAX  = 3113; //'\u0C29';

 UTF_LETTER_PA  = 3114; //'\u0C2A';
 UTF_LETTER_PHA = 3115; //'\u0C2B';
 UTF_LETTER_BA  = 3116; //'\u0C2C';
 UTF_LETTER_BHA = 3117; //'\u0C2D';
 UTF_LETTER_MA  = 3118; //'\u0C2E';

 UTF_LETTER_YA  = 3119; //'\u0C2F';
 UTF_LETTER_RA  = 3120; //'\u0C30';
 UTF_LETTER_RRA = 3121; //'\u0C31';
 UTF_LETTER_LA  = 3122; //'\u0C32';
 UTF_LETTER_LLA = 3123; //'\u0C33';
 UTF_LETTER_VA  = 3125; //'\u0C35';
 UTF_LETTER_SSA = 3126; //'\u0C36';
 UTF_LETTER_SHA = 3127; //'\u0C37';
 UTF_LETTER_SA  = 3128; //'\u0C38';
 UTF_LETTER_HA = 3129; //'\u0C39';

// DEERGHALU,POLLULU
 UTF_SIGN_AA = 3134; //'\u0C3E';
 UTF_SIGN_I  = 3135; //'\u0C3F';
 UTF_SIGN_II = 3136; //'\u0C40';
 UTF_SIGN_U  = 3137; //'\u0C41';
 UTF_SIGN_UU = 3138; //'\u0C42';
 UTF_SIGN_VOCALIC_R = 3139; //'\u0C43';
 UTF_SIGN_VOCALIC_RR = 3140; //'\u0C44';
 UTF_SIGN_E = 3142; //'\u0C46';
 UTF_SIGN_EE = 3143; //'\u0C47';
 UTF_SIGN_AI = 3144; //'\u0C48';
 UTF_SIGN_EX = 3145; //'\u0C49';
 UTF_SIGN_O = 3146; //'\u0C4A';
 UTF_SIGN_OO = 3147; //'\u0C4B';
 UTF_SIGN_AU = 3148; //'\u0C4C';
 UTF_SIGN_VIRAMA = 3149; //'\u0C4D';

// HISTORICAL VALUES
 UTF_LENGTH_MARK = 3157; //'\u0C55';

// MISC
 UTF_AI_LENGTH_MARK = 3158; //'\u0C56';
 UTF_LETTER_VOCALIC_RR = 3168;//'\u0C60';
 UTF_LETTER_VOCALIC_LL = 3169;//'\u0C61';

 UTF_DIGIT_ZERO  = 3174; //'\u0C66';
 UTF_DIGIT_ONE   = 3175; //'\u0C67';
 UTF_DIGIT_TWO   = 3176; //'\u0C68';
 UTF_DIGIT_THREE = 3177; //'\u0C69';
 UTF_DIGIT_FOUR  = 3178; //'\u0C6A';
 UTF_DIGIT_FIVE  = 3179; //'\u0C6B';
 UTF_DIGIT_SIX   = 3180; //'\u0C6C';
 UTF_DIGIT_SEVEN = 3181; //'\u0C6D';
 UTF_DIGIT_EIGHT = 3182; //'\u0C6E';
 UTF_DIGIT_NINE  = 3183; //'\u0C6F';
         
//==========================================         
ee_telugutoolbar_initialize();

/**
 *
 */
 
function ee_telugutoolbar_initialize() {
  //this.myToolbarId = myToolbarId;
  if(parseInt(navigator.appVersion)>=4) {
    if(navigator.appName=="Netscape") {
      isNavigator = true;
    }
  }
  else { 
    isNavigator = false;
  }
  //document.onkeypress = ee_telugutoolbar_eventCaptured;// For IE 
}


/**
  * This function captures the Keypress event and handles the event accordingly.
  */
function ee_telugutoolbar_eventCaptured(event, input) {
  //if(event.target.type=="textarea" || event.target.type=="text") {
    var target = event.target;
    
    //restrict log
    if(log.length >= 1000) {
      log = '';
    }
    
    if (isNavigator)
		txtControl = target; //keep track of target
	else
		txtControl = input;
    var retVal = ee_handleCharacter(txtControl, event);    
    if (isNavigator) {
       // for Firefox
         event.stopPropagation();
    }
    else {
        event.cancelBubble = true;
    }
    return retVal;
  //}
}

/**
 * Handles the character input
 *
 */
function ee_onKeyDown(event)
{
	
	if (isNavigator)
		return true;
	var keyCode = event.keyCode ? event.keyCode :
      event.charCode ? event.charCode :
      event.which ? event.which : void 0;
  //var key = String.fromCharCode(keyCode);
  //alert("onkeyDown: Keycode/charCode: " + event.keyCode + "/" + event.charCode + " keyCode" + keyCode);
	if( keyCode == 8 || keyCode == 9 || 
      keyCode == 13 || keyCode == 27 ||
      keyCode == 47 ||
      (keyCode >=32 && keyCode <=34) || 
      (keyCode >=36 && keyCode <=38) || 
      (keyCode >=40 && keyCode <=46) || 
      (keyCode >=58 && keyCode <=63) || 
      // (keyCode == 86) || (keyCode == 89) || 
      (keyCode >=91 && keyCode <=93) || 
      (keyCode == 96) || 
      (keyCode >122 && keyCode <=125)) {
     ee_commit(); // ee_commit the composition
     return true;
  }
}

function ee_handleCharacter(textControl, event) {
  var keyCode = event.keyCode ? event.keyCode :
      event.charCode ? event.charCode :
      event.which ? event.which : void 0;
  var key = String.fromCharCode(keyCode);
  
  if (document.newtopic != null)
      indicMode = document.newtopic.langmode[1].checked;

  //alert("Keycode/charCode: " + event.keyCode + "/" + event.charCode + " keyCode" + keyCode);
  // 14(backspace) - reset whole composition
  // 33(pgup), 34(pgdn), 35(End), 36(Home)
  // 37-40 arrow keys  
  // allow @(64) for visargha,^(94) for virama
  // ~(126) for nga,nya "'"(39)
  if( keyCode == 8 || keyCode == 9 || 
      keyCode == 13 || keyCode == 27 ||
      keyCode == 47 ||
      (keyCode >=32 && keyCode <=34) || 
      (keyCode >=36 && keyCode <=38) || 
      (keyCode >=40 && keyCode <=46) || 
      (keyCode >=58 && keyCode <=63) || 
      //(keyCode == 86) || (keyCode == 89) || 
      (keyCode >=91 && keyCode <=93) || 
      (keyCode == 96) || 
      (keyCode >122 && keyCode <=125)) {
     ee_commit(); // ee_commit the composition
     return true;
  }

  //differentiate between # and END keys
  // END -> keyCode = 35, charCode = 0
  //  # -> keyCode = 0, charCode = 35
  if(event.charCode == 0 && event.keyCode == 35) {
    ee_commit();
    return true;
  }

  //Toggle input if it is # char
  // "#" should toggle the input
  // "##" should produce a "#" and toggle back
  if(keyCode != 35) {
    prevKeyCode = keyCode;
  } else if(key =="#" && keyCode == 35 && !(prevKeyCode == 35)){
    ee_commit();
    ee_cmdtoggleInput();
    prevKeyCode = 35;
    if (event.preventDefault) { event.preventDefault(); }
    return true;
  } else if(key == "#" && keyCode == 35 && prevKeyCode == 35){
    ee_commit();
    ee_cmdtoggleInput();
    prevKeyCode = -1;
  }
     
  if(indicMode) {
      //If netscape
      //alert(" isNavigator:" + isNavigator);
      if (isNavigator) {
        if(ee_isPunctuation(key)) {
           ee_commit();
           //alert("punctuation");
           return true;
        }
//alert(uncommittedChar);
        //get the cursor location
        var selStart       = textControl.selectionStart;
        var selEnd         = textControl.selectionEnd;
        var selectedText   = textControl.value.substring(selStart,selEnd);
        var composeText    = (uncommittedChar == null) ? key : (uncommittedChar.asciiText + key); 
        var uncommitLength = (uncommittedChar == null) ? 0 : uncommittedChar.unicodeText.length;
        var aksharas       = ee_getAksharas(composeText);
        //alert(composeText);
        //alert(aksharas);

        // cancel the key event and insert the newKey for the current selection
        if (event.preventDefault) {
          event.preventDefault();
        }
         
        log += key + '@' + selStart + '-' + selEnd + ':' + selectedText +'<BR>';

        var commitText = '';
        var lastChar = null;
        if(aksharas.length > 1) {
          lastChar = aksharas[aksharas.length-1]; 
        }
        
        //donot ee_commit (n-1)th if nth last akshara doesnot have enough chars
        //otherwise donot ee_commit the nth
        var cLen = (lastChar != null && lastChar.unicodeText.length > 0 && aksharas.length > 1) ?
                   aksharas.length - 1 : 0;
        log += 'Total aksharas: ' + aksharas.length + ', commitLen: ' + cLen + '<BR>';
        for(var j=0; j<cLen; j++) {
          commitText += aksharas[j].unicodeText; //ee_commit unicode
        }

        //reclaculate the uncommittedChar
        var uncommittedAsciiText     = '';
        var uncommittedUnicodeText   = '';
        for(var j=cLen; j<aksharas.length; j++) {
          uncommittedAsciiText += aksharas[j].asciiText;
          uncommittedUnicodeText   += aksharas[j].unicodeText;
        }
        uncommittedChar = new ee_ComboChar(uncommittedAsciiText, uncommittedUnicodeText);
	var scrollTop = textControl.scrollTop;
        
        textControl.value = textControl.value.substring(0, 
                  selStart - uncommitLength) 
                  + commitText 
                  + uncommittedChar.unicodeText
                  + textControl.value.substring(selEnd);

        //calculate the caret location
        
        var newSelStart = selStart - uncommitLength + commitText.length + uncommittedChar.unicodeText.length;
        var newSelEnd = newSelStart;
        
        textControl.setSelectionRange(newSelStart, newSelEnd);
	textControl.scrollTop = scrollTop;
        log += 'uncommitted text: ' + uncommittedChar.asciiText +'@' 
               + newSelStart + ':' + newSelEnd + '<BR>';
        //document.getElementById("output").innerHTML = log;
        
        return false;
      } else {
		if(ee_isPunctuation(key)) {
           ee_commit();
           //alert("punctuation");
           return true;
        }
		//alert(" uncommittedChar: "+uncommittedChar.asciiText);
        //get the curson location
        var composeText    = (uncommittedChar == null) ? key : (uncommittedChar.asciiText + key); 
        var uncommitLength = (uncommittedChar == null) ? 0 : uncommittedChar.unicodeText.length;
        var aksharas       = ee_getAksharas(composeText);
        //alert(composeText);
        //alert(aksharas);

        // cancel the key event and insert the newKey for the current selection
        if (event.preventDefault) {
          event.preventDefault();
        }
         
        //log += key + '@' + selStart + '-' + selEnd + ':' + selectedText +'<BR>';

        var commitText = '';
        var lastChar = null;
        if(aksharas.length > 1) {
          lastChar = aksharas[aksharas.length-1]; 
        }
        
        //donot ee_commit (n-1)th if nth last akshara doesnot have enough chars
        //otherwise donot ee_commit the nth
        var cLen = (lastChar != null && lastChar.unicodeText.length > 0 && aksharas.length > 1) ?
                   aksharas.length - 1 : 0;
        log += 'Total aksharas: ' + aksharas.length + ', commitLen: ' + cLen + '<BR>';
        for(var j=0; j<cLen; j++) {
          commitText += aksharas[j].unicodeText; //ee_commit unicode
        }

        //reclaculate the uncommittedChar
        var uncommittedAsciiText     = '';
        var uncommittedUnicodeText   = '';
        for(var j=cLen; j<aksharas.length; j++) {
          uncommittedAsciiText += aksharas[j].asciiText;
          uncommittedUnicodeText   += aksharas[j].unicodeText;
        }
        uncommittedChar = new ee_ComboChar(uncommittedAsciiText, uncommittedUnicodeText);
        //alert("New uncommittedChar: " + uncommittedChar.asciiText);
		sel = document.selection.createRange();
		sel.select();
		sel.moveStart("character",-1*uncommitLength);
		//alert("Current PositionChar:" + sel.text.substring(0,uncommitLength));
		sel.text = commitText + uncommittedChar.unicodeText;
		return false;
        //document.getElementById("output").innerHTML = log;
      }    
   }// unselected text 
   return true;
 }

 /**
  *
  */
 function ee_commit() {
   uncommittedChar = new ee_ComboChar('','');
   //alert("ee_commit");
   return;
 }

  /**
    * This function returns true, if any of the modifiers keys were pressed 
    * before pressing any other button, otherwise returns false.
    */
  function ee_telugutoolbar_isModifierKeyOn(evt) {
    if(evt.ctrlKey || evt.altKey) 
      return true;

    return false; 
  }

  /**
   *  Process Ascii text and returns the indian aksharas('cluster') 
   *  in unicode as array.
   *
   *  Ex: saMskRtaM => ["\uxxx\uxxx","\uxxx\uxxx","\uxxx\uxxx"]
   */
  function ee_getAksharas(s) {
    var aAkshara;
    var aksharas = new Array();
    var caksharas = new Array();
    var origStr = s;
    var i = 0;
    var loop = true;
    log += 'Splitting: ' + s + '<BR>';

    //replace m,n with M(anuswara) for some cases
    s = s.replace(/[mn]([gGcCjJTDtdbB])/g,'M$1');
    s = s.replace(/m([lvsS])/g,'M$1');
    s = s.replace(/x/g,'ksh');

    //Get aksharas
    while(true) {
      aAkshara = ee_getFirstAkshara(s);
      if(aAkshara == '') break;
      aksharas[i] = aAkshara; 
      if(ee_isPunctuation(aAkshara)) {
        caksharas[i] = new ee_ComboChar(aAkshara, aAkshara);
      } else {
        caksharas[i] = new ee_ComboChar(aAkshara, ee_getAksharaUnicode(aAkshara)); 
      }
      s = s.substring(aAkshara.length);
      log += '=>' + caksharas[i].asciiText + '(' + caksharas[i].unicodeText +')<=, left =>' + s + '<=<BR>';
      i++;
      if(s.length <= 0) break;
    }
    log += origStr + " = ";
    for(var j=0; j<caksharas.length; j++) {
      //log += caksharas[j].unicodeText;
    }
    return caksharas;
 } 

  /**
   *
   */
  function ee_isPunctuation(str) {
    if(str.match(/\-|\.|\s|`|\!|\#|\$|\%|\&|\(|\)|_|=|\||\\|\[|\]|:|;|\"|,|\.|\<|\>|\/|\?|\n|\r\n/)) {
      return true;
    } else {
      return false;
    }
  }

  /**
   *  Process Ascii text and returns the first indian aksharam
   *  saMskRtaM => saM
   *  bhArat    => bhA
   *  !!!DONOT EDIT THIS FUNCTION IF YOU DONT KNOW WHAT YOU ARE DOING!!!
   */
  function ee_getFirstAkshara(str) {
    var C1 = "k|K|kh|g|G|\~j|\~m";
    var C2 = "c'|c|C|j|J|\~n|\~c";
    var C3 = "T|Th|D|Dh|N";
    var C4 = "t'|t|th|d'|d|dh|n'|n";
    var C5 = "p|f|P|b|B|m";
    var C6 = "y|r|l'|l|L|v|S|s|h|~r";
    var D = "~[0-9]";
    //order important 'aa,uu,ee' etc. should preced 'a,u,e'
    var V = "aa|ae|au|ou|ow|ai|uu|ee|oo|ii|a|A|i|I|u|U|Ru|R|e|E|o|O|\~l|\~L"; //vowels, vowelsigns
    var V2 = "M|H|@h|@M"; //secondary vowelsigns
    var PUNC = "\-|\.|\s|`|\!|#|\$|%|\&|\(|\)|_|=|\||\\|\[|\*|\]|:|;|'|\"|,|\.|\<|\>|\/|[0-9]|\n|\r\n";
    var C = C1 + "|" + C2 + "|" + C3 + "|" + C4 + "|" + C5 + "|" + C6;

    var exp = "("  + D + "){1}|" + 
              "((" + C + "){1,4}(" + V + "){0,1}(" + V2 + "){0,1})|" +
              "(("  + V + "){1}(" + V2 + "){1})|" + 
              "(("  + V + "){1})|" +
              "("  + PUNC + ")";
    var rule = new RegExp(exp);
    var aksharas = rule.exec(str);
    if(typeof aksharas == 'undefined' || aksharas == null) return '';
    else return aksharas[0];
  }



  /**
   *  Extracts individual consonant from a akshara
   *  Ex: Input: 'saM' => Output: 's'
   *      Input:  'skR' => Output: 's'  
   *      Input:  'taM' => Output: 't'  
   *  Similarly, bhA->bh, ra->r, taM->t of 'bhArataM'
   *
   *  !!!DONOT EDIT THIS FUNCTION IF YOU DONT KNOW WHAT YOU ARE DOING!!!
   */
  function ee_getAksharaConsonant(str) {
    var C1 = "kKgGcCjJTDtdnpfPbBmrSslL"; //can be followed by optional 'h'
    var C2 = "ctdnl"; //can be followed by a single quote "'"
    var C3 = "Nyvw"; //no h
    var C4 = "\~[mjncrlL]"; //NGA,NYA,TCHA
    var C5 = "h"; //@h is reserved VISARGA, h for HA

    //order important
    var exp = "[" + C1 + "]h" + "|[" + C2 + "]\'|[" + C1 + C3 + "]|" + C4 + "|" + C5 ; 
    var rule = new RegExp(exp,'g');

    var consonants = rule.exec(str);
    //log += 'cons for : ' +  str + ' rule : ' + exp + '<BR>';
    if(consonants != null) {
       return consonants[0];
    } else {
       return '';
    }
  }

  /**
   *  Extracts individual vowel from a akshara
   *  Ex: Input: 'aM' => Output: 'a'
   *      Input: 'kR' => Output: 'R'  
   *      Input: 'taM' => Output: 'a'  
   *  Similarly, bhA->bh, ra->r, taM->t of 'bhArataM'
   *
   *  !!!DONOT EDIT THIS FUNCTION IF YOU DONT KNOW WHAT YOU ARE DOING!!!
   */
  function ee_getAksharaVowel(str) {
    //order important
    var V = "aa|ae|au|ou|ow|ai|uu|ee|oo|ii|a|A|i|I|u|U|Ru|R|e|E|o|O|\~l|\~L"; //vowels
    var D = "~[0-9]";
    var exp = "(" + D + ")|(("  + V + "){1})";
    var rule = new RegExp(exp,'g');

    var consonants = rule.exec(str);
    //log += 'cons for : ' +  str + ' rule : ' + exp + '<BR>';
    if(consonants != null) {
       return consonants[0];
    } else {
       return '';
    }
  } 

  /**
   *
   */
  function ee_getAksharaUnicode(str) {
    var consCount = 0;
    var vowCount = 0;
    var uAkshara = '';
    var count = 0;
    var uc = '';
    while(str.length >= 0) {
      if(count++ > 10) break;

      //extract consonants
      var c = ee_getAksharaConsonant(str);
      if(c != '' && str.indexOf(c) == 0) { 
        log += '-->found cons ' + c + ' of ' + str + '<BR>';
        if(consCount > 0) uAkshara += String.fromCharCode(UTF_SIGN_VIRAMA);
        consCount++;
        uAkshara += String.fromCharCode(ee_getAksharaUnicodeConsonant(c));
        str = str.substring(c.length);
        continue;
      }

      //try for a vowel
      log += '--> lookinup for vowel1: ' + str +'<BR>';
      var v = ee_getAksharaVowel(str);
      if(v != '') {
        if(consCount > 0) {
          uc = ee_getAksharaUnicodeSignFromMap(v);
          uAkshara += (uc > 0) ? String.fromCharCode(uc) : '';
          str = str.substring(v.length);
        } else {
          uc = ee_getAksharaUnicodeVowel(v);
          uAkshara += (uc > 0) ? String.fromCharCode(uc) : '';
          str = str.substring(v.length);
          vowCount++;
        }
      } 

      log += '-->no more consonants in ' + str + ' <BR>';
      uc = '';
      if(str != '') {
        log += '--> lookinup for sign: ' + str +'<BR>';
        uc = ee_getAksharaUnicodeSignFromMap(str);
      } 

      log += '-->conscount ' + consCount + ' uc: ' + uc +'<BR>';
      uAkshara += (uc > 0) ? String.fromCharCode(uc) : ee_composeMisc(str);
      break;
    }
    log += '---->' + uAkshara + '<BR>';
    //alert(log);
    return uAkshara;
  }

  /**
   *
   */
  function ee_getAksharaUnicodeConsonant(str) {
    switch(str) {  
      case 'k': return UTF_LETTER_KA; break; 
      case 'K': return UTF_LETTER_KHA; break; 
      case 'Kh': return UTF_LETTER_KHA; break; 
      case 'kh': return UTF_LETTER_KHA; break; 
      case 'q': return UTF_LETTER_KHA; break; 
      case 'Q': return UTF_LETTER_KHA; break; 
      case 'g': return UTF_LETTER_GA; break; 
      case 'G': return UTF_LETTER_GHA; break; 
      case 'Gh': return UTF_LETTER_GHA; break; 
      case 'gh': return UTF_LETTER_GHA; break; 
      case '~j': return UTF_LETTER_NGA; break; 
      case '~m': return UTF_LETTER_NGA; break; 

      case 'c': return UTF_LETTER_CA; break; 
      case '~c': return UTF_LETTER_CA; break; 
      case 'ch': return UTF_LETTER_CA; break; 
      case 'c\'': return UTF_LETTER_CHA; break; 
      case 'Ch': return UTF_LETTER_CHA; break; 
      case 'C': return UTF_LETTER_CHA; break; 
      case 'j': return UTF_LETTER_JA; break; 
      case 'J': return UTF_LETTER_JHA; break; 
      case 'jh': return UTF_LETTER_JHA; break; 
      case 'Jh': return UTF_LETTER_JHA; break; 
      case '~n': return UTF_LETTER_NYA; break; 

      case 'T': return UTF_LETTER_TTA; break; 
      case 't\'': return UTF_LETTER_TTA; break; 
      case 'Th': return UTF_LETTER_TTHA; break; 
      case 'D': return UTF_LETTER_DDA; break; 
      case 'Dh': return UTF_LETTER_DDHA; break; 
      case 'N': return UTF_LETTER_NNA; break; 
      case 'nh': return UTF_LETTER_NNA; break; 
      case 'n\'': return UTF_LETTER_NNA; break; 

      case 't': return UTF_LETTER_TA; break; 
      case 'th': return UTF_LETTER_THA; break; 
      case 'd': return UTF_LETTER_DA; break; 
      case 'dh': return UTF_LETTER_DHA; break; 
      case 'd\'': return UTF_LETTER_DHA; break; 
      case 'n': return UTF_LETTER_NA; break; 

      case 'p': return UTF_LETTER_PA; break; 
      case 'P': return UTF_LETTER_PHA; break; 
      case 'ph': return UTF_LETTER_PHA; break; 
      case 'Ph': return UTF_LETTER_PHA; break; 
      case 'f': return UTF_LETTER_PHA; break; 
      case 'fh': return UTF_LETTER_PHA; break; 
      case 'b': return UTF_LETTER_BA; break; 
      case 'bh': return UTF_LETTER_BHA; break; 
      case 'Bh': return UTF_LETTER_BHA; break; 
      case 'B': return UTF_LETTER_BHA; break; 
      case 'm': return UTF_LETTER_MA; break; 

      case 'y': return UTF_LETTER_YA; break; 
      case 'r': return UTF_LETTER_RA; break; 
      case 'l': return UTF_LETTER_LA; break; 
      case 'v': return UTF_LETTER_VA; break; 
      case 'w': return UTF_LETTER_VA; break; 
      case 'S': return UTF_LETTER_SSA; break; 
      case 'Sh': return UTF_LETTER_SHA; break; 
      case 'sh': return UTF_LETTER_SHA; break; 
      case 's': return UTF_LETTER_SA; break; 
      case 'h': return UTF_LETTER_HA; break; 
      case 'L': return UTF_LETTER_LLA; break; 
      case 'Lh': return UTF_LETTER_LLA; break; 
      case 'l\'': return UTF_LETTER_LLA; break; 
      case 'lh': return UTF_LETTER_LLA; break; 
      case 'r\'': return UTF_LETTER_RRA; break; 
      case '~r': return UTF_LETTER_RRA; break; 
      default: break;
    }
  } 

  /**
   *
   */
  function ee_getAksharaUnicodeVowel(str) {
    switch(str) {  
      case 'a': return UTF_LETTER_A; break;
      case 'aa': return UTF_LETTER_AA; break;
      case 'a\'': return UTF_LETTER_AA; break;
      case 'A': return UTF_LETTER_AA; break;
      case 'i': return UTF_LETTER_I; break;
      case 'ii': return UTF_LETTER_II; break;
      case 'i\'': return UTF_LETTER_II; break;
      case 'ee': return UTF_LETTER_II; break;
      case 'I': return UTF_LETTER_II; break;
      case 'u': return UTF_LETTER_U; break;
      case 'uu': return UTF_LETTER_UU; break;
      case 'u\'': return UTF_LETTER_UU; break;
      case 'ua': return UTF_LETTER_UU; break;
      case 'oo': return UTF_LETTER_UU; break;
      case 'U': return UTF_LETTER_UU; break;
      case 'e': return UTF_LETTER_E; break;
      case 'E': return UTF_LETTER_EE; break;
      case 'ai': return UTF_LETTER_AI; break;
      case 'o': return UTF_LETTER_O; break;
      case 'O': return UTF_LETTER_OO; break;
      case 'oe': return UTF_LETTER_OO; break;
      case 'oa': return UTF_LETTER_OO; break;
      case 'o\'': return UTF_LETTER_OO; break;
      case 'au': return UTF_LETTER_AU; break;
      case 'ou': return UTF_LETTER_AU; break;
      case 'ow': return UTF_LETTER_AU; break;
      case 'R': return UTF_LETTER_VOCALIC_R; break;
      case 'r\'': return UTF_LETTER_VOCALIC_R; break;
      case 'Ru': return UTF_LETTER_VOCALIC_RR; break;
      case '~l': return UTF_LETTER_VOCALIC_L; break;
      case '~L': return UTF_LETTER_VOCALIC_LL; break;

      case '~0': return UTF_DIGIT_ZERO; break;
      case '~1': return UTF_DIGIT_ONE; break;
      case '~2': return UTF_DIGIT_TWO; break;
      case '~3': return UTF_DIGIT_THREE; break;
      case '~4': return UTF_DIGIT_FOUR; break;
      case '~5': return UTF_DIGIT_FIVE; break;
      case '~6': return UTF_DIGIT_SIX; break;
      case '~7': return UTF_DIGIT_SEVEN; break;
      case '~8': return UTF_DIGIT_EIGHT; break;
      case '~9': return UTF_DIGIT_NINE; break;
      default: break;
    }
  } 

  /**
   *
   */
  function ee_getAksharaUnicodeSignFromMap(str) {
    switch(str) {  
      case 'aa': return UTF_SIGN_AA; break;
      case 'A': return UTF_SIGN_AA; break;
      case 'i': return UTF_SIGN_I; break;
      case 'I': return UTF_SIGN_II; break;
      case 'ee': return UTF_SIGN_II; break;
      case 'ii': return UTF_SIGN_II; break;
      case 'u': return UTF_SIGN_U; break;
      case 'uu': return UTF_SIGN_UU; break;
      case 'oo': return UTF_SIGN_UU; break;
      case 'U': return UTF_SIGN_UU; break;
      case 'e': return UTF_SIGN_E; break;
      case 'E': return UTF_SIGN_EE; break;
      case 'ae': return UTF_SIGN_EE; break;
      case 'ea': return UTF_SIGN_EE; break;
      case 'ai': return UTF_SIGN_AI; break;
      case 'o': return UTF_SIGN_O; break;
      case 'O': return UTF_SIGN_OO; break;
      case 'au': return UTF_SIGN_AU; break;
      case 'ou': return UTF_SIGN_AU; break;
      case 'ow': return UTF_SIGN_AU; break;
      case 'R': return UTF_SIGN_VOCALIC_R; break;
      case 'Ru': return UTF_SIGN_VOCALIC_RR; break;
      case 'M': return UTF_SIGN_ANUSVARA; break;
      case '@h': return UTF_SIGN_VISARGA; break;
      case 'H': return UTF_SIGN_VISARGA; break;
      case '^': return UTF_SIGN_VIRAMA; break;
      case '@M': return UTF_SIGN_CHANDRABINDU; break;
      default: break;
   }
  }

function ee_composeMisc(str) {
  switch(str) {
    case '0': return '0'; break;
    case '1': return '1'; break;
    case '2': return '2'; break;
    case '3': return '3'; break;
    case '4': return '4'; break;
    case '5': return '5'; break;
    case '6': return '6'; break;
    case '7': return '7'; break;
    case '8': return '8'; break;
    case '9': return '9'; break;
    //case '~': return '~'; break;
    default: return ''; break;
  }
}

/**
 * Toggles the input mode for Telugu
 */
function ee_cmdtoggleInput() {
  indicMode = !indicMode;
  if (! isNavigator)
	event.keyCode = void 0;
  if (document.newtopic != null)
   document.newtopic.langmode[(indicMode ? 1 : 0)].checked=true;
}

/**
 * A combochar class.
 * Keeps track of character under composition. When user enters a
 * key we need to recompose the akshara('cluster').
 */
//function ee_ComboChar(asciiText, unicodeText, startPos) {
function ee_ComboChar(asciiText, unicodeText) {
  this.asciiText = asciiText;
  this.unicodeText = unicodeText;
  //this.caretPosition = startPos;
}


/**
 *
 */
function ee_batchProcess(target) {
  var selStart = 0;
  var selEnd   = target.value.length;
  var selText = target.value.substring(selStart, selEnd);
  var count = 0;
  var uText = ee_convertRts2Unicode(selText);
  target.value = target.value.substring(0,selStart-1) +
                 uText +
                 target.value.substring(selEnd, target.value.length);
}

/**
 *
 */
function ee_convertRts2Unicode(rtsText) {
  var uText = "";
  // convert line by line
  var count = 0;
  while(rtsText.length > 0) {
    var exp = new RegExp(".*[\r\n]?");
    var lines  = exp.exec(rtsText);
    var aksharas = ee_getAksharas(lines[0]);
    for(var i=0; i<aksharas.length; i++) {
      uText += aksharas[i].unicodeText;
    }
    uText += '\n';
    rtsText = rtsText.substring(lines[0].length);
    if(count++ > 256) break; //
  } 
  return uText;
}

/**
 *
 */
function ee_replaceBrowserText() {
  alert("Sorry! This feature is not yet implemented.");
  var txt = '';
  if (window.getSelection) {
    alert('**1');
    var selection = window.getSelection();
    txt = selection.toString();
    alert("Text: " + txt);
    var uniText = ee_convertRts2Unicode(txt);
    alert("uText: " + uniText);
    if (selection.rangeCount) {
      var range = selection.getRangeAt(0);
      var tNode = document.createTextNode(ee_convertRts2Unicode("ikkaDa: ") + uniText);
      range.deleteContents();
      range.insertNode(tNode);
    }
  } else if (document.getSelection) {
    selection = document.getSelection();
    txt = document.getSelection();
  } else if (document.selection) {
    selection = document.selection;
    txt = document.selection.createRange().text;
  } else {
  }
}


