var GAME_ENABLED=false;
var GAME=null;
var MLEVEL=3;
var SSAVE="_saveSudoku";
var SGET="_getSudoku";
var SLEVEL="_sLevel";
var _ContextMenuHooked=false;
var SName='<span class="c1" >M</span><span class="c2" >a</span>th<span class="c1" >T</span><span class="c2" >o</span><span class="c1" >S</span><span class="c2" >u</span>cc<span class="c2" >e</span><span class="c4">ss</span> Sudoku Challenger';
var NEWGAME_ALARM="Please select a level and then click 'New Game' to start a challenging journey!";
var SVersion="V2.0.0";

function MSudokuGame(id,sGiven,sAnswer,sHints,sLevel,sMonthBest,login)
{
    this.ID=id;
    this.SID="MSDK";
	this.Login=login;
	this.Evaluated=true;
	this.UserAns="";
	this.CurPosition=-1;
	this.PositionXs=null;
	this.PositionYs=null;
	this.PositionKeys=null;
    this.Givens=sGiven;
    this.Answer=sAnswer;
    this.Hints=sHints;
    this.Level=sLevel;
    this.MonthBestMS=sMonthBest;
	this.StartMS=0;
	this.EndMS=0;
}

function showMsg(str)
{
   // do the trim
   var idx1 = str.indexOf("[");
   var idx2 = str.lastIndexOf("]");
   if (idx1 != -1 && idx2 != -1)
   {
       str = str.substring(idx1+1,idx2);
   }
   alert(str);
}

function fetchNewGameData(str)
{
   // do the trim
   var idx1 = str.indexOf("[");
   var idx2 = str.lastIndexOf("]");
   if (idx1 == -1 || idx2 == -1)
   {
       alert("Got error:"+str);
       return;
   }
   str = str.substring(idx1+1,idx2);
   // do the split
   var sID = null;
   var sGiven = null;
   var sAnswer =null; 
   var sHints = null;
   var sLevel = null;
   var sMonthBest = null;
   var sLogin = null;
   var vas = str.split("|");
   for (var i=0;i<vas.length;i++)
   {
      var idx = vas[i].indexOf("=");
      if (idx != -1)
      {
          var skey = vas[i].substring(0,idx);
          var sval = vas[i].substring(idx+1);
		  if ("ID"==skey)
		  {
			  sID = sval;
		  }
		  else if ("Answer"==skey)
		  {
			  sAnswer = sval;
		  }
		  else if ("Given"==skey)
		  {
			  sGiven = sval;
		  }
		  else if ("Hints"==skey)
		  {
			  sHints = sval;
		  }
		  else if ("Level"==skey)
		  {
			  sLevel = sval;
		  }
		  else if ("MonthBest"==skey)
		  {
			  sMonthBest = sval;
		  }
		  else if ("Login"==skey)
		  {
			  sLogin = sval;
		  }
	  }
   }
   if (sID && sGiven && sAnswer && sLevel && sHints)
   {
	   GAME = new MSudokuGame(sID,sGiven,sAnswer,sHints,sLevel,sMonthBest);
	   GAME.Evaluated=false;
	   if (sLogin)
	   {
		   GAME.Login = sLogin;
	   }
       setCookie(SLEVEL+MLEVEL,sID,365);
	   GAME_ENABLED=true;
       for (var r=0; r<3; r++)
	   {
           for (var l=0; l<3; l++)
	       {
		       for (var x=0;x<3;x++)
		       {
			       for (var y=0;y<3;y++)
			       {
                       var idx = (r*3+x)*9+l*3+y;
                       var c = GAME.Givens.charAt(idx);
			           var oi = document.getElementById(GAME.SID+'_'+idx);
		               if (c=='0')
		               {
					       oi.setAttribute("mflag","1");
				       }
				       else
				       {
					       oi.setAttribute("mflag","0");
				       }
			       }
		       }
		   }
	   }
	   goFirst();
	   for (var i=1;i<=5;i++)
	   {
           var olevel = document.getElementById('MLevel'+i);
		   if (olevel)
		   {
		       olevel.disabled = true;
		   }
           var omgo = document.getElementById('MGO'+i);
		   if (omgo)
		   {
		       omgo.disabled = true;
		   }
	   }
       var omans = document.getElementById('MANS');
	   if (omans)
	   {
	       omans.disabled = true;
	   }
	   var d = new Date();
	   GAME.StartMS=d.getTime();
   }
   else
   {
	   alert("No game data returned. Please try it later!");
   }
}
function parseHint2Steps(bForce)
{
   var gm = GAME;
   if (bForce || gm.PositionXs == null || gm.PositionYs == null || gm.PositionKeys == null)
   {
       gm.PositionXs = new Array(); 
       gm.PositionYs = new Array(); 
       gm.PositionKeys = new Array(); 
	   // parsing the Hints
	   var ss = gm.Hints.split(")");
	   // loop througth the ss
	   for (var i=0;i<ss.length;i++)
       {
           var idx = ss[i].indexOf("(");
           if (idx != -1)
           {
               var s = ss[i].substring(idx+1);
			   var sc = ss[i].charAt(idx-1);
			   var xys=s.split(",");
			   if (xys.length==2)
			   {
				   gm.PositionXs.push(eval(xys[0]));
				   gm.PositionYs.push(eval(xys[1]));
				   gm.PositionKeys.push(sc);
			   }
		   }
	   }
   }
}

function goFirst()
{
   GAME.CurPosition = -1;
   showCurrentPosition();
}

function goLast()
{
   parseHint2Steps(false);
   GAME.CurPosition = GAME.PositionXs.length;
   showCurrentPosition();
}

function goNext()
{
   GAME.CurPosition += 1;
   showCurrentPosition();
}

function goPrev()
{
   if (GAME.CurPosition >= 0)
   {
       GAME.CurPosition -= 1;
   } 
   showCurrentPosition();
}

function showCurrentPosition()
{
   var gm = GAME;
   parseHint2Steps(false);
   var num = '0';
   var sc = ' ';
   if (gm.CurPosition>=0 &&gm.CurPosition<gm.PositionXs.length)
   {
	   sc = gm.PositionKeys[gm.CurPosition];
	   if ('s' == sc)
	   {
           num = gm.Answer.charAt(gm.PositionXs[gm.CurPosition]*9+gm.PositionYs[gm.CurPosition]);
	   }
   }

   var olevel = document.getElementById('MLevel'+MLEVEL);
   if (olevel)
   {
	   olevel.checked = true;
   }
   var row = gm.PositionXs[gm.CurPosition];
   var col = gm.PositionYs[gm.CurPosition];
   var box = Math.floor(row/3)*3+Math.floor(col/3);

   for (var i=0; i<9; i++)
   {
       for (var j=0; j<9; j++)
	   {
           var idx = i*9+j;
           var c = gm.Givens.charAt(idx);
           var nb = Math.floor(i/3)*3+Math.floor(j/3);
           var oi = document.getElementById(gm.SID+'_'+idx);
		   if (c != '0')
		   {
		       oi.value=c;
		   }
		   if (c == '0')
		   {
			   // set the background color  and clear value for all
			   oi.style.background="#EEE0E5";
		       oi.value="";
		   }
		   else if (sc=='s' && num == c)
		   {
			  oi.style.background="yellow";
		   }
		   else if ((sc == 'r' || sc == 'o') && row == i)
		   {
			  oi.style.background="yellow";
		   }
		   else if ((sc == 'c' || sc == 'o') && col == j)
		   {
			  oi.style.background="yellow";
		   }
		   else if ((sc == 'b' || sc == 'o') && box == nb)
		   {
			  oi.style.background="yellow";
		   }
		   else
		   {
			  oi.style.background="#EEE0E5";
		   }
	   }
   }
   for (var j=0; j<=gm.CurPosition; j++)
   {
       var idx = gm.PositionXs[j]*9+gm.PositionYs[j];
       var nb = Math.floor(gm.PositionXs[j]/3)*3+Math.floor(gm.PositionYs[j]/3);
       var oi = document.getElementById(gm.SID+'_'+idx);
	   if (oi)
	   {
		   oi.value=gm.Answer.charAt(idx);
	       if (j==gm.CurPosition)
	       {
			  oi.style.background="#FFA500";
	       }
		   else if (num!='0' && oi.value == num)
		   {
			  oi.style.background="yellow";
		   }
		   else if ((sc == 'r'||sc=='o') && row == gm.PositionXs[j])
		   {
			  oi.style.background="yellow";
		   }
		   else if ((sc == 'c'||sc=='o')&& col == gm.PositionYs[j])
		   {
			  oi.style.background="yellow";
		   }
		   else if ((sc == 'b' || sc == 'o') && box == nb)
		   {
			  oi.style.background="yellow";
		   }
		   else
		   {
			   oi.style.background="#EEE0E5";
		   }
	   }
   }
}

function showUserAnswer()
{
	var gm = GAME;
	if (gm.Evaluated)
	{
       for (var i=0; i<9; i++)
       {
           for (var j=0; j<9; j++)
	       {
               var idx = i*9+j;
               var oi = document.getElementById(gm.SID+'_'+idx);
			   if (oi)
			   {
                   if (gm.Givens.charAt(idx)=='0')
				   {
					   if (gm.UserAns.charAt(idx) == '0')
					   {
					       oi.value="";
					   }
					   else
					   {
					       oi.value=gm.UserAns.charAt(idx);
					   }
					   if (gm.Answer.charAt(idx)!=gm.UserAns.charAt(idx))
					   {
					       oi.style.background="yellow";
					   }
					   else
					   {
					       oi.style.background="#EEE0E5";
					   }
				   }
				   else
				   {
					   oi.style.background="#EEE0E5";
				   }
			   }
	       }
       }
	}
}

function loadOrCheckCorrectness(event)
{
   if (!event) event= window.event;
   var tgt = event.srcElement || event.currentTarget || event.target;
	
   var gm = GAME;
   if ("Check Answer"==tgt.value)
   {
	   var d = new Date();
	   if ((d.getTime()-gm.StartMS)<300000)
	   {
		   // check if all empty cells are filled
		   var ballfilled = true;
           for (var i=0; i<9; i++)
           {
               for (var j=0; j<9; j++)
	           {
                   var idx = i*9+j;
                   var c = gm.Givens.charAt(idx);
		           if (c == '0')
		           {
                       var oi = document.getElementById(gm.SID+'_'+idx);
			           if (!oi || oi.value == "")
					   {
		                   ballfilled = false;
						   break;
					   }
				   }
			   }
		   }
		   if (!ballfilled)
		   {
		       alert("You need fill all cells or work at least 5 minutes before checking answer!");
		       return;
		   }
	   }
	   gm.EndMS = d.getTime();
       gm.UserAns="";
       tgt.value ="New Game";

       for (var i=0; i<9; i++)
       {
           for (var j=0; j<9; j++)
	       {
               var idx = i*9+j;
               var c = gm.Givens.charAt(idx);
		       if (c == '0')
		       {
                   var oi = document.getElementById(gm.SID+'_'+idx);
			       if (oi)
			       {
				       var v = ""+oi.value;
				       if (v != "")
				       {
					       c = v.charAt(0);
				       }
			           // set the background color here for incorrect answer
                       if (c == gm.Answer.charAt(idx))
				       {
					       oi.style.background="#EEE0E5";
				       }
				       else
				       {
					       oi.style.background="yellow";
				       }
			       }
		       }
               gm.UserAns += c;
	       }
       }
	   for (var i=1;i<=5;i++)
	   {
           var olevel = document.getElementById('MLevel'+i);
		   if (olevel)
		   {
		       olevel.disabled = false;
		   }
           var omgo = document.getElementById('MGO'+i);
		   if (omgo)
		   {
		       omgo.disabled = false;
		   }
	   }
       var omans = document.getElementById('MANS');
	   if (omans)
	   {
	       omans.disabled = false;
	   }
       gm.Evaluated=true;
       if (gm.Answer == gm.UserAns)
	   {
		   if (gm.Login && gm.Login != "" && (gm.MonthBestMS<=0 || (gm.EndMS-gm.StartMS) < gm.MonthBestMS))
	       {
               loadOrSaveGame(SSAVE);
		   }
		   else
		   {
			   alert("Congratulations, you got all correct answers!");
		   }
	   }
   }
   else if ("New Game"==tgt.value)
   {
       tgt.value ="Check Answer";
       loadOrSaveGame(SGET);
   }
   return true;
}

function writeSudokuGame(gm)
{
   GAME=gm;
   document.writeln('<table align="center">');
   document.writeln('<tr><td>');
   document.writeln('<table align="center" class="msudoku" id="'+gm.SID+'" style="border:solid 1px black;"><caption>'+SName+' ('+SVersion+')</caption>');
   gm.UserAns=gm.Givens;
   for (var r=0; r<3; r++)
   {
       document.writeln('<tr>');
       for (var l=0; l<3; l++)
	   {
           document.writeln('<td>');
           document.writeln('<table align="center" class="mbox" style="border:solid 1px orange;">');
		   for (var x=0;x<3;x++)
		   {
              document.writeln('<tr>');
			  for (var y=0;y<3;y++)
			  {
                  document.write('<td style="text-align:center;width:30px;height:30px;border:solid 1px green;">');
                  var idx = (r*3+x)*9+l*3+y;
                  var c = gm.Givens.charAt(idx);
		          if (c=='0')
		          {
			          document.write('<input id="'+gm.SID+'_'+idx+'" mflag="1" type="button" onclick="changeNum(event)" onmousedown="checkRightClick(event)" onkeydown="numTyped(event)" style="width:30px;height:30px;background:#EEE0E5;font-weight:bold;font-size:16pt;" value=""/>');
		          }
		          else
		          { 
			          document.write('<input id="'+gm.SID+'_'+idx+'" mflag="0" type="button" onclick="changeNum(event)" onmousedown="checkRightClick(event)" onkeydown="numTyped(event)" style="width:30px;height:30px;background:#EEE0E5;font-weight:bold;font-size:16pt;" value="'+c+'"/>');
		          }
                  document.write('</td>');
			  }
              document.writeln('</tr>');
		   }
           document.writeln('</table>');
           document.writeln('</td>');
	   }
       document.writeln('</tr>');
   }
   document.writeln('</table>');
   document.writeln('</td></tr><td>');
   document.writeln('<table align="center" class="mgcmd">');
   document.writeln('<tr>');
   document.writeln('<td>');
   document.writeln('<table align="center"><tr>');
   document.writeln('<td style="text-align:center;">');
   document.write('<button type="button" id="MGO1" onclick="goFirst()" style="padding:0px;width:25px;background:#EEE0E5;" ><image src="js/menu/first.png" style="width:20px;height:30px;" alt="first" /></button>');
   document.writeln('</td>');
   document.writeln('<td style="text-align:center;">');
   document.write('<button type="button" id="MGO2" onclick="goPrev()" style="padding:0px;width:25px;background:#EEE0E5;"><image src="js/menu/prev.png" style="width:20px;height:30px;" alt="previous" /></button>');
   document.writeln('</td>');
   document.writeln('<td style="text-align:center;">');
   document.write('<button type="button" id="MGO3" onclick="goNext()" style="padding:0px;width:25px;background:#EEE0E5;"><image src="js/menu/next.png" style="width:20px;height:30px;" alt="next" /></button>');
   document.writeln('</td>');
   document.writeln('<td style="text-align:center;">');
   document.write('<button type="button" id="MGO4" onclick="goLast()" style="padding:0px;width:25px;background:#EEE0E5;"><image src="js/menu/last.png" style="width:20px;height:30px;" alt="last" /></button>');
   document.writeln('</td>');
   document.writeln('<td style="text-align:center;">');
   document.write('<button type="button" id="MANS" onclick="showUserAnswer()" style="padding:0px;width:25px;background:#EEE0E5;"><span style="height:30px;text-align:center;font-size:18pt;font-style:bold;border:solid 1pt blue;" title="My Answers">A</span></button>');
   document.writeln('</td>');
   document.writeln('</tr></table>');
   document.writeln('</td>');
   document.writeln('<td>');
   // difficult level
   document.writeln('<table align="center"><tr><td style="text-align:center;">');
   document.write('Easier - Harder');
   document.writeln('</td></tr><tr><td style="text-align:center;">');
   document.write('<input type="radio" id="MLevel1" class="mgradio" style="background:#ADFF2F;" onclick="MLEVEL=1;" name="MLevel" value="1"/>');
   document.write('<input type="radio" id="MLevel2" class="mgradio" style="background:#7CFC00;" onclick="MLEVEL=2;" name="MLevel" value="2"/>');
   document.write('<input type="radio" id="MLevel3" class="mgradio" style="background:#00FF00;" onclick="MLEVEL=3;" name="MLevel" value="3"/>');
   document.write('<input type="radio" id="MLevel4" class="mgradio" style="background:#00CD00;" onclick="MLEVEL=4;" name="MLevel" value="4"/>');
   document.write('<input type="radio" id="MLevel5" class="mgradio" style="background:#008B00;" onclick="MLEVEL=5;" name="MLevel" value="5"/>');
   document.writeln('</td></tr></table>');
   document.writeln('</td>');
   document.writeln('<td>');
   document.write('<input type="button" onclick="loadOrCheckCorrectness(event)" style="width:95px;height:25px;background:#EEE0E5;" value="New Game"/>');
   document.writeln('</td>');
   document.writeln('</tr>');
   document.writeln('</table>');
   document.writeln('</td></tr></table>');
   document.body.oncontextmenu = disableContextMenu;
}
function disableContextMenu(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	if (tgt && tgt.getAttribute("mflag")=="1")
	{
	    return false;
	}
}

function checkRightClick(event)
{
	if (!event) event= window.event;
	var rightclick = false;
	if (event.which) rightclick = (event.which == 3);
	else if (event.button) rightclick = (event.button == 2);
	if (rightclick)
	{
	    var tgt = event.srcElement || event.currentTarget || event.target;
		if (tgt && tgt.getAttribute("mflag")=="1")
		{
			if (!GAME_ENABLED)
			{
				alert(NEWGAME_ALARM);
			}
			else if (tgt.value=="")
			{
	            tgt.value=9;
		        tgt.style.background="#FFA500";
			}
			else if (tgt.value==1)
			{
	            tgt.value="";
		        tgt.style.background="#EEE0E5";
			}
			else
			{
	            tgt.value=tgt.value-1;
		        tgt.style.background="#FFA500";
			}
		}
	}
}
function numTyped(event)
{
    var keynum;
    var keychar;
    if(window.event) // IE
    {
        keynum = event.keyCode;
    }
    else if(event.which) 
    {
        keynum = event.which;
    }
    keychar = String.fromCharCode(keynum);
    var numcheck = /[0-9]/;
    if (numcheck.test(keychar))
	{
	    if (!event) event= window.event;
	    var tgt = event.srcElement || event.currentTarget || event.target;
	    if (tgt && tgt.getAttribute("mflag")=='1')
		{
            var num1to9 = /[1-9]/;
			if (!GAME_ENABLED)
			{
				alert(NEWGAME_ALARM);
			}
			else if (num1to9.test(keychar))
			{
	            tgt.value=keychar;
		        tgt.style.background="#FFA500";
			}
			else
			{
	            tgt.value="";
		        tgt.style.background="#EEE0E5";
			}
		}
	}
}

function changeNum(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	
	if (!tgt || tgt.getAttribute("mflag")!='1')
	{
		return;
	}
	else if (!GAME_ENABLED)
	{
		alert(NEWGAME_ALARM);
		return;
	}

	var sval;
	if (tgt.value=="")
	{
		sval = 1;
	}
	else
	{
	    sval=eval(tgt.value+"+1");
	}
	if (sval>9)
	{
		tgt.value="";
		tgt.style.background="#EEE0E5";
	}
	else
	{
		tgt.value=sval;
		tgt.style.background="#FFA500";
	}
}

// fetch a new game and save the result of a game if it breaks the records
function loadOrSaveGame(scmd)
{  
  var gm=GAME;
  if (gm && !gm.Evaluated)
  {
	  return;
  }
  else
  {
	  var sqstr = null;
	  if (scmd==SSAVE)
	  {
		  sqstr = "MLOGIN="+gm.Login+"&MGID="+gm.ID+"&MCMD="+scmd+"&MGMS="+(gm.EndMS-gm.StartMS);
	  }
	  else if (scmd==SGET)
	  {
		  var gid = getCookie(SLEVEL+MLEVEL);
		  if (!gid || gid == "")
		  {
			  if (gm.ID>0 && gm.Level==MLEVEL)
			  {
				  gid = gm.ID;
			  }
		  }
		  sqstr = SLEVEL+"="+MLEVEL+"&MCMD="+scmd+"&MGID="+gid;
	  }
	  else
	  {
		  return;
	  }
      var xmlHttp;
      try
      {  
          // Firefox, Opera 8.0+, Safari    
          xmlHttp=new XMLHttpRequest();    
          if (xmlHttp.overrideMimeType) 
          {
             xmlHttp.overrideMimeType('text/html');
          }
      }
      catch (e)
      {    // Internet Explorer    
          try
          {      
              xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");      
          }
          catch (e)
          {      
              try
              {        
                  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");        
              }
              catch (e)
              {        
                  alert("Your browser does not support AJAX and you may need to consider to update your browser!");        
                  return;        
              }      
           }    
       }
       xmlHttp.onreadystatechange=function()
       {
            if(xmlHttp.readyState==4)
            {
				if (scmd == SSAVE)
				{
					// set any returned data to msg area
					showMsg(xmlHttp.responseText);
				}
				else if (scmd == "_getSudoku")
				{
					//fetch the new game data
                   fetchNewGameData(xmlHttp.responseText);
				}
            }
        }

       // build the query string dynamically
       xmlHttp.open("POST","http://"+document.domain+"/DoMath.do",true);
       xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       xmlHttp.send('MAJAX=1&MService=MSudoku_4&'+sqstr);  
    }
}

