var WebAppVersion = "1.0.2";

// Create the console object if it doesn't exist (like in IE)
try { console.assert(1); } catch(e) { console = { log: function() {}, assert: function() {} } }

var DocumentIsLoaded = false;

var UsingKeyboardLayout = 0;

// QWERTY
// "~`!1@2#3$4%5^6&7*8(9)0_-+=";
// "QqWwEeRrTtYyUuIiOoPp{[}]|\\"; 
// "AaSsDdFfGgHhJjKkLl:;\"'\n"
// "ZzXxCcVvBbNnMm<,>.?/"

// Dvorak
// "~`!1@2#3$4%5^6&7*8(9)0{[}]";
// "\"'<,>.PpYyFfGgCcRrLl?/+=|\\";
// "AaOoEeUuIiDdHhTtNnSs_-\n";
// ":;QqJjKkXxBbMmWwVvZz";

// Colemak
// "~`!1@2#3$4%5^6&7*8(9)0_-+=";
// "QqWwFfPpGgJjLlUuYy:;{[}]|\\";
// "AaRrSsTtDdHhNnEeIiOo\"'\n";
// "ZzXxCcVvBbKkMm<,>.?/";

var KEY_HEIGHT = 39;
var KbCenterPositions = [];
var KbPositions = [];
// top, left, width
KbPositions[0] = [ [  0,  0, 39 ], [  0, 40, 39 ], [  0, 80, 39 ], [  0,120, 39 ], [  0,160, 39 ], [  0,200, 39 ], 
                   [  0,240, 39 ], [  0,280, 39 ], [  0,320, 39 ], [  0,360, 39 ], [  0,400, 39 ], [  0,440, 39 ], 
                   [  0,480, 39 ], [  0,520, 79 ] ];
KbPositions[1] = [ [ 40,  0, 59 ], [ 40, 60, 39 ], [ 40,100, 39 ], [ 40,140, 39 ], [ 40,180, 39 ], [ 40,220, 39 ], 
                   [ 40,260, 39 ], [ 40,300, 39 ], [ 40,340, 39 ], [ 40,380, 39 ], [ 40,420, 39 ], [ 40,460, 39 ], 
                   [ 40,500, 39 ], [ 40,540, 59 ] ];
KbPositions[2] = [ [ 80,  0, 69 ], [ 80, 70, 39 ], [ 80,110, 39 ], [ 80,150, 39 ], [ 80,190, 39 ], [ 80,230, 39 ], 
                   [ 80,270, 39 ], [ 80,310, 39 ], [ 80,350, 39 ], [ 80,390, 39 ], [ 80,430, 39 ], [ 80,470, 39 ], 
                   [ 80,510, 89 ] ];
KbPositions[3] = [ [120,  0, 89 ], [120, 90, 39 ], [120,130, 39 ], [120,170, 39 ], [120,210, 39 ], [120,250, 39 ], 
                   [120,290, 39 ], [120,330, 39 ], [120,370, 39 ], [120,410, 39 ], [120,450, 39 ], [120,490,109 ] ];
KbPositions[4] = [ [160,  0, 59 ], [160, 60, 39 ], [160,100, 59 ], [160,160,239 ], [160,400, 59 ], [160,460, 39 ], 
                   [160,500, 39 ], [160,540, 59 ] ];

var KeyIndexToRowAndCol = [];

var KI_IMAGE_ID = 1;
var KI_COUNT = 0;
var KI_KEY1 = 2;
var KI_KEY2 = 3;

var KeyInfo = [ [0, "0_0", "~", "`"],  [1, "0_1", "!", "1"],[2, "0_2", "@", "2"], [3, "0_3", "#", "3"],[4, "0_4", "$", "4"],  [5, "0_5", "%", "5"],
                [6, "0_6", "^", "6"],  [7, "0_7", "&", "7"],[8, "0_8", "*", "8"], [9, "0_9", "(", "9"],[10, "0_10", ")", "0"],[11, "0_11", "_", "-"],
                [12, "0_12", "+", "="],[13, "0_13", ""],
                
                [14, "1_0", "", "\t"], [15, "1_1", "Q", "q"],  [16, "1_2", "W", "w"],[17, "1_3", "E", "e"],[18, "1_4", "R", "r"], [19, "1_5", "T", "t"],
                [20, "1_6", "Y", "y"], [21, "1_7", "U", "u"],  [22, "1_8", "I", "i"],[23, "1_9", "O", "o"],[24, "1_10", "P", "p"],[25, "1_11", "{", "["],
                [26, "1_12", "}", "]"],[27, "1_13", "|", "\\"],
                
                [28, "2_0", ""],      [29, "2_1", "A", "a"],[30, "2_2", "S", "s"],[31, "2_3", "D", "d"],[32, "2_4", "F", "f"], [33, "2_5", "G", "g"],
                [34, "2_6", "H", "h"],[35, "2_7", "J", "j"],[36, "2_8", "K", "k"],[37, "2_9", "L", "l"],[38, "2_10", ":", ";"],[39, "2_11", "\"", "'"],
                [40, "2_12", "", "\n"],
                
                [41, "3_0", ""],      [42, "3_1", "Z", "z"],[43, "3_2", "X", "x"],[44, "3_3", "C", "c"],[45, "3_4", "V", "v"], [46, "3_5", "B", "b"],
                [47, "3_6", "N", "n"],[48, "3_7", "M", "m"],[49, "3_8", "<", ","],[50, "3_9", ">", "."],[51, "3_10", "?", "/"],[52, "3_11", ""],
                
                [53, "4_0", ""],[54, "4_1", ""],[55, "4_2", ""],[56, "4_3", "", " "],[57, "4_4", ""],[58, "4_5", ""],[59, "4_6", ""],[60, "4_7", ""]
              ];

// " " E T A O I N S R H L D C U M F P G W Y B V K X J Q Z
var FreqOrderedKeyInfoIndex = [ 56, 17, 19, 29, 23, 22, 47, 30, 18, 34, 
                                37, 31, 44, 21, 48, 32, 24, 33, 16, 20, 
                                46, 45, 36, 43, 35, 15, 42, 40, 38, 39,  
                                 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 
                                49, 50, 51, 25, 26, 27, 11, 12,  0, 13, 
                                14, 28, 41, 52, 53, 54, 55, 57, 58, 59, 60];

/* Numbers map to array positions in the KeyInfo array */

var KbMapLabel = ["QWERTY", "Dvorak (Simplified)", "Colemak", "Capewell", "Arensito (Simplified)", "Personalized Layout (see below)"];

var KbMap = [];
KbMap[0] = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];
KbMap[1] = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];
KbMap[2] = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];
KbMap[3] = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];
KbMap[4] = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];
KbMap[5] = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];

var QwertyMap = [];
QwertyMap[0] = [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13 ];
QwertyMap[1] = [ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 ];
QwertyMap[2] = [ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 ];
QwertyMap[3] = [ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52 ];
QwertyMap[4] = [ 53, 54, 55, 56, 57, 58, 59, 60 ];

var DvorakMap = [];
DvorakMap[0] = [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 25, 26, 13 ];
DvorakMap[1] = [ 14, 39, 49, 50, 24, 20, 32, 33, 44, 18, 37, 51, 12, 27 ];
DvorakMap[2] = [ 28, 29, 23, 17, 21, 22, 31, 34, 19, 47, 30, 11, 40 ];
DvorakMap[3] = [ 41, 38, 15, 35, 36, 43, 46, 48, 16, 45, 42, 52 ];
DvorakMap[4] = [ 53, 54, 55, 56, 57, 58, 59, 60 ];

var ColemakMap = [];
ColemakMap[0] = [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13 ];
ColemakMap[1] = [ 14, 15, 16, 32, 24, 33, 35, 37, 21, 20, 38, 25, 26, 27 ];
ColemakMap[2] = [ 28, 29, 18, 30, 19, 31, 34, 47, 17, 22, 23, 39, 40 ];
ColemakMap[3] = [ 41, 42, 43, 44, 45, 46, 36, 48, 49, 50, 51, 52 ];
ColemakMap[4] = [ 53, 54, 55, 56, 57, 58, 59, 60 ];

var CapewellMap = []; 
CapewellMap[0] = [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 25, 26, 13 ];
CapewellMap[1] = [ 14, 50, 20, 16, 31, 32, 35, 24, 37, 21, 15, 51, 12, 27 ];
CapewellMap[2] = [ 28, 29, 17, 18, 30, 33, 46, 19, 47, 22, 23, 11, 40 ];
CapewellMap[3] = [ 41, 43, 42, 44, 45, 38, 36, 48, 34, 49, 39, 52 ];
CapewellMap[4] = [ 53, 54, 55, 56, 57, 58, 59, 60 ];

var ArensitoMap = [];
ArensitoMap[0] = [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 51, 12, 13 ];
ArensitoMap[1] = [ 14, 15, 37, 50, 24, 39, 38, 32, 21, 31, 36, 25, 26, 27 ];
ArensitoMap[2] = [ 28, 29, 18, 17, 47, 46, 33, 30, 22, 19, 23, 11, 40 ];
ArensitoMap[3] = [ 41, 42, 16, 49, 34, 35, 45, 44, 20, 48, 43, 52 ];
ArensitoMap[4] = [ 53, 54, 55, 56, 57, 58, 59, 60 ];

var RightShiftCount = [0,0,0,0,0,0];
var LeftShiftCount = [0,0,0,0,0,0];
var NumKeysPressed = [0,0,0,0,0,0];

/* 
  This array indicates a mapping of fingers to keys
  0 = thumb
  1 = left pinky
  2 = left ring finger
  3 = left middle finger
  4 = left index finger
  5 = right index finger
  6 = right middle finger 
  7 = right ring finger
  8 = right pinky
*/
var FingerToKeys = [ [1,1,2,3,4,4,5,5,6,7,8,8,8,8],
                     [1,1,2,3,4,4,5,5,6,7,8,8,8,8],
                     [1,1,2,3,4,4,5,5,6,7,8,8,8], 
                     [1,1,2,3,4,4,5,5,6,7,8,8],
                     [4,4,4,0,5,5,5,5] ];

// one for each main layout

var FingerUsage = [ [0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0] ];
var RowUsage = [ [0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0] ];

var KeyLabelMap = [];
KeyLabelMap["13"] = "[BACKSPACE]";
KeyLabelMap["14"] = "[TAB]";
KeyLabelMap["28"] = "[CAPS LOCK]";
KeyLabelMap["40"] = "[ENTER]";
KeyLabelMap["41"] = "[LEFT SHIFT]";
KeyLabelMap["52"] = "[RIGHT SHIFT]";
KeyLabelMap["53"] = "[LEFT CTRL]";
KeyLabelMap["54"] = "[LEFT WIN KEY]";
KeyLabelMap["55"] = "[LEFT ALT]";
KeyLabelMap["56"] = "[SPACE]";
KeyLabelMap["57"] = "[RIGHT ALT]";
KeyLabelMap["58"] = "[RIGHT WIN KEY]";
KeyLabelMap["59"] = "[MENU]";
KeyLabelMap["60"] = "[RIGHT CTRL]";
/*
var ImageIdMapping = {
  "0_0":0, "0_1":1, "0_2":2, "0_3":3, "0_4":4, "0_5":5, "0_6":6, "0_7":7, "0_8":8, "0_9":9, "0_10":10,"0_11":11,"0_12":12,"0_13":13,
  "1_0":14,"1_1":15,"1_2":16,"1_3":17,"1_4":18,"1_5":19,"1_6":20,"1_7":21,"1_8":22,"1_9":23,"1_10":24,"1_11":25,"1_12":26,"1_13":27,
  "2_0":28,"2_1":29,"2_2":30,"2_3":31,"2_4":32,"2_5":33,"2_6":34,"2_7":35,"2_8":36,"2_9":37,"2_10":38,"2_11":39,"2_12":40,
  "3_0":41,"3_1":42,"3_2":43,"3_3":44,"3_4":45,"3_5":46,"3_6":47,"3_7":48,"3_8":49,"3_9":50,"3_10":51,"3_11":52,
  "4_0":53,"4_1":54,"4_2":55,"4_3":56,"4_4":57,"4_5":58,"4_6":59,"4_7":60
}*/

var RvLPlotter=[0,0,0,0,0,0];
var RvLPieLayout=[0,0,0,0,0,0];
var RowPlotter=[0,0,0,0,0,0];
var RowPieLayout=[0,0,0,0,0,0];

var TypingDistances = [];

var MlSelectedKey = "";
var MlSelectedLayout = 0;

function decimalToHex(d, padding) {
    var hex = d.toString(16);
    padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
    while (hex.length < padding) {
        hex = "0" + hex;
    }
    return hex;
}

function getCenterPositions()
{
  KbCenterPositions = [];
  for (var row = 0; row < KbPositions.length; row++)
  {
    KbCenterPositions[row] = [];
    for (var col = 0; col < KbPositions[row].length; col++)
    {
      // top, left, width, KEY_HEIGHT
      KbCenterPositions[row][col] = [getKeyCenterX(row,col), getKeyCenterY(row,col)];
    } 
  }
}

function getKeyCenterX(row, col) 
{
   return ( KbPositions[row][col][1]*2 + Math.round(KbPositions[row][col][2]/1) );
}
function getKeyCenterY(row, col) 
{
   return ( KbPositions[row][col][0]*2 + Math.round(KEY_HEIGHT/1) );
}

function loadLayoutToModify(layoutIndex)
{
  MlSelectedLayout = layoutIndex;
  document.getElementById("mlName").value = KbMapLabel[MlSelectedLayout];
  
  setupLayoutImages("ml_key_", layoutIndex, false);
}

// this is simple, and will become more complex later
function getBestKbLayout()
{
  var fingerUsagePoints = [0, 1, 2, 3, 4, 4, 3, 2, 1];
  var rowUsagePoints = [1, 3, 4, 2, 0];
  var points = [];
  var maxIndex = 0;
  
  // don't include the personal layout into the mix
  for (var l = 0; l < KbMap.length-1; l++)
  {
    points[l] = 0;
    for (var f = 0; f < FingerUsage[l].length; f++)
    {
      points[l] += (FingerUsage[l][f] * fingerUsagePoints[f]);
    }
    for (var r = 0; r < RowUsage[l].length; r++)
    {
      points[l] += (RowUsage[l][r] * rowUsagePoints[r]);
    }
    if (points[l] > points[maxIndex]) 
    {
      maxIndex = l;
    }
  }
  
  return maxIndex;
}

function resetKeyboardKeyStats()
{
  // reset stored key counts
  for (var keyIndex = 0; keyIndex < KeyInfo.length; keyIndex++) 
  {
    KeyInfo[keyIndex][KI_COUNT] = 0;
  }
  
  for (var i = 0; i < RightShiftCount.length; i++)
  {
    RightShiftCount[i] = 0;
  }
  for (var i = 0; i < LeftShiftCount.length; i++)
  {
    LeftShiftCount[i] = 0;
  }
  for (var i = 0; i < NumKeysPressed.length; i++)
  {
    NumKeysPressed[i] = 0;
  }
  
  for (var l = 0; l < KbMap.length; l++)
  {
    KeyIndexToRowAndCol[l] = [];
    for (var i = 0; i < KeyInfo.length; i++)
    {
      KeyIndexToRowAndCol[l][i] = [];
    }
  }
}

/**
 * Function: insertKey
 *
 * About: Takes in a character and then increments the associated array index representing that character.
 *
 **/
function insertKey(txt)
{
  var charInfo = getCharKeyInfo(txt);
  var keyIndex = charInfo[0];
  var rightShifts = charInfo[1];
  var leftShifts = charInfo[2];
  
  if (keyIndex != -1)
  {
    KeyInfo[ keyIndex ][0]++;
    for (l = 0; l < KbMap.length; l++)
    {
      if ( rightShifts[l] ) { RightShiftCount[l]++; }
      if ( leftShifts[l] ) { LeftShiftCount[l]++; }  
    }
  }
}

/**
 * Function: getRowAndColFromKeyIndex
 *
 * About: Returns the row and column of a key based on its layout and position in the KeyInfo array.
 *
 **/
function getRowAndColFromKeyIndex(layoutIndex, keyIndex, useLookupIndexes)
{
  if (useLookupIndexes == "undefined")
  {
    useLookupIndexes = true; 
  }
  
  // see if we've calculated this before
  if ( KeyIndexToRowAndCol[layoutIndex][keyIndex][0] && useLookupIndexes == true )
  {
    return KeyIndexToRowAndCol[layoutIndex][keyIndex];
  }

  var keyFound = false;

  for (var row = 0; row < KbMap[layoutIndex].length; row++)
  {
    for (var col = 0; col < KbMap[layoutIndex][row].length; col++)
    {
      if (KbMap[layoutIndex][row][col] == keyIndex)
      {
        KeyIndexToRowAndCol[layoutIndex][keyIndex][0] = row;
        KeyIndexToRowAndCol[layoutIndex][keyIndex][1] = col;
        keyFound = true;
        break;
      }
    }
    if (keyFound == true) {break;}
  }
  
  if (keyFound == false)
  {
    return false; 
  }
  
  return KeyIndexToRowAndCol[layoutIndex][keyIndex];
}

/**
 * Function: findLargestCharacterFrequency
 *
 * About: Returns the number of times the most typed character occurred.
 *
 **/
function findLargestCharacterFrequency(keyboardType)
{
  var largestNumTimes = 0;

  for (var i = 0; i < KeyInfo.length; i++)
  {
    if (KeyInfo[i][0] > largestNumTimes) {
      if (i != 56 ) {
        largestNumTimes = KeyInfo[i][0];
      } else {
        if ( document.getElementById("includeSpaces").checked == true ) {
          largestNumTimes = KeyInfo[i][0];  
        }
      }
    }
  }

  // check shift keys
  if (RightShiftCount[keyboardType] > largestNumTimes)
  {
    largestNumTimes = RightShiftCount[keyboardType];
  }
  if (LeftShiftCount[keyboardType] > largestNumTimes)
  {
    largestNumTimes = LeftShiftCount[keyboardType];
  }
  
  return largestNumTimes;
}


function setupLayoutImages(layoutPrefix, layoutIndex, useLookUpIndexes)
{
  if (useLookUpIndexes == 'undefined')
  {
    useLookUpIndexes = true; 
  }
  
  for (var row = 0; row < KbMap[layoutIndex].length; row++)
  {
    for (var col = 0; col < KbMap[layoutIndex][row].length; col++)
    {
      var imageId = row+"_"+col;
      document.getElementById(layoutPrefix+imageId).style.backgroundImage = "url(./" + WebAppVersion + "/images/keys/qwerty_600_" + KeyInfo[ KbMap[layoutIndex][row][col] ][KI_IMAGE_ID] + getImageFileExtension() + ")";
    } 
  }
  
}

function hotSpotMouseOver (imageId) 
{
  // find key index based on image Id
    
  var layoutIndex = document.getElementById('hotSpotLayoutSelector').selectedIndex;
  
  //var kIndex = ImageIdMapping[imageId];
  var pos = imageId.split("_");
  var kIndex = KbMap[layoutIndex][pos[0]][pos[1]];
  
  if (kIndex == 41) {
    numTimesPressedStr = LeftShiftCount[layoutIndex] + " Times";
  } else if (kIndex == 52) {
    numTimesPressedStr = RightShiftCount[layoutIndex] + " Times";
  } else {
    numTimesPressedStr = KeyInfo[kIndex][KI_COUNT] + " Times";
  }
  
  var keyLabel = "";
  if (kIndex in KeyLabelMap)
  {
    keyLabel = KeyLabelMap[kIndex];
  } else {
    keyLabel = KeyInfo[kIndex].slice(KI_KEY1).join(" ");
  }
  
  // alter the label for certain keys

  document.getElementById("hs_statsKeyPressed").innerHTML = "<strong>{</strong>" + keyLabel + "<strong>}</strong>";
  document.getElementById("hs_statsTimesPressed").innerHTML = numTimesPressedStr;
  
  highlightKey("hs_key_", imageId);
}

function hotSpotMouseOut(imageId)
{
  document.getElementById("hs_statsKeyPressed").innerHTML = "";
  document.getElementById("hs_statsTimesPressed").innerHTML = "";
  
  unHighlightKey("hs_key_", imageId);
}

function isValidMlKey(imageId)
{
  if (imageId in {"4_0":1,"4_1":1,"4_2":1,"4_3":1,"4_4":1,"4_5":1,"4_6":1,"4_7":1,"3_0":1,"3_11":1})
  {
    return false; 
  } else {
    return true; 
  }
}

function mlMouseOver(imageId)
{
  if (!isValidMlKey(imageId))
  {
    return; 
  }
  
  highlightKey("ml_key_", imageId);
}

function mlMouseOut(imageId)
{
  unHighlightKey("ml_key_", imageId);
}

function highlightKey(keyPrefix, imageId)
{
  // get width, minus 2 for border size
  var eId = keyPrefix + imageId;
  var theWidth = document.getElementById(eId).offsetWidth - 4;
  var theHeight = document.getElementById(eId).offsetHeight - 4;
  document.getElementById(eId).style.width = theWidth + "px";
  document.getElementById(eId).style.height = theHeight + "px";
  document.getElementById(eId).style.borderWidth = "2px";
  document.getElementById(eId).style.backgroundPosition = "-1px -1px";
}

function unHighlightKey(keyPrefix, imageId)
{
  // minus 4 for border size
  var theWidth = document.getElementById(keyPrefix + imageId).offsetWidth-4;
  theWidth = theWidth + 2;
  var theHeight = document.getElementById(keyPrefix + imageId).offsetHeight-4;
  theHeight = theHeight + 2;
  document.getElementById(keyPrefix + imageId).style.width = theWidth + "px";
  document.getElementById(keyPrefix + imageId).style.height = theHeight + "px";
  
  document.getElementById(keyPrefix + imageId).style.borderWidth = "1px";
  document.getElementById(keyPrefix + imageId).style.backgroundPosition = "0px 0px"; 
}

function mlSwitchKeys(imageId)
{
  if (!isValidMlKey(imageId))
  {
    return; 
  }
  
  var keyPrefix = "ml_key_";
  
  console.log("MlSelectedLayout = " + MlSelectedLayout);
  console.log("MlSelectedKey = " + MlSelectedKey);
  console.log("imageId = " + imageId);
  
  if ( MlSelectedKey == "" ) 
  {
    MlSelectedKey = imageId;
    document.getElementById(keyPrefix + MlSelectedKey).style.backgroundColor = "RGB(255,255,51)";//"RGB(66, 111, 217)";
  }
  else
  {
    document.getElementById(keyPrefix + MlSelectedKey).style.backgroundColor = "#fff";
    
    // change key places
    var pos1 = MlSelectedKey.split("_");
    var pos2 = imageId.split("_");
    
    console.log("pos1[0] = " + pos1[0]);
    console.log("pos1[1] = " + pos1[1]);
    console.log("pos2[0] = " + pos2[0]);
    console.log("pos2[1] = " + pos2[1]);
    
    var index1 = KbMap[MlSelectedLayout][ pos1[0] ][ pos1[1] ];
    var index2 = KbMap[MlSelectedLayout][ pos2[0] ][ pos2[1] ];
    
    console.log("index1 = " + index1);
    console.log("index2 = " + index2);
    
    KbMap[MlSelectedLayout][ pos1[0] ][ pos1[1] ] = index2;
    KbMap[MlSelectedLayout][ pos2[0] ][ pos2[1] ] = index1;
    
    loadLayoutToModify(MlSelectedLayout);
    
    // swap the images
    var imageId1 = pos1[0]+"_"+pos1[1];
    var imageId2 = pos2[0]+"_"+pos2[1];
    document.getElementById("ml_key_"+imageId1).style.backgroundImage = "url(./" + WebAppVersion + "/images/keys/qwerty_600_" + KeyInfo[ KbMap[MlSelectedLayout][pos1[0]][pos1[1]] ][KI_IMAGE_ID] + getImageFileExtension() + ")";
    document.getElementById("ml_key_"+imageId2).style.backgroundImage = "url(./" + WebAppVersion + "/images/keys/qwerty_600_" + KeyInfo[ KbMap[MlSelectedLayout][pos2[0]][pos2[1]] ][KI_IMAGE_ID] + getImageFileExtension() + ")";
    
    setTimeout(function() {yellowFlashSwitchedKeys("ml_key_"+imageId1,"ml_key_"+imageId2, 100);}, 50);
    
    // reset selected key
    MlSelectedKey = ""; 
  }
}

function yellowFlashSwitchedKeys(id1, id2, fadeDepth) 
{
  var invertedRed = 0;
  var invertedGreen = 0;
  var invertedBlue = 204;
  
  var val = Math.round(( fadeDepth / 100) * 255);
  var redVal = 255 - Math.round( val * (invertedRed/255));
  var greenVal = 255 - Math.round( val * (invertedGreen/255));
  var blueVal = 255 - Math.round( val * (invertedBlue/255));
  
  document.getElementById(id1).style.backgroundColor = "#" + decimalToHex(redVal) + decimalToHex(greenVal) + decimalToHex(blueVal);
  document.getElementById(id2).style.backgroundColor = "#" + decimalToHex(redVal) + decimalToHex(greenVal) + decimalToHex(blueVal);
  
  fadeDepth = fadeDepth - 20;
  
  if (fadeDepth < 0)
  {
    document.getElementById(id1).style.backgroundColor = "#ffffff";
    document.getElementById(id2).style.backgroundColor = "#ffffff";
  } 
  else
  {
    setTimeout(function() {yellowFlashSwitchedKeys(id1, id2, fadeDepth);}, 50);
  }
}

function updateMlName(newName)
{
  KbMapLabel[MlSelectedLayout] = newName;
}

function updateMlFromList(layoutName)
{
  var layoutArray;
  
  if (layoutName == "qwerty") {
    layoutArray = QwertyMap;
  } else if (layoutName == "dvorak") {
    layoutArray = DvorakMap;
  } else if (layoutName == "colemak") {
    layoutArray = ColemakMap; 
  } else if (layoutName == "capewell") {
    layoutArray = CapewellMap; 
  } else if (layoutName == "arensito") {
    layoutArray = ArensitoMap; 
  }
  
  loadLayoutFromArray(MlSelectedLayout, layoutArray);
}

function loadLayoutFromArray(l, kMap)
{
  for (var row = 0; row < kMap.length; row++)
  {
    for (var col = 0; col < kMap[row].length; col++)
    {
      KbMap[l][row][col] = kMap[row][col]; 
    } 
  } 
  loadLayoutToModify(l);
}

function getMlId()
{
  var mlId = "";
  for (var row = 0; row < KbMap[MlSelectedLayout].length; row++)
  {
    for (var col = 0; col < KbMap[MlSelectedLayout][row].length; col++)
    {
      mlId = mlId + KbMap[MlSelectedLayout][row][col] + ","; 
    } 
  }
  mlId = mlId.substring(0,mlId.length-1);
  document.getElementById("mlTextId").value = mlId;
}

function loadMlFromId()
{
  var inputId = document.getElementById("mlTextLoadId").value;
  var inputIndexes = inputId.split(",");
  
  if (inputIndexes.length != 61) {alert("Error In Input");return;}
  
  var testArray = [];
  for (var i = 0; i <= 60; i++)
  {
    testArray[i] = false; 
  }
  
  for (var i = 0; i <= 60; i++)
  {
    testArray[ inputIndexes[i] ] = true;
  }
  
  // ensure each index was filled in
  
  var testResult = true;
  for (var i = 0; i <= 60; i++)
  {
    testResult = testResult && testArray[i];
  }
  
  if (!testResult) {return;}
  
  // ensure certain indexes
  
  for (var i = 52; i <= 60; i++)
  {
    if ( inputIndexes[i] != i ) {alert("Error In Input");return;}
  }
  if ( inputIndexes[ 41 ] != 41 ) {alert("Error In Input");return;}
  
  // Otherwise, fill in and enjoy
  
  var index = 0;
  
  for (var row = 0; row < KbMap[MlSelectedLayout].length; row++)
  {
    for (var col = 0; col < KbMap[MlSelectedLayout][row].length; col++)
    {
      KbMap[MlSelectedLayout][row][col] = inputIndexes[ index ] 
      index++;
    } 
  }
  
  setupLayoutImages("ml_key_", MlSelectedLayout, false);
}

/**
 * Function: colorTheKeyboard
 *
 * About: Colors in the visualization.
 *
 **/
function colorTheKeyboard()
{
  var layoutIndex = document.getElementById('hotSpotLayoutSelector').selectedIndex;
  
  // setup layout based on layoutIndex
  
  setupLayoutImages("hs_key_", layoutIndex);
  
  // get max value
  
  var maxRed = 38;
  var maxGreen = 71;
  var maxBlue = 160;
  var invertedRed = 255 - maxRed;
  var invertedGreen = 255 - maxGreen;
  var invertedBlue = 255 - maxBlue;
  
  var maxCount = findLargestCharacterFrequency(layoutIndex);
  
  // loop through keys and assign color
  
  for (var row = 0; row < KbMap[layoutIndex].length; row++)
  {
    for (var col = 0; col < KbMap[layoutIndex][row].length; col++)
    {
      var kIndex = KbMap[layoutIndex][row][col];
      var count = 0;
      
      if (kIndex == 41) {
        count = LeftShiftCount[layoutIndex];
      } else if (kIndex == 52) {
        count = RightShiftCount[layoutIndex];
      } else {
        count = KeyInfo[ kIndex ][0];
      }

      var val = Math.round(( count / maxCount) * 255);
      redVal = 255 - Math.round( val * (invertedRed/255));
      greenVal = 255 - Math.round( val * (invertedGreen/255));
      blueVal = 255 - Math.round( val * (invertedBlue/255));
      
      if ( document.getElementById("includeSpaces").checked == false && kIndex == 56 ) {
        //"hs_key_" + KeyInfo[ kIndex ][KI_IMAGE_ID]
        document.getElementById("hs_key_" + row+"_"+col).style.backgroundColor = "#ffffff";
      } else {
        document.getElementById("hs_key_" + row+"_"+col).style.backgroundColor = "#" + decimalToHex(redVal) + decimalToHex(greenVal) + decimalToHex(blueVal);
      }
    } 
  }
}

// note to self: re-write this with a better sorting algorithm later
function sortKeys(keyIndexes)
{
  var retIndexes = [];
  var retValues = [];
  for (var k = 0; k < keyIndexes.length; k++)
  {
    var kIndex = keyIndexes[k];
    var kVal = KeyInfo[ kIndex ][KI_COUNT];
    var insertIndex = retIndexes.length;

    for (var i = 0; i < retIndexes.length; i++)
    {
      if (kVal > retValues[i])
      {
        insertIndex = i;
        break;
      }
    }
  
    // shift existing entries
    var len = retIndexes.length;
    for (i = len; i > insertIndex; i--)
    {
      retIndexes[i] = retIndexes[i-1];
      retValues[i] = retValues[i-1];
    }
    
    // add new item
    retValues[insertIndex] = kVal;
    retIndexes[insertIndex] = kIndex;
  }
  
  return retIndexes;
}

function generatePersonalLayout()
{
  for (var i = 0; i < KeyInfo.length; i++)
  {
    KeyIndexToRowAndCol[5][i] = [];
  }
  
  var topPositions = [  [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 34,  -1],
                        [ -1, 25, 15, 13, 11, 16, 19, 10, 12, 14, 24, 29, 30, -1],
                        [ -1,  7,  5,  3,  1,  9,  8,  0,  2,  4,  6, 20, -1], 
                        [ -1, 32, 28, 22, 18, 23, 17, 21, 26, 27, 31, -1],
                        [ -1, -1, -1, -1, -1, -1, -1, -1] ];
  var kIndexes = [];
  var index = 0;

  for (var row = 0; row < topPositions.length; row++)
  {
    for (var col = 0; col < topPositions[row].length; col++)
    {
      if ( topPositions[row][col] != -1) 
      {
        kIndexes[index] = QwertyMap[row][col];
        index++;
      }
    }
  }

  var keyPos = sortKeys(kIndexes);
  
  for (var row = 0; row < topPositions.length; row++)
  {
    for (var col = 0; col < topPositions[row].length; col++)
    {
      if ( topPositions[row][col] == -1)  {
        KbMap[5][row][col] = QwertyMap[row][col];
      } else {
        KbMap[5][row][col] = keyPos[ topPositions[row][col] ];
      }
    }
  }
  setupLayoutImages("pl_key_", 5);
}

function getCharKeyInfo(inputChar)
{
  var keyFound = false;
  var retIndex = -1;
  var retRightShift = [];
  var retLeftShift = [];
  
  for (var k = 0; k < KeyInfo.length; k++) 
  {
    var keyIndex = FreqOrderedKeyInfoIndex[k];
    for (var letterIndex = KI_KEY1; letterIndex < KeyInfo[keyIndex].length; letterIndex++)
    {
      if (inputChar == KeyInfo[keyIndex][letterIndex])
      {
        retIndex = keyIndex;
         
        // Figure out if a shift key was pressed
        if (letterIndex == KI_KEY1) 
        {
          for (l = 0; l < KbMap.length; l++)
          {
            var pos = getRowAndColFromKeyIndex(l, keyIndex);
            retRightShift[l] = false;
            retLeftShift[l] = false;
            
            if (pos)
            {
              if (FingerToKeys[pos[0]][pos[1]] <= 4) {
                retRightShift[l] = true;
              } else {
                retLeftShift[l] = true;  
              }
            }
          }
        }
        
        keyFound = true
        break;
      }
    }
    if (keyFound == true) {break;}
  }
  
  return [retIndex, retRightShift, retLeftShift];
}

//console.log("KbCenterPositions[row1][col1][0] = " + KbCenterPositions[row1][col1][0] );
//console.log("KbCenterPositions[row1][col1][1] = " + KbCenterPositions[row1][col1][1] );
//console.log("KbCenterPositions[row2][col2][0] = " + KbCenterPositions[row2][col2][0] );
//console.log("KbCenterPositions[row2][col2][1] = " + KbCenterPositions[row2][col2][1] );

function calculateDistanceBetweenKeys(row1, col1, row2, col2)
{
  var xDiff = KbCenterPositions[row1][col1][0] - KbCenterPositions[row2][col2][0];
  var yDiff = KbCenterPositions[row1][col1][1] - KbCenterPositions[row2][col2][1];
  return Math.sqrt((xDiff * xDiff) + (yDiff * yDiff));
}

function calculateTypingDistances(inputTxt)
{
  var prevFinger = []; /* 0 - 9 */
  var prevRow = [];
  var prevCol = [];
  var distanceTraveled = [];
  var distanceTraveledMemory = [];
  
  // finger home keys
  var fingerHomeKeys = [];
  fingerHomeKeys[0] = [4,3];
  fingerHomeKeys[1] = [2,1];
  fingerHomeKeys[2] = [2,2];
  fingerHomeKeys[3] = [2,3];
  fingerHomeKeys[4] = [2,4];
  fingerHomeKeys[5] = [2,7];
  fingerHomeKeys[6] = [2,8];
  fingerHomeKeys[7] = [2,9];
  fingerHomeKeys[8] = [2,10];
  
  // set up "previous" arrays
  for (var l = 0; l < KbMap.length; l++)
  {
    prevFinger[l] = -1;
    prevRow[l] = -1;
    prevCol[l] = -1;
    distanceTraveled[l] = 0;
    distanceTraveledMemory[l] = 0;
  }
    
  for (var i = 0; i < inputTxt.length; i++)
  {
    var charInfo = getCharKeyInfo( inputTxt.substring(i,i+1) ); 
    var keyIndex = charInfo[0];
    var rightShifts = charInfo[1];
    var leftShifts = charInfo[2];
  
    if (keyIndex == -1)
    {
      continue; 
    }
  
    for (var l = 0; l < KbMap.length; l++)
    {
      var pos = getRowAndColFromKeyIndex(l, keyIndex);
      
      if (!pos)
      {
        continue; 
      }
      
      var row = pos[0];
      var col = pos[1];
      var finger = FingerToKeys[row][col];
      
      // If the finger isn't the same one as used previously, return the previously
      // used finger to its home row position (unless its the thumb or an invalid finger)
      if (finger != prevFinger[l] && prevFinger[l] > 0)
      {
        if ( distanceTraveledMemory[l] )
        {
          distanceTraveled[l] += distanceTraveledMemory[l];
        } 
        else
        {
          distanceTraveled[l] += calculateDistanceBetweenKeys( prevRow[l], prevCol[l], fingerHomeKeys[prevFinger[l]][0], fingerHomeKeys[prevFinger[l]][1]);
        }
      }

      // if the finger is the thumb (finger == 0), don't bother with any calucations, as the distance is 0      
      if (finger != 0)
      {
        if (finger == prevFinger[l])
        {
          if ( prevRow[l] != row || prevCol[l] != col )
          {
            distanceTraveled[l] += calculateDistanceBetweenKeys( prevRow[l], prevCol[l], row, col);
            
            // scramble memory, as its no longer good
            distanceTraveledMemory[l] = 0;
          }
        }
        else
        {
          distanceTraveledMemory[l] = calculateDistanceBetweenKeys( fingerHomeKeys[finger][0], fingerHomeKeys[finger][1], row, col );
          distanceTraveled[l] += distanceTraveledMemory[l];
        }
      }
      
      // set up previous values
      prevFinger[l] = finger;
      prevRow[l] = row;
      prevCol[l] = col;
    }
  }
  
  // normalize for later conversions
  var keyDist = calculateDistanceBetweenKeys( 2, 4, 2, 5);
  for (var l = 0; l < KbMap.length; l++)
  {
    distanceTraveled[l] = distanceTraveled[l] / keyDist;
  }
  
  return distanceTraveled;
}

function updateTypingDistances(distType)
{
  console.log("TypingDistances[0] = " + TypingDistances[0]);
  console.log("TypingDistances[1] = " + TypingDistances[1]);
  console.log("TypingDistances[2] = " + TypingDistances[2]);
  console.log("TypingDistances[3] = " + TypingDistances[3]);
  console.log("TypingDistances[4] = " + TypingDistances[4]);
  console.log("TypingDistances[5] = " + TypingDistances[5]);
  
  for (var l = 0; l < KbMap.length; l++)
  {
    document.getElementById("labelDistKb" + l + "Name").innerHTML = KbMapLabel[l];
    var numMeters = (TypingDistances[l] * 0.0019);
    var numFeet = numMeters * 3.2808399;
    var numMiles = numMeters * 0.000621371192;
    var theDist = 0;
    
    if (distType == 'feet')
    {
      document.getElementById("distTdDistHeader").innerHTML = "Feet";
      theDist = numFeet.toFixed(4);
    }
    else if (distType == 'miles')
    {
      document.getElementById("distTdDistHeader").innerHTML = "Miles";
      theDist = numMiles.toFixed(4);
    }
    else
    {
      // METERS IS THE DEFAULT
      document.getElementById("distTdDistHeader").innerHTML = "Meters";
      theDist = numMeters.toFixed(4);
    }
    
    document.getElementById("labelDistKb" + l + "Dist").innerHTML = theDist ;
  }
}

function resetReport()
{
  //document.getElementById("inputContainer").style.display = "block";
  //document.getElementById("resultContainer").style.display = "none";
}

/**
 * Function: generateReport
 *
 * About: Generates the analysis report on the entered text.
 *
 **/
function generateReport()
{
  if (document.getElementById("txtInput").value == "")
  {
    alert("Please enter some text to analyze.");
    return; 
  }
  
  if (DocumentIsLoaded == false)
  {
    alert("Page is still initializing values.");
    return; 
  }
  
  // Clear out the old information
  resetKeyboardKeyStats();
  
  var inputTxt = document.getElementById("txtInput").value;
  
  if (inputTxt == "")
  {
    return; 
  }
  
  // Count how many of each letter there are
  var keyCount = 0;
  for (var i = 0; i < inputTxt.length; i++)
  {
    insertKey( inputTxt.substring(i,i+1) );
    keyCount++;
  }
  NumKeysPressed[0] = keyCount + LeftShiftCount[0] + RightShiftCount[0];
  NumKeysPressed[1] = keyCount + LeftShiftCount[1] + RightShiftCount[1];
  NumKeysPressed[2] = keyCount + LeftShiftCount[2] + RightShiftCount[2];
  NumKeysPressed[3] = keyCount + LeftShiftCount[3] + RightShiftCount[3];
  NumKeysPressed[4] = keyCount + LeftShiftCount[4] + RightShiftCount[4];
  NumKeysPressed[5] = keyCount + LeftShiftCount[5] + RightShiftCount[5];
  
  generatePersonalLayout();
  TypingDistances = calculateTypingDistances(inputTxt);
  var distType = "meters";
  
  if (document.getElementById("distTypeFeet").checked == true)
  {
    distType = "feet";
  }
  else if (document.getElementById("distTypeMiles").checked == true)
  {
    distType = "miles";
  }
  
  updateTypingDistances(distType);
  
  // update combo box for hot spot visualization
  
  for (var i = 0; i < KbMapLabel.length; i++)
  {
    document.getElementById("hotSpotLayoutSelector").options[i].text = KbMapLabel[i];
  }

  fadeOutInput(100);
  setTimeout( function() {
    colorTheKeyboard();
    collectFingerAndRowUsageData();
    updateStatisticsCharts();
  
    document.getElementById("bestLayout").innerHTML = "<strong>" + KbMapLabel[getBestKbLayout()] + "</strong>";
  }, 1000);
  //fadeOutInput(100); 
}

function updateStatisticsCharts() 
{
  updateRvLCharts();
  updateRowCharts();
}

function updateRvLCharts()
{
  var labelArray = ["Thumbs","Left Pinky","Left Ring","Left Middle","Left Index","Right Index","Right Middle","Right Ring","Right Pinky"];
  var xTickArr = [];
  var index = 0;
  for (var i = 1; i < labelArray.length; i++)
  {
    if ( document.getElementById("includeFinger"+i).checked == true )
    {
      xTickArr[index] = {v:index, label:labelArray[i]}; 
      index++;
    }
  }

  if ( document.getElementById("includeFinger0").checked == true )
  {
    xTickArr[index] = {v:index, label:labelArray[0]}; 
  }
  
  // color scheme
  var colorScheme = [];
  colorScheme[0] = MochiKit.Color.Color.fromHexString("#D6DFEF");
  colorScheme[1] = MochiKit.Color.Color.fromHexString("#8DA7D2");
  colorScheme[2] = MochiKit.Color.Color.fromHexString("#476FB2");
  colorScheme[3] = MochiKit.Color.Color.fromHexString("#2A4269");
  
  colorScheme[4] = MochiKit.Color.Color.fromHexString("#EFD6DF");
  colorScheme[5] = MochiKit.Color.Color.fromHexString("#D28DA7");
  colorScheme[6] = MochiKit.Color.Color.fromHexString("#B2476F");
  colorScheme[7] = MochiKit.Color.Color.fromHexString("#692A42");
  
  colorScheme[8] = MochiKit.Color.Color.fromHexString("#888888");
  
  var rvlOptions = {
     "IECanvasHTC": "/plotkit/iecanvas.htc",
     "colorScheme": colorScheme,
     "padding": {left: 10, right: 10, top: 10, bottom: 10},
     "xTicks": xTickArr,
     "drawYAxis": false,
     "axisLabelWidth": 40
  };
  var canvasOptions = {
    "axisLabelWidth": 40,
    "colorScheme": colorScheme,
    "axisLabelFontSize": 9,
    "pieRadius": 0.4,
    "padding": {left: 30, right: 30, top: 5, bottom: 10}
  };
  
  for (var l = 0; l < KbMap.length; l++)
  {
    var thumbs =      FingerUsage[l][0];
    var leftPinky =   FingerUsage[l][1];
    var leftRing =    FingerUsage[l][2];
    var leftMiddle =  FingerUsage[l][3];
    var leftIndex =   FingerUsage[l][4];
    var rightIndex =  FingerUsage[l][5];
    var rightMiddle = FingerUsage[l][6];
    var rightRing =   FingerUsage[l][7];
    var rightPinky =  FingerUsage[l][8];

    var dataSetArr = [];
    var index = 0;
    for (var i = 1; i < FingerUsage[l].length; i++)
    {
      if ( document.getElementById("includeFinger"+i).checked == true )
      {
        dataSetArr[index] = [index, FingerUsage[l][i]]; 
        index++;
      }
    }
    
    if ( document.getElementById("includeFinger0").checked == true ) {
      dataSetArr[index] = [index, FingerUsage[l][0]]; 
    }
    
    RvLPieLayout[l] = new PlotKit.Layout("pie", rvlOptions);
    RvLPieLayout[l].addDataset("sqrt", dataSetArr);
    RvLPieLayout[l].evaluate();
    var canvas = MochiKit.DOM.getElement("rvlGraph"+l);
    try {
      RvLPlotter[l].clear();
    } catch (err) {}
    RvLPlotter[l] = new PlotKit.SweetCanvasRenderer(canvas, RvLPieLayout[l], canvasOptions);
    RvLPlotter[l].render();
    
    document.getElementById("rvlChartLabel"+l).innerHTML = KbMapLabel[l];
  }
}

function updateRowCharts()
{
  var labelArray = ["Number Row","Top Row","Home Row","Bottom Row","Space Bar"];
  var xTickArr = [];
  var index = 0;
  for (var i = 0; i < labelArray.length; i++)
  {
    if ( document.getElementById("includeRow"+i).checked == true )
    {
      xTickArr[index] = {v:index, label:labelArray[i]}; 
      index++;
    }
  }
  
  var rowOptions = {
     "IECanvasHTC": "/plotkit/iecanvas.htc",
     "colorScheme": PlotKit.Base.palette(PlotKit.Base.baseColors()[0]),
     "padding": {left: 10, right: 10, top: 10, bottom: 10},
     "xTicks": xTickArr,
     "drawYAxis": false,
     "axisLabelWidth": 40
  };
  var canvasOptions = {
    "axisLabelWidth": 45,
    "axisLabelFontSize": 9,
    "pieRadius": 0.4
  };
  
  for (var l = 0; l < KbMap.length; l++)
  {
    var dataSetArr = [];
    var index = 0;
    for (var i = 0; i < RowUsage[l].length; i++)
    {
      if ( document.getElementById("includeRow"+i).checked == true )
      {
        dataSetArr[index] = [index, RowUsage[l][i]]; 
        index++;
      }
    }
    
    RowPieLayout[l] = new PlotKit.Layout("pie", rowOptions);
    RowPieLayout[l].addDataset("sqrt", dataSetArr);
    RowPieLayout[l].evaluate();
    var canvas = MochiKit.DOM.getElement("rowGraph"+l);
    try {
      RowPlotter[l].clear();
    } catch (err) {}
    RowPlotter[l] = new PlotKit.SweetCanvasRenderer(canvas, RowPieLayout[l], canvasOptions);
    RowPlotter[l].render();
    
    document.getElementById("rowChartLabel"+l).innerHTML = KbMapLabel[l];
  }
}

function collectFingerAndRowUsageData() 
{
  // clear out old data
  for (var l = 0; l < FingerUsage.length; l++)
  {
    for (var f = 0; f < FingerUsage[l].length; f++)
    {
      FingerUsage[l][f] = 0; 
    } 
  }
  for (var l = 0; l < RowUsage.length; l++)
  {
    for (var r = 0; r < RowUsage[l].length; r++)
    {
      RowUsage[l][r] = 0; 
    } 
  }
  
  // collect new data  
  for (var l = 0; l < KbMap.length; l++)
  {
    for (var row = 0; row < KbMap[l].length; row++)
    {
      for (var col = 0; col < KbMap[l][row].length; col++)
      {
        var kIndex = KbMap[l][row][col];
        var finger = FingerToKeys[row][col];

        FingerUsage[l][finger] = FingerUsage[l][finger] + KeyInfo[kIndex][KI_COUNT];
        RowUsage[l][row] = RowUsage[l][row] + KeyInfo[kIndex][KI_COUNT];
      } 
    }
  }
}

function getImageFileExtension()
{
  // FOR IE6 WE MUST USE GIF IMAGES INSTEAD OF PNG IMAGES
  var imageExt = ".png";
  var browser=navigator.appName;
  if (browser == "Microsoft Internet Explorer")
  {
    var IE6 = false /*@cc_on || @_jscript_version < 5.7 @*/;

    if (IE6 == true)
    {
      imageExt = ".gif";
    }
  }
  return imageExt; 
}

window.onload = function() 
{
  document.getElementById('hotSpotLayoutSelector').selectedIndex = 0;
  
  // set up the KbMap array
  for (var row = 0; row < KbMap[0].length; row++)
  {
    for (var col = 0; col < KbMap[0][row].length; col++) 
    {
      KbMap[0][row][col] = QwertyMap[row][col];
      KbMap[1][row][col] = DvorakMap[row][col];
      KbMap[2][row][col] = ColemakMap[row][col];
      KbMap[3][row][col] = CapewellMap[row][col];
      KbMap[4][row][col] = ArensitoMap[row][col];
      KbMap[5][row][col] = QwertyMap[row][col];
    }
  }
  
  /* SET OUR ARRAY VALUES */  
  resetKeyboardKeyStats();
  
  getCenterPositions();
  
  // Set up keyboard positions
  for (var row = 0; row < KbMap[0].length; row++)
  {
    for (var col = 0; col < KbMap[0][row].length; col++)
    {
      document.getElementById("hs_key_"+row+"_"+col).style.top = KbPositions[row][col][0] + "px";
      document.getElementById("hs_key_"+row+"_"+col).style.left = KbPositions[row][col][1] + "px";
      document.getElementById("hs_key_"+row+"_"+col).style.width = KbPositions[row][col][2] + "px";
      document.getElementById("hs_key_"+row+"_"+col).style.height = KEY_HEIGHT + "px";
      document.getElementById("hs_key_"+row+"_"+col).style.backgroundImage = "url(./" + WebAppVersion + "/images/keys/qwerty_600_" + KeyInfo[ KbMap[0][row][col] ][KI_IMAGE_ID] + getImageFileExtension() + ")";

      document.getElementById("pl_key_"+row+"_"+col).style.backgroundColor = "#ffffff";
      document.getElementById("pl_key_"+row+"_"+col).style.top = KbPositions[row][col][0] + "px";
      document.getElementById("pl_key_"+row+"_"+col).style.left = KbPositions[row][col][1] + "px";
      document.getElementById("pl_key_"+row+"_"+col).style.width = KbPositions[row][col][2] + "px";
      document.getElementById("pl_key_"+row+"_"+col).style.height = KEY_HEIGHT + "px";
      document.getElementById("pl_key_"+row+"_"+col).style.backgroundImage = "url(./" + WebAppVersion + "/images/keys/qwerty_600_" + KeyInfo[ KbMap[0][row][col] ][KI_IMAGE_ID] + getImageFileExtension() + ")";

      document.getElementById("ml_key_"+row+"_"+col).style.top = KbPositions[row][col][0] + "px";
      document.getElementById("ml_key_"+row+"_"+col).style.left = KbPositions[row][col][1] + "px";
      document.getElementById("ml_key_"+row+"_"+col).style.width = KbPositions[row][col][2] + "px";
      document.getElementById("ml_key_"+row+"_"+col).style.height = KEY_HEIGHT + "px";
      document.getElementById("ml_key_"+row+"_"+col).style.backgroundColor = "#ffffff";
      document.getElementById("ml_key_"+row+"_"+col).style.backgroundImage = "url(./" + WebAppVersion + "/images/keys/qwerty_600_" + KeyInfo[ KbMap[0][row][col] ][KI_IMAGE_ID] + getImageFileExtension() + ")";
    } 
  }

  

  document.getElementById("loading").className = "loadingInvisible";
  document.getElementById("loadingMessage").className = "loadingInvisible";
  
  var ii = 0;
  var inputContainers = [];
  inputContainers[ii++] = "inputContainer";
  inputContainers[ii++] = "inputTabs";
  setFadeInputContainers(inputContainers);
  
  var jj = 0;
  var outputContainers = [];
  outputContainers[jj++] = "resultContainer";
  outputContainers[jj++] = "hsKeyboardContainer";
  outputContainers[jj++] = "plKeyboardContainer";
  
  var rr = 0;
  for (rr = 0; rr < KeyInfo.length; rr++)
  {
    outputContainers[jj++] = "hs_key_"+KeyInfo[rr][KI_IMAGE_ID];
    outputContainers[jj++] = "pl_key_"+KeyInfo[rr][KI_IMAGE_ID];
  }
  
  setFadeOutputContainers(outputContainers);
  
  DocumentIsLoaded = true;
}

function drawGraph() 
{
  var canvas = null;
  for (var l = 0; l < KbMap.length; l++)
  {
    canvas = MochiKit.DOM.getElement("rvlGraph"+l);
    RvLPieLayout[l] = new PlotKit.Layout("pie", {});
    RvLPlotter[l] = new PlotKit.SweetCanvasRenderer(canvas, RvLPieLayout[l], {});
    
    canvas = MochiKit.DOM.getElement("rowGraph"+l);
    RowPieLayout[l] = new PlotKit.Layout("pie", {});
    RowPlotter[l] = new PlotKit.SweetCanvasRenderer(canvas, RowPieLayout[l], {});  
  }
}
MochiKit.DOM.addLoadEvent(drawGraph);
