﻿var crossrefsorted = false;
var fargs;
var lastGuess = 0;
var guessPhase= 0;  // 0: guess  1: show answer
var guessMode = 0;  // 0: inactive  1: normal (play)  2: replay  3: series
var guessTime = 12;      // in seconds
var answerTime = 8;
var replayGuessTime = 3;
var replayAnswerTime = 9;
var seriesGuessTime = 3;
var seriesAnswerTime = 9;

var guessStack = new Array;
var guessTotal = 0;
var guessIndex = 0;

var dbPinyin = new Object();

var guessingCompound = -1;
var guessingPhonetic = 0;

var squote = "'";
var dquote = '"';
var sp   = ' ';
var nbsp = '&nbsp;';
var crlf = "\n";
var comma = ',';
var linebreak = '<br />';
var fargs;

var loBase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012346789";
var hiBase = "abcdefghijklmnopqrstuvwxyz_";
var base10 = "0123456789";
var nBase = 36;

var dbAccented = new Object();
var dbDeaccented = new Object();

function initModal() {

 closeModal();
 // showIframe('empty.htm');
}

function init() {
var i,n,sep,params;

 BrowserDetect.init(); // ==> BrowserDetect.browser, BrowserDetect.version, BrowserDetect.OS
 //      if (BrowserDetect.browser=="Explorer") alert("IE not supported\nbest viewed with Firefox");
 // else if (BrowserDetect.browser!="Firefox")  alert("best viewed with Firefox");
 // if (BrowserDetect.browser!="Firefox")  alert("best viewed with Firefox");
 if (BrowserDetect.browser=="Explorer") alert("IE not fully supported\nbest viewed with Firefox");

 sep = location.href.indexOf('?');
 if (sep>0) fargs = location.href.substring(sep+1); else fargs = '';
 // editCPod = fargs.length;

 // init0(); // unused : requires loading _index0.js
 init1();
 dbComplete();
 crossrefPhonetics();
 //
 // dbCheck();
 //
 if (fargs.length) {
  params = fargs.split(',');
  guessingPhonetic = params[0]
  if (params.length>1) {
    guessingCompound = params[1];
    showChar(params[0],params[1]);
  }
  else if (isnumeric(params[0])) showChar(params[0],0);
  else {
    listDecode(params);
    reviewSession(true);
   }
 }
 else guessPhonetic(false);
 // startGuessing();
}

function baseEncode(k,h) {
var r,q,x;

 r = k % nBase;
 q = (k - r) / nBase;
 x = loBase[q]+loBase[r];
 // if (h<0) h=0;
 if (h>0) x += hiBase[h];
 return x;
}

function listDecode(l) {         // list encoded as string of XXy or XX - XX encode with loBase and y with hiBase
var a,b,c,i,j,h,k,r,q,s,ll;      // where XX is encoded char index and y is encoded compound subindex

 x = l.toString(l);
 ll = x.length;
 if(ll) {
  for(i=j=0;;) {
   q=loBase.indexOf(x.charAt(i++));
   if(i==ll) break;
   r=loBase.indexOf(x.charAt(i++));
   k = r + nBase*q;
   if(i==ll) {
     guessStack[j++]=[k,0];
     guessTotal=j;
     break;
   }
   c= x.charAt(i)
   h=hiBase.indexOf(c);
   if (h>0) i++; else h=0;
   guessStack[j++]=[k,h];
   guessTotal=j;
   if(i==ll) break;
  }
 }
}

function listEncode() {
var h,i,j,k,n;
var s,st;

 s = '';
 for (i=0;i<guessTotal;i++) {
   st = guessStack[i];
   k = st[0];
   h = st[1];
   s+= baseEncode(k,h);  // indexes are all absolute [0..800+]
 }
 return(s);
}

function clearChar() {
 document.getElementById('charDetails').innerHTML = nbsp;
}

function formatSingleChar(node,n) {
var j,r,s,comp,sub;

 r = node.char + sp + node.pinyin + sp + node.definition;
 s = '<tr><td align=left valign=top ID=charMap class=charMap>' + r + '</td></tr>';
 comp = node.compounds;
 for(j=0;j<comp.length;j++) {
   sub = comp[j];
   s+= sub.hanzi + sp + sub.pinyin + sp + sub.definition + linebreak ;
 }
 if (node.comment.length) s+= linebreak + node.comment + linebreak;
 return('<tr><td align=left valign=top ID=charSub  class=charSub>' + s + '</td></tr>');
}

function formatCompound(node,n,flag) {
var c,h,i,j,s,core,phon,temp,result;
var charRoot,crossRef;
var phonList=new Array;

  core = dbCore[n]
  c = core.char;
  if (flag) {
    s = 'from <a class=fromcore href=Javascript:showRoot('+n+');>'+stripPar(c)+'</a> :'+nbsp;
    s += '<a class=series href="Javascript:startSeries('+n+')">&gt; series</a></td></tr>';
    charRoot = '<tr><td align=left valign=top ID=charRoot class=charRoot>' + s + '</td></tr>';
  }
  else charRoot = '';
  result = '';
  //
  // scan series for alternate pronunciations
  //
  crossRef = ''; // <tr><td align=left valign=top ID=crossRef class=crossRef>' + crossrefList(node.pinyin) + '</td></tr>';
  phon = core.phonetics;
  for (i=0;i<phon.length;i++) {
    temp=phon[i];
    if(temp.char==node.char) {
      result += formatSingleChar(temp);
      phonList[phonList.length] = temp.pinyin; // if (!inList(phonList,temp.pinyin)) ; 

      crossRef += '<tr><td align=left valign=top ID=crossRef class=crossRef>' + crossrefList(temp.pinyin) + '</td></tr>';
    }
  }
  return (result + charRoot + crossRef);
}

function formatRoot(node,n,c) {
var j,p,q,s;
var charMap,charSub,charRoot,charAlt,crossRef;

   s = c + sp + node.pinyin + sp + node.definition;
   charMap = '<tr><td align=left valign=top ID=charMap class=charMap>' + s + '</td></tr>';
   crossRef = '<tr><td align=left valign=top ID=crossRef class=crossRef>' + crossrefList(node.pinyin) + '</td></tr>';
   s = '';
   comp = node.compounds;
   for(j=0;j<comp.length;j++) {
     sub = comp[j];
     s+= sub.hanzi + sp + sub.pinyin + sp + sub.definition + linebreak ;
   }
   if (node.comment.length) s+= linebreak + node.comment + linebreak;
   charSub = '<tr><td align=left valign=top ID=charSub  class=charSub>' + s + '</td></tr>';
   s = 'phonetic '+n+':'+nbsp;
   s += '<a class=series href="Javascript:startSeries('+n+')">&gt; series</a></td></tr>';
   charRoot = '<tr><td align=left valign=top ID=charRoot class=charRoot>' + s + '</td></tr>';
   // check alternate pronunciations
   node = node.db[c];
   if (node == undefined) charAlt  = ''; else charAlt  = formatCompound(node,n,false);
   return (charMap + charSub + charRoot + charAlt + crossRef);
}

function showRoot(n) {
var ndex,core,comp,sub,alt,i,j,s,c;
var t;

 initModal();
 core = dbCore[n];
 c = core.char;
 // only search for simplified character, skip the rest except for character compounds where no unicode exists
 if ((c.indexOf('+')<0) && c.indexOf('-')<0) c = c.charAt(0);
 if(core==undefined) alert('** undefined character error : '+i+':'+c+','+n);
                else document.getElementById('charOptions').innerHTML = '<table border=0>'+formatRoot(core,n,c)+'</table>';
}

function getAnswer(n,m) {
var ndex,core,node,comp,sub,alt,i,j,s,c,d,r;
var t;

 core = dbCore[n];
 if (m<=0) { // phonetic root only
   c = firstChar(core.char);
   if(core==undefined) r = '** undefined character error : '+i+':'+c+','+n;
                  else r = formatRoot(core,n,stripPar(c));
 }
 else { // phonetic compound
   t = charlistTable(core.charlist);
   c = t[m];
   node = core.db[addPar(c)];
   if(node==undefined) r = '** undefined character error : '+i+':'+c+','+n;
                  else r = formatCompound(node,n,true);
 }
 return r;
}


function viewAnswer(n,m) {
 // showChar(n,m);
 showAnswer(n,m);
}

function showAnswer(n,m) {
 initModal();
 document.getElementById('charDetails').innerHTML = getAnswer(n,m);
}

function addPar(s) {
  if ((s.indexOf('+')<0) && (s.indexOf('-')<0)) return s; else return(openpar+s+closepar); 
}

function stripPar(s) {

  if (s.indexOf(openpar)<0) {
    if (s.indexOf(closepar)<0) return s; else return s.substr(0,s.length-1);
  }
  else if (s.indexOf(closepar)<0) return s.substr(1,s.length-1); else return s.substr(1,s.length-2);
}

function showChar(k,h) {
var i,c,g,ref,s,t;
var core;

  initModal();
  clearChar();
  if ((k==undefined) && (h==undefined)) {
    k = guessingPhonetic;
    h = guessingCompound;
  }
  else {
    guessingPhonetic = k;
    guessingCompound = h;
    guessStack[guessTotal++] = [k,h];
  }
  core = dbCore[k];
  //
  // load definition file if not already done
  // this is asynchronous, so it must start before calling showAnswer()
  //
  if (core.definition == undefined) jsinclude(fformat(k)+'.js'); 
  c = core.char;
  if (h<=0) {
    g = stripPar(c);
    document.getElementById('mapID').innerHTML = guessTotal + ' : ' + k;
  }
  else {
    t = charlistTable(core.charlist);
    g = stripPar(t[h]);
  }
  ref = '<a class=guessChar href=Javascript:showAnswer('+k+','+h+')>'+g+'</a>';
  document.getElementById('guessChar').innerHTML = ref;
  if (guessMode == 3) {
    s = 'series ' + seriesRef +' : '+ (seriesIndex+1) +'/'+seriesLength;
  }
  else {
    if (guessMode == 2) s = 'replaying ' + (1+guessIndex) +'/'+ guessTotal; 
    else s= '[' + (guessTotal) + ']';
    s += ' char. ' + k;
    if (h>0) s+= ',' + h;
  }
  document.getElementById('mapID').innerHTML = s;
  s = 'click on character to show details';
  if (guessMode) s+= '<br /><br /><a class=skipchar href="Javascript:skipChar()">skip this character</a>';
  document.getElementById('charDetails').innerHTML = '<tr><td class=note align=center valign=top>'+s+'</td></tr>';
  // ref = '<a href=Javascript:showAnswer('+k+','+h+')>show char.</a>';
  // document.getElementById('charID').innerHTML = ref;
  document.getElementById('charOptions').innerHTML = '';
  document.getElementById('pinyinOptions').innerHTML = '';
}

function listClear() {

 guessTotal = 0;
 document.getElementById('charOptions').innerHTML = '';
}

function listSort() {
 
 function indexSort(s,t) {
 var u;
   u = (s[0]-t[0]);
   if (u) return u; else return (s[1]-t[1]);
 }
 guessStack.sort(indexSort);
 reviewSession();
}

function listRandom() {

 function randomSort(a,b) { return(get_random(0,3)-1); }
 guessStack.sort(randomSort);
 reviewSession();
}

function listDedup() {
var f,i,j,k,s,t;

 for(i=j=0;i<guessTotal;i++) {
   s = guessStack[i];
   for(f=k=0;k<j;k++) {
    t = guessStack[k];
    if ((s[0]==t[0])&&(s[1]==t[1])) {f++; break;}
   }
   if (!f) guessStack[j++]=s;
 }
 guessTotal = j;
 reviewSession();
}

function listMenu(encoding) {
var s;

 s =  '<table border=0 cellpadding=2 cellspacing=3>';
 s += '</tr>';
 s += '<td class=list align=left><a href=Javascript:replaySession(false)>replay list</a> &nbsp;</td>';
 s += '<td class=list align=left><a class=xx href=?'+  encoding + '>save list as...</a></td>';
 s += '</tr>';
 s += '<tr>';
 s += '<td class=list align=left><a class=xx href="Javascript:listSort()">sort list</a></td>';
 s += '<td class=list align=left><a class=xx href="Javascript:listRandom()">random order</a></td>';
 s += '</tr>';
 s += '<tr>';
 s += '<td class=list align=left><a class=xx href="Javascript:listClear()">clear list</a></td>';
 s += '<td class=list align=left><a class=xx href="Javascript:listDedup()">deduplic. list</a></td>';
 s += '</tr>';
 s += '<tr><td class=note colspan=2>click any character<br />below to view it</td></tr>';
 s += '</table>';
 return s;
}

function reviewSession(clearscr) {
var c,i,h,k,l,s,st,t;
var core;

 if (clearscr) document.getElementById('guessChar').innerHTML = '';
 if (guessTotal) { 
   s = listMenu(listEncode());
   s += '<table border=0>';
   for (i=0;i<guessTotal;i++) {
     s += '<tr><td class=charSub>[' + (i+1) + ']</td><td class=charMap>';
     st = guessStack[i];
     k = st[0];
     h = st[1];
     core = dbCore[k];
     //
     if (core==undefined) alert('undefined: ['+i+'] k='+k+',h='+h+' / '+guessTotal);
     if (h<0) s += ' <a class=charOptions href="Javascript:showChar('+k+','+h+')">'+ core.char + '</a>' +nbsp;
     else {
       t = charlistTable(core.charlist);
       s += ' <a class=charOptions href="Javascript:showChar('+k+','+h+')">'+ t[h] + '</a>' +nbsp;
     }
     if (core.definition == undefined) jsinclude(fformat(k)+'.js'); 
     // onMouseOver="Javascript:showAnswer('+k+','+h+')"
     s += '<a class=series href="Javascript:viewAnswer('+k+','+h+')">cheat</a>' +nbsp;
     s += '<a class=series href="Javascript:startSeries('+k+')">&gt; series</a></td></tr>';
   }
   s += '</table>';
   document.getElementById('charOptions').innerHTML = s;
 }
 else document.getElementById('charOptions').innerHTML = '<p class=note>list is empty</p>';
}

function dbComplete() {
var core,phon;
var c,i,j,l;

 for(i=0;i<dbList.length;i++) {  // add charlist field to all core characters
   l = '';
   core = dbList[i];
   phon = core.phonetics;
   for(j=0;j<phon.length;j++) {

     c=phon[j].char;
     if (l.indexOf(c)<0) l+=phon[j].char;
   }
   core.charlist = l;
 }
}

function dbCheck() {
var c,i,n,s;

 s='checking database'+crlf;
 for (i=0;i<phoneticList.length;i++) {
   c = phoneticList[i].char;
   n = phoneticList[i].ndex;
   if(dbCore[n]==undefined) s+= i+ ": missing entry: "+c+" @"+ n+ crlf;   
 }
 s += "dbList:"+dbList.length+" phoneticList: "+phoneticList.length+crlf;
 alert(s);
}


function guessPhonetic(gstop) {
var n,k;

  if (gstop) stopGuessing();
  // lastGuess = 0;
  n = dbList.length;
  k = dbList[get_random(0,n)].ndex;
  guessingPhonetic = k;
  guessingCompound = 0;
  guessStack[guessTotal++] = [k,0];
  showChar();
}

function guessCompound(gstop) {
var n,k;
var c,i,j,h,k,l,n,p,s;

  if (gstop) stopGuessing();
  // lastGuess = 1;
  n = dbList.length;
  k = dbList[get_random(0,n)].ndex;
  l = charlistTable(dbCore[k].charlist);
  h = get_random(0,l.length);
  guessingPhonetic = k;
  guessingCompound = h;
  guessStack[guessTotal++] = [k,h];
  showChar();
}

function inArray(t,x) {
var i;
 for (i=0;i<t.length;i++) if (x==t[i]) return true;
 return false;
}


function charHint(n) {
var s,l,ll,h,i,j,k;
var t = new Array;

  initModal();
  k = guessingPhonetic;
  if (k < 0) return;
  s = '<p class=note>click on any of the <br />characters below to view it</p>';
  l = charlistTable(dbCore[k].charlist);
  ll = l.length;
  if (n) {
    if (n>(ll-1)) n = ll-1;
    for(j=0;j<n;j++) {
      do { h = get_random(1,l.length); } while (inArray(t,h));
      t[j]=h;
      s += '<a class=charOptions href="Javascript:showChar('+k+','+h+')">' + l[h] + '</a>' +nbsp;
    }
  }
  else {
    for (i=0;i<ll;i++) {
      if (i && ((i % 3)==0)) s+= linebreak;
      s += '<a class=charOptions href="Javascript:showChar('+k+','+i+')">' + l[i] + '</a>' +nbsp;
    }
  }
  document.getElementById('charOptions').innerHTML = s;
}

function pinyinHint(n) {
var c,s,q,i,j,k,l,q,x;
var p = new Array;
var t = new Array;
var phon,node,core,temp;

  initModal();

  k = guessingPhonetic;
  if (k < 0) return;
  s = '<p class=note>click on any of the <br />sounds below to check</p>';
  core = dbCore[k];
  c = core.char;
/*
  build list of all pronunciations, retrieve accented pinyin

  start with core character - alternate core pronunciation would be under .db compounds
*/
  i=0;
  p[i++] = core.pinyin;
  for(x in core.db) {
    node = core.db[x];
    p[i++] = node.pinyin;
    for(j=0;j<node.alternate.length;j++) {
      temp = node.alternate[j];
      p[i++] = temp.pinyin;
    }
  }
  // p is the non-deduped list of all pinyin pronunciations
  l = i; // == p.length;
  if (n) {
    for(j=0;j<n;j++) {
      i=0;
      do {
        h = get_random(0,l); 
        q = p[h].toLowerCase();
        i++;
      }
      while (inArray(t,q) && (i < 100));  // limit to 100 to avoid infinite loop
      s += '<a class=pinyinOptions href="Javascript:checkPinyin(' + squote + q + squote +')">'+q+'</a><br />';
      t[t.length] = q; 
    }
  }
  else {
    for (i=0;i<l;i++) {
     q = p[i].toLowerCase();
     if (!inArray(t,q)) {
       s += '<a class=pinyinOptions href="Javascript:checkPinyin(' + squote + q + squote +')">'+q+'</a><br />';
       t[t.length] = q; 
      }
    }
  }
  document.getElementById('pinyinOptions').innerHTML = s;
}

function showIframe(fname) {
var x,y;

  // t = findPos(obj);
  // x = t[0];
  // y = t[1];
  x = 0;
  y = 0;

  s = '<table border=0 cellspacing=2 cellpadding=1>';
  // s+= '<tr><td style="background-color: #C40403;" align=right class=closew>';
  // s+= '<a class=closew href=Javascript:closeModal()>×</a></td></tr>';
  s += '<tr><td><iframe frameborder=0 width=800 height=450 src=' + fname + ' /></td></tr></table>';

  document.getElementById('modal').style.position  = 'absolute';
  // document.getElementById('modal').style.width = 800;
  // document.getElementById('modal').style.height = 800;
  document.getElementById('modal').style.left = x;
  document.getElementById('modal').style.top  = y+176;
  document.getElementById('modal').innerHTML = s;
  document.getElementById('closew').innerHTML = '<a style="font: 10pt courier; color: #FFFFFF; font-weight:bold; " href=Javascript:closeModal()>×</a>';
}

function checkPinyin(s) {
var c,h,j,k,q,r,s,guessed;
var temp,ndex,core,node;

 initModal();
 k = guessingPhonetic;
 h = guessingCompound;
 // ndex = phoneticList[k].ndex;
 // core = dbCore[ndex];
 core = dbCore[k];
 if (h<=0) { // phonetic core only
   q = core.pinyin.toLowerCase();
   if (q == s) guessed = 1;
   else {  // check if there are alternate core pronunciations
     node = core.db[core.char];
     if(node==undefined) guessed = 0;
     else {
       q = node.pinyin.toLowerCase();
       if (q == s) guessed = 2; else guessed = 0;
     }
   }
 }
 else { // phonetic compound
   t = charlistTable(core.charlist);
   c = t[h];
   node = core.db[c];
   q = node.pinyin.toLowerCase();
   if (q == s) guessed = 1;
   else {  // check if there are alternate pronunciations
     guessed = 0;
     for(j=0;j<node.alternate.length;j++) {
       temp = node.alternate[j];
       q = temp.pinyin.toLowerCase();
       if (q == s) guessed = 2;
     }
   }
 }
 if (guessed==0) {
   r = '<span class=wrong align=center>not quite :-(</span>';
   document.getElementById('charDetails').innerHTML = r + crossrefListdb(s,dbAccented[s.toLowerCase()],'');
 }
 else if (guessed==1) {
   r = '<span class=correct align=center>correct :-)</span>'; 
   document.getElementById('charDetails').innerHTML = r + getAnswer(guessingPhonetic,guessingCompound);
 }
 else if (guessed==2) {
   r = "<span class=wrong align=center>it's one option</span>";
   document.getElementById('charDetails').innerHTML = r;
 }
}


function charMap() {
var node;

  p = guessingPhonetic;
  h = guessingCompound;
  node = dbCore[p];
  map = fformat(p) + deaccentPinyin(node.pinyin) + '.htm?-'; // '-' will remove logo and links at top
  showIframe(map);
}

var mins,secs,timerRunning,timerID;
var seriesLength;
var seriesIndex;
var seriesRef;

function startGuessing() {

  guessMode = 1;
  guessPhase = 0;
  if (get_random(0,2)<1) guessPhonetic(false); else guessCompound(false);
  initTimer(guessTime);
}

function stopGuessing() {

 guessMode = 0;
 stopTimer(false);
 showChar();
 showAnswer(guessingPhonetic ,guessingCompound);
}

function replaySession() {
var st;

 guessMode = 2;
 guessPhase = 0;
 guessIndex = 0;

 guessIndex = 0;     // stack index will only be increased after showing answer in the timer
 st = guessStack[0];
 guessingPhonetic= st[0];
 guessingCompound = st[1];

 showChar();
 initTimer(replayGuessTime);
}

function startSeries(k) {
// var phon;

 guessMode = 3;
 guessPhase = 0;

 // phon = dbCore[k].phonetics;
 // seriesLength = phon.length;
 // alert(seriesLength);
 // alert(dbCore[k].charlist);
 seriesLength = charlistLength(dbCore[k].charlist);
 seriesRef = k;
 seriesIndex = 0;     // stack index will only be increased after showing answer in the timer
 guessingPhonetic= k;
 guessingCompound = 0;
 showChar();
 initTimer(seriesGuessTime);
}


function crossrefPhonetics() {
var c,h,j,k,l;
var node,phon,temp;
var p,q,t,u;

 // build cross-ref by accented and unaccented pinyin
 for(k in dbCore) {
   node = dbCore[k];
   phon = node.phonetics;
   l = node.charlist;
   for(j=0;j<phon.length;j++) {
     temp = phon[j];
     c = temp.char;
     h = charlistIndexof(l,c); // convert db index to index in deduped .charlist
     p = temp.pinyin.toLowerCase();
     if (dbAccented[p] == undefined) {
       var t = new Array;
       t[0] = [k,h];
       dbAccented[p] = t;
     }
     else {
       u = dbAccented[p];
       u[u.length] = [k,h];
     }
     q = deaccentPinyin(p).toLowerCase();
     if (dbDeaccented[q] == undefined) {
       var t = new Array;
       t[0] = [k,h];
       dbDeaccented[q] = t;
     }
     else {
       u = dbDeaccented[q];
       u[u.length] = [k,h];
     }
   }
 }
}

function crossrefListdb(pinyin,dbentry,suffix) {
var c,h,i,k,q,t,v,r,s;
var node,core;

 s = '';
 r =  '<table border=0 cellspacing=2 cellspacing=2>';
 r += '<tr><td align=left valign=top class=crossRef>'+pinyin+suffix+'</td><td>';
 for(i=0;i<dbentry.length;i++) {
   v=dbentry[i]; 
   k=v[0]; h=v[1];
   core = dbCore[k];
   if (h<=0) c = firstChar(core.char); // phonetic root only
   else { // phonetic compound
    t = charlistTable(core.charlist);
    c = t[h]; // stripPar(t[h]);
   }
   if (charlistIndexof(s,c) < 0) { // dedup
     s += c;
     r += '<a class=crossRef href="Javascript:showChar('+k+ comma+h+')">'+c+ '</a>' + sp;
   }
 }
 r += '</td></tr></table>';
 return r;
}

function crossrefList(p) {
var q;

 p = p.toLowerCase();
 q = deaccentPinyin(p);
 return crossrefListdb(p,dbAccented[p],'') + crossrefListdb(q,dbDeaccented[q],'*');
}

function skipChar() {
 showAnswer(guessingPhonetic,guessingCompound);
 if (guessMode==1) {
   if (get_random(0,2)<1) guessPhonetic(false); else guessCompound(false);
   initTimer(guessTime);
 } 
 else if (guessMode==2) {
   if (guessIndex<guessTotal) {
     st = guessStack[++guessIndex];
     guessingPhonetic = st[0];
     guessingCompound = st[1];
     showChar();
     initTimer(replayGuessTime);
   }
   else guessMode = 0;
 }
 else if (guessMode==3) {
   if (seriesIndex<seriesLength) {
    guessingPhonetic = seriesRef;
    guessingCompound = ++seriesIndex;
    initTimer(seriesGuessTime);
   }
   else guessMode = 0;
 }
}
 
function initTimer(s) {
    mins=0;
    secs=s;
    stopTimer(false);
    startTimer();
}

function stopTimer(action) {
var st;

  if(timerRunning) clearTimeout(timerID);
  timeRunning=false;
  if (action) {
    if (guessMode==1) {  // normal session
      if (guessPhase) {       // alternate guess phases and display results
        guessPhase = 0;       // showing answer, next cycle will show character to guess
        showAnswer(guessingPhonetic,guessingCompound);
        initTimer(answerTime);
      }
      else {
        guessPhase = 1; // showing character to guess, next cycle will show answer
        if (get_random(0,2)<1) guessPhonetic(false); else guessCompound(false);
        initTimer(guessTime);
      }
    } 
    else if (guessMode==2) {     // replaying guess session
      if (guessPhase) {  // alternate guess phases and display results
        guessPhase = 0;  // showing answer, next cycle will show character to guess
        if (guessIndex<guessTotal) {
          st = guessStack[++guessIndex];
          guessingPhonetic = st[0];
          guessingCompound = st[1];
          showChar();
          initTimer(replayGuessTime);
        }
        else guessMode = 0;
      }
      else {
        guessPhase = 1; // showing character to guess, next cycle will show answer
        showAnswer(guessingPhonetic,guessingCompound);
        initTimer(replayAnswerTime);
      }
    }
    else if (guessMode==3) {  // series session
      if (guessPhase) {  // alternate guess phases and display results
        guessPhase = 0;  // showing answer, next cycle will show character to guess
        seriesIndex++;
        if (seriesIndex<seriesLength) {
          guessingPhonetic = seriesRef;
          guessingCompound = seriesIndex;
          showChar();
          initTimer(seriesGuessTime);
        }
        else guessMode = 0;
      }
      else {
        guessPhase = 1; // showing character to guess, next cycle will show answer
        showAnswer(guessingPhonetic,guessingCompound);
        initTimer(seriesAnswerTime);
      }
    }
  }
}
 
function startTimer() {
    timerRunning=true;
    timerID=self.setTimeout("startTimer()",1000);

    if(mins==0 && secs==0) stopTimer(true);
    if(secs==0) {
       mins--;
       secs=60;
    }
    secs--;
}

