/*
 * Copyright 2006 Tridium, Inc. All Rights Reserved.
 */

/**
 * Keypad.
 *
 * @author    JJ Frankovich
 * @creation  22 May 09
 * @version   $Revision$ $Date$
 * @since     Baja 3.4
 */

////////////////////////////////////////////////////////////////
// Keypad
////////////////////////////////////////////////////////////////

var keypad = new Keypad(); // global instance
function Keypad()
{ 
  this.cachedKeyboard = null;
  this.preload = function()
  { 
    var preloadElem = $('preload');
    var div = document.createElement("div");
    
    var width = "width:657px;";
    if(hx.ie)
      width = "width:633px;";
    var body = "";
    body += "<table><tr><td style='white-space:nowrap; " + width +"' id='keypadDescription'>";
    body += this.makeInput();
    body += "</td><td> </td><td>";
    
    body +="<div class='keyboard_button keyboard_button_G'";
    body += " onclick='keypad.closeDialog();' >Ok</div>";      

    body += "</td></tr><tr><td colspan=3>";
    
    body += "<div id='keyboard' class='keyboard'>";
    body += this.makeDefaultPalette();
    body += "</div>";    
    body += "</td></tr></table>";
    
    div.innerHTML=body;
    
    this.cachedKeyboard=div; 
  }
  
  this.show = function(elem)
  {
    if(hx.dynamic)
    {
      //stop polling
      hx.failure = true;
    }
      
    keypad.commitElem = elem;
    
    if(elem != null)
    {
      keypad.commitValue=elem.value;
      keypad.setCaretPosition(keypad.commitValue.length);
    }
    else
      keypad.commitValue="";
      
    
    var body = "<div id='keyboard_dialog'>Loading...</div>";
    
    hx.showDialog(keypad.chrome(body, "Virtual Keyboard", true));
    setTimeout('keypad.finishShow()', 1);
  }
  
  this.finishShow = function()
  {
    
    if(keypad.cachedKeyboard == null)
      keypad.preload();
    
    var preloadElem = $('preload');
    if(this.cachedKeyboard.parentNode != null)
      this.cachedKeyboard.parentNode.removeChild(this.cachedKeyboard);
    
    var dialogDiv = $('keyboard_dialog');
    
    dialogDiv.parentNode.replaceChild(this.cachedKeyboard, dialogDiv);
    
    $('keypadDescription').innerHTML=this.makeInput();
    
    try
    {
      $("keypadCommit").style.display='';
      $("keypadCommit").focus();
      
    }
    catch(err)
    {}        
    
    //if(hx.ie)
//      $( hx.dialogId + hx.dialogCounter).firstChild.nextSibling.style.width="800px";
  }
  
  this.commit = function(refocus)
  {
    if (keypad.commitElem != null)
    {
      keypad.commitElem.value=keypad.commitValue;
      if(refocus)
      {
        try
        {
          keypad.commitElem.focus();        
          if(save != null)
            save.modified();
          
        }
        catch(err)
        {        
        }
      }      
      
      touchscreen.fireOnChange(keypad.commitElem);
    }
  }
  
////////////////////////////////////////////////////////////////
// Methods
////////////////////////////////////////////////////////////////

  /**
   * Add chrome for the dialog around body.
   */
  this.chrome = function(body, title, fullHeight)
  {
    var c = "";
    
    c += "<table border='0' align='center' "
    if(fullHeight)
      c += "height='100%'";
    c += ">";
    c += "<tr><td valign='middle'>";
    c += "<div class='control-bg dialog-outerBorder'>";
    c += "<div class='dialog-innerBorder'>";
//    
    // Titlebar
    c += "<div class='dialog-header'>";
    c += title;
    c += "</div>";
//    
    // Padding
    c += "<div class='dialog-content'>";
//    
//    // invisible span with a single value so that onclick is not skippd
//    c += "<span style='display:none;'>";
//    c += " <input type='text' name='dialog-fix' style='display:none;'/>";
//    c += "</span>";
//    
//    // maxHeight
//    c += "<div id='dialog-maxHeight'>";
    
    // Content
    c += body;
//    
    //end maxHeight
//    c += "</div>";
//    
    // End padding
    c += "</div>";
//    
//    // End dialog
    c += "</div>"; // inner border
    c += "</div>"; // outer border
    c += "</td></tr>";
    c += "</table>";
        
    
    return c;
  }
  
  /**
   * Create default palette.
   */
  this.makeDefaultPalette = function()
  {         
    var p = "";
        p += "<div class='keyboard_row'>";
    
    for (var i=0; i<this.def.length; i++)
    {
        if(this.def[i] == null)
        {
          p += "</div><div class='keyboard_row'>";  
          continue;
        }
        
        var val = this.def[i][0];
        var altVal = null;
        if(this.def[i][2] != null && this.def[i][1] == null)
          altVal = this.def[i][2];
       
        
        p += "<div class='keyboard_button keyboard_button_" + this.def[i][3];
        p += "'";
        
        p += "oncontextmenu  ='return touchscreen.endEvent(window.event);'";
        
        if(this.def[i][4] == null)
        {
          p += "onmousedown='keypad.update(this);'";
          if(hx.ie)
            p += "ondblclick='keypad.update(this);'";
        }
        else
        {
          p += "onmousedown='" + this.def[i][4] + ";'";          
          if(hx.ie)
            p += "ondblclick='" + this.def[i][4] + ";'";          
        }
        
        if(this.def[i][5] != null)
          p += "id='" + this.def[i][5] + "'";          
        
        p += "index='" + i + "'";
        p += ">";  
        p += val;
        if(altVal != null)
          p += "<span class='keyboard_superscript'>" + altVal + "</span>";
          
        p += "</div>";                        
        
     }
    
    p += "</div>";    
    return p;
  }
  
  this.makeInput = function()
  {
    var s = "";
    
    
    //try to get a description
    s+="<b>" + keypad.getDescription(keypad.commitElem) + "</b> ";          
//    
    if(keypad.commitElem != null && keypad.commitElem.tagName == 'TEXTAREA')
    {
      var rows = keypad.commitElem.rows;
      if(rows != null && rows > 3)
        rows=3;
      s += "<textarea id='keypadCommit' ";
      s +=" noKeyboard='true'"; 
      s += "onkeyup='keypad.inputChanged(this);'";
      s += "onmouseup='keypad.inputMouseUp(this);'";
      s += "style='display:none;'"; 
      s += " cols=" + keypad.commitElem.cols;
      s += " rows=" + rows;
      s += " >" + keypad.commitValue;
      s += "</textarea>";
      s += keypad.getAfterDescription(keypad.commitElem);
      return s;
    }
    else
    {
      s += "<input ";
        
      s +="noKeyboard='true'"; 
      
      if(keypad.commitElem != null && keypad.commitElem.type == 'password')
      {
        //Fix for disguised passwordFE
        if(keypad.hasSubstitute(keypad.commitElem))
          keypad.commitValue="";
        s +="type='password'";
      }
      else
        s +="type='text'"; 
      
      s +="id='keypadCommit' ";
      s += "style='width:200px; display:none;'"; 
      s += "value='"+ keypad.commitValue + "'";
      s += "onkeyup='keypad.inputChanged(this);'";
      //s += "onmouseup='keypad.inputMouseUp(this);'";      
      s += " />";
      
      s += keypad.getAfterDescription(keypad.commitElem);
      return s;
    }
  }
  
  //Fix for disguised passwordFE
  this.substitute =  65533; //ASCII 'replacement' character
  
  this.hasSubstitute = function(elem)
  {
    var value = elem.value;
    for(var i=0; i<value.length; i++)
    {
      if(value.charCodeAt(i) == keypad.substitute)
      {
        return true;        
      }
    }    
    return false;
  }
  
  this.getDescription = function(commitElem)
  {
    if(commitElem == null)
      return "";
    var td = commitElem.parentNode;
    while(td.tagName == 'SPAN' && td.parentNode != null)
    {
      td=td.parentNode;      
    }
    
    if(td.tagName == 'TD')
    {
      
      var match = null;
      var sibling = td.previousSibling;
      while(sibling != null)
      {
        if(sibling.tagName == 'TD' && sibling.innerHTML != '&nbsp;')
        {
          match=sibling;
          break;
        }
        sibling=sibling.previousSibling
      }
      
      return keypad.checkForDescription(match);            
    }
    return "";
  }
  
  this.checkForDescription = function(match)
  {
    if(match != null && match.nodeValue != null)
      return match.nodeValue;
      
    if(match == null)
      return "";
    var childNodes = match.childNodes;
    for(var i=0; i<childNodes.length; i++)
    {
      if(childNodes[i].nodeValue != null)
        return childNodes[i].nodeValue;
      else
      {
        var deep = keypad.checkForDescription(childNodes[i]);
        if( deep.length > 0)
          return deep;
      }
    }
    return "";
  }
  
  this.getAfterDescription = function(commitElem)
  {
    if(commitElem)
      return "";
    var elem = commitElem.nextSibling;
    
    if(elem != null &&  elem.nodeValue != null)
    {
      return " " + elem.nodeValue;
    }
    
    return "";
  }

  
  this.enableButton = function(elem)
  {
    keypad.removeClass(elem, "keyboard_disabled");    
  }
  
  this.disableButton = function(elem)
  {
    keypad.addClass(elem, "keyboard_disabled");        
  }

  
  this.setCommit = function(elem)
  {
    if(elem == null)
    {
      keypad.setCaretPosition(null);    
      return elem;
    }
    
    keypad.commitElem=elem;
    keypad.commitValue=keypad.commitElem.value;
    $('keypadDescription').innerHTML=keypad.makeInput();
    $("keypadCommit").style.display='';
    keypad.setCaretPosition(keypad.commitValue.length);    
    return elem;
  }
  
  this.tab = function(elem)
  {
    keypad.add("  ");
  }
  
  this.inputChanged = function(elem)
  {
    keypad.commitValue=elem.value;
    var pos = keypad.getCaretPosition();
    keypad.setCaretPosition(pos);
  }
  
  this.inputMouseUp = function(elem)
  {
    var pos = keypad.getCaretPosition();
    keypad.setCaretPosition(pos);
  }
  
  this.removeStyle = function()
  {
    if(keypad.removeStyleElem != null)
    {
      keypad.removeClass(keypad.removeStyleElem, "keyboard_button_pressed");
      keypad.removeStyleElem=null;
    }
  }
  
  this.removeClass = function(elem, className)
  {
    var split = elem.className.split(" ");
    var newClassNames = "";
    for(var i=0; i<split.length; i++)
    {
      if(split[i] != className)
        newClassNames+=split[i] + " ";
    }
    elem.className=newClassNames;
  }
  
  this.addClass = function(elem, className)
  {
    
    var elemClassName = elem.className;
    var index = elemClassName.indexOf(className);
    if( index == -1)
    {
      elemClassName=elemClassName + " " + className;
      elem.className=elemClassName;
    }
  }
  
  this.update = function(elem)
  {
    
    var d = this.def[parseInt(elem.getAttribute('index'))];
    var val = null;
    
    if(keypad.shifted && !keypad.capped && d[2] != null)
    {
      val = d[2];
    }
    else if(keypad.capped && !keypad.shifted && d[1] != null)
    {
      val = d[1];
    }
    else if(keypad.shifted && d[1] == null && d[2] != null)
    {
      val = d[2];
    }
    else 
    {
      val = d[0];
    }    
  
    keypad.add(val);
    
    if(keypad.shifted)
      keypad.shift(null);
        
  }

  
  this.add = function(val)
  {
    var v = $("keypadCommit").value;
    
    v = v.substring(0, keypad.caretPosition) + 
        val + 
        v.substring(keypad.caretPosition, v.length)
    
    keypad.commitValue=v;
    $("keypadCommit").value=v;
    
    keypad.caretPosition++;
    keypad.setCaretPosition(keypad.caretPosition);    
  }

  
  this.space = function(elem)
  { 
    keypad.add(" ");        
  }
  
  this.back = function(elem)
  {
    var val = $("keypadCommit").value;
    
    val=val.substring(0, keypad.caretPosition - 1) + val.substring(keypad.caretPosition, val.length);
    keypad.commitValue=val;   
    $("keypadCommit").value=val;
    
    keypad.caretPosition--;
    keypad.setCaretPosition(keypad.caretPosition);
        
  }
  
  this.clear = function(elem)
  {
    keypad.commitValue="";   
    $("keypadCommit").value="";
    
    keypad.caretPosition=0;
    keypad.setCaretPosition(keypad.caretPosition);
        
  }
  
  this.closeDialog = function()
  {
    hx.closeDialog(null, null); 
    keypad.commit(true);
    
    if(hx.dynamic)
    {
      //restart polling
      hx.failure = false;
      setTimeout("hx.poller()", hx.pollTimeout);        
    }
  }
  
  this.enter = function(elem)
  {
    var inputElem = $("keypadCommit");
    if(inputElem.type == 'text' || inputElem.type == 'password')
    {
      keypad.closeDialog();
    }
    else
    {
      keypad.add('\r');
    }    
  }

  this.shift = function(shiftElem)
  {
    var elem = $('keyboard');
    var divs = elem.getElementsByTagName("div");
    keypad.shifted=!keypad.shifted;        
//    var offset = 1;
//    for (var i=0; i<this.def.length; i++) 
//    {
//      if(this.def[i] == null)
//        continue;
//      
//      if(divs[i + offset].className.indexOf("arrow") > -1)
//        offset++;
//        
//      keypad.changeLetter(divs[i + offset], i);
//    }
    
    if(keypad.shifted)
    {
      $('keypad-shift1').className = $('keypad-shift1').className + " keyboard_button_selected";
      $('keypad-shift2').className = $('keypad-shift2').className + " keyboard_button_selected";
    }
    else
    {
      keypad.removeClass($('keypad-shift1'), "keyboard_button_selected");            
      keypad.removeClass($('keypad-shift2'), "keyboard_button_selected");            
    }
  }
  
  this.cap = function(capElement)
  {
    var elem = $('keyboard');
    var divs = elem.getElementsByTagName("div");
    keypad.capped=!keypad.capped;        
//    var offset = 1;
//    for (var i=0; i<this.def.length; i++) 
//    {
//      if(this.def[i] == null)
//        continue;
//      
//      if(divs[i + offset].className.indexOf("arrow") > -1)
//        offset++;
//        
//      keypad.changeLetter(divs[i + offset], i);      
//    }
    
    if(keypad.capped)
      capElement.className = capElement.className + " keyboard_button_selected";
    else
      keypad.removeClass(capElement, "keyboard_button_selected");            
    
  }
  
//  this.changeLetter = function(div, i)
//  {
//    if(keypad.shifted && !keypad.capped && this.def[i][2] != null)
//    {
//      div.innerHTML = this.def[i][2];
//    }
//    else if(keypad.capped && !keypad.shifted && this.def[i][1] != null)
//    {
//      div.innerHTML = this.def[i][1];
//    }
//    else if(keypad.shifted && this.def[i][1] == null && this.def[i][2] != null)
//    {
//      div.innerHTML = this.def[i][2];
//    }
//    else 
//    {
//      div.innerHTML = this.def[i][0];
//    }    
//  }

//positioing  
  this.moveLeft = function(elem)
  {
    if(keypad.caretPosition == 0)
    {
      keypad.setCaretPosition(null);
      return false;
    }
    
    keypad.caretPosition--;
    keypad.setCaretPosition(keypad.caretPosition);
    return true;
  }
  
  this.moveRight = function(elem)
  {
    if(keypad.caretPosition >= $("keypadCommit").value.length)
    {
      keypad.setCaretPosition(null);
      return false;
    }
    
    keypad.caretPosition++;
    keypad.setCaretPosition(keypad.caretPosition);
    
    return true;
  }
  
  this.moveUp = function(elem)
  {
    if(keypad.caretPosition == 0)
    {
      keypad.setCaretPosition(null);
      return false;
    }
      
    var inputElem = $("keypadCommit");
    if(inputElem.tagName == 'TEXTAREA')
    {
      var val = inputElem.value;
      var split = val.split("\n");
      
      var i= -1;
      var count = 0; 
      var lastCount = 0;
      
      while(count <  keypad.caretPosition)
      {
        lastCount=count;
        i++;
        count+=split[i].length + 1;        
      }
      
      if(i == 0)
        keypad.caretPosition=0;
      else
      {
        var a = keypad.caretPosition - (split[i - 1].length + 1);        
        if(lastCount < a)
        {
          lastCount--;
          a=lastCount;
        }
        keypad.caretPosition=a;        
      }      
    }
    else
    {
      keypad.caretPosition=0;
    }
    
    keypad.setCaretPosition(keypad.caretPosition);
    return true;
  }   
  
   this.moveDown = function(elem)
  {
    if(keypad.caretPosition >= $("keypadCommit").value.length)
    {
      keypad.setCaretPosition(null);
      return false;
    }
      
    var inputElem = $("keypadCommit");
    if(inputElem.tagName == 'TEXTAREA')
    {
      var val = inputElem.value;
      var split = val.split("\n");
      
      var i= -1;
      var count = 0; 
      var lastCount = 0;
      
      while(count <=  keypad.caretPosition)
      {
        lastCount=count;
        i++;
        count+=split[i].length + 1;                
      }
      
      if(i == split.length -1)
        keypad.caretPosition=$("keypadCommit").value.length;
      else
      {
        var a = keypad.caretPosition + (split[i].length + 1);        
        if(i < split.length - 2)
        {
          var nextCount = count + split[i + 1].length + 1;
          if(a > nextCount)
          {
            nextCount--;
            a=nextCount;
          }
        }
        keypad.caretPosition=a;        
      }      
    }
    else
    {
      keypad.caretPosition=$("keypadCommit").value.length;      
    }
    
    keypad.setCaretPosition(keypad.caretPosition);
    return true;
  }

  this.setCaretPosition = function(value)
  {
    if(value !=null)
      keypad.caretPosition=value;
    var input = $("keypadCommit");
    if(input == null)
      return;
    
    if(keypad.commitElem != null && keypad.commitElem.tagName == "SELECT")
      return;
    
    
    try
    {
      input.focus();  
    }
    catch(err)
    {}
    if(keypad.caretPosition < 0)
      keypad.caretPosition=0;   
    
    if(keypad.caretPosition > input.value.length)
      keypad.caretPosition=input.value.length;

      
    if (input.selectionStart) //firefox, safarri, iris
    {
      input.setSelectionRange(keypad.caretPosition, keypad.caretPosition);      
    }
    else if (input.createTextRange) //ie
    {
      var range = input.createTextRange();
      
      range.moveStart('character', -input.value.length);      
      range.moveEnd('character', 0);
      range.moveStart('character', keypad.caretPosition);      
      range.moveEnd('character', keypad.caretPosition);
      range.select();
    }    
  }
  
  this.getCaretPosition = function()
  {
    var input = $("keypadCommit");
    if(input == null)
      return;
      
    if (input.selectionStart) 
    { 
      return input.selectionStart;      
    }
    else if (input.createTextRange) 
    {
         
      try
      {
        input.focus();  
      }
      catch(err)
      {}

       var sel = document.selection.createRange();
       sel.moveStart ('character', -input.value.length);
       return sel.text.length;
    }
  }
  
  this.shifted = false;
  this.capped  = false;

////////////////////////////////////////////////////////////////
// Attributes
////////////////////////////////////////////////////////////////
  
  this.caretPosition    = 0;
  this.removeStyleElem  = null;
  this.lastButton       = null;
  this.commitElem       = null;
  this.commitValue      = "";
  this.def              = new Array();  
  
  //              lower cap   shift class
  //              a     A     A    
  this.def.push(['`',  null,  '~',  'A']);
  this.def.push(['1',  null,  '!',  'A']);  
  this.def.push(['2',  null,  '@',  'A']);
  this.def.push(['3',  null,  '#',  'A']);
  this.def.push(['4',  null,  '$',  'A']);
  this.def.push(['5',  null,  '%',  'A']);
  this.def.push(['6',  null,  '^',  'A']);
  this.def.push(['7',  null,  '&',  'A']);
  this.def.push(['8',  null,  '*',  'A']);
  this.def.push(['9',  null,  '(',  'A']);
  this.def.push(['0',  null,  ')',  'A']);
  this.def.push(['-',  null,  '_',  'A']);
  this.def.push(['=',  null,  '+',  'A']);
  this.def.push(['Backspace',  null,  null,  'G', 'keypad.back(this)']);
  
  this.def.push(null);
  
  this.def.push(['Tab',  null,  null,  'C', 'keypad.tab(this)']);
  this.def.push(['q',  'Q',  'Q',  'A']);  
  this.def.push(['w',  'W',  'W',  'A']);
  this.def.push(['e',  'E',  'E',  'A']);
  this.def.push(['r',  'R',  'R',  'A']);
  this.def.push(['t',  'T',  'T',  'A']);
  this.def.push(['y',  'Y',  'Y',  'A']);
  this.def.push(['u',  'U',  'U',  'A']);
  this.def.push(['i',  'I',  'I',  'A']);
  this.def.push(['o',  'O',  'O',  'A']);
  this.def.push(['p',  'P',  'P',  'A']);
  this.def.push(['[',  null,  '{',  'A']);
  this.def.push([']',  null,  '}',  'A']);
  this.def.push(['\\',  null,  '|',  'C']);
  
  this.def.push(null);
  
  this.def.push(['Caps Lock',  null,  null,  'D', 'keypad.cap(this)']);
  this.def.push(['a',  'A',  'A',  'A']);  
  this.def.push(['s',  'S',  'S',  'A']);
  this.def.push(['d',  'D',  'D',  'A']);
  this.def.push(['f',  'F',  'F',  'A']);
  this.def.push(['g',  'G',  'G',  'A']);
  this.def.push(['h',  'H',  'H',  'A']);
  this.def.push(['j',  'J',  'J',  'A']);
  this.def.push(['k',  'K',  'K',  'A']);
  this.def.push(['l',  'L',  'L',  'A']);
  this.def.push([';',  null,  ':',  'A']);
  this.def.push(["'",  null,  '"',  'A']);
  this.def.push(['Enter',  null,  null,  'B', 'keypad.enter(this)']);
  
  this.def.push(null);
  
  this.def.push(['Shift',  null,  null,  'E', 'keypad.shift(this)', 'keypad-shift1']);
  this.def.push(['z',  'Z',  'Z',  'A']);  
  this.def.push(['x',  'X',  'X',  'A']);
  this.def.push(['c',  'C',  'C',  'A']);
  this.def.push(['v',  'V',  'V',  'A']);
  this.def.push(['b',  'B',  'B',  'A']);
  this.def.push(['n',  'N',  'N',  'A']);
  this.def.push(['m',  'M',  'M',  'A']);
  this.def.push([',',  null,  '<',  'A']);
  this.def.push(['.',  null,  '>',  'A']);
  this.def.push(['/',  null,  '?',  'A']);
  this.def.push(["Shift",  null,  null,  'E', 'keypad.shift(this)', 'keypad-shift2']);  
  
  this.def.push(null);
  
  this.def.push(['Clear',  null,  null,  'H', 'keypad.clear(this)']);
  this.def.push(["<div class='keyboard_arrowup'></div>",  null,  null,  'A', 'keypad.moveUp(this)']);
  this.def.push(["<div class='keyboard_arrowdown'></div>",  null,  null,  'A', 'keypad.moveDown(this)']);
  this.def.push(['Space',  null,  null,  'F', 'keypad.space(this)']);
  this.def.push(["<div class='keyboard_arrowleft'></div>",  null,  null,  'A', 'keypad.moveLeft(this)']);
  this.def.push(["<div class='keyboard_arrowright'></div>",  null,  null,  'A', 'keypad.moveRight(this)']);
  this.def.push(['',  '',  '',  'I']);  
  this.def.push(['Delete',  null,  null,  'G', 'if(keypad.moveRight(null)) keypad.back(this);']);
}


