var mData = new Hashtable();
var mOps = new Array("+","-","*","/");
var mRanges = new Array(20,50,100,500);
var mRangeNames = new Array("0-20","20-50","50-100","100-500");
var mSpeeds = new Array(1500,800,400,200);
var mSpeedNames = new Array("Slower","Medium","Fast","Faster");
var Delta=10;
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> Calc Challenger';
var SVersion="Version 5.0.0";
function MCalcGame(sid,nwidth,nheight,nlow,nhigh,aops,ntimeout,num,blogin,bfloat)
{
    this.SID=sid;
    this.Low=nlow;
    this.High=nhigh;
    this.Operations=aops;
    this.TimeOut=ntimeout;
    this.TotalNum=num;
    this.CorrectNum=0;
    this.Answer=0;
    this.CurCnt=0;
    this.CurOper='+';
    this.Nums=null;
	this.Store= new Array();
    this.Width=nwidth;
    this.Height=nheight;
    this.Left=0;
    this.Top=0;
    this.Cid=null;
	this.Running=false;
	this.StartMS=0;
	this.TimeMS=0;
	this.Login=blogin;
	this.Float=bfloat;
}
function writeCalcGame(gm)
{
   document.writeln('<div id="'+gm.SID+'Out" style="width:'+(gm.Width+60)+'px;height:'+(gm.Height+126)+'px;line-height:120%;text-indent:0px;display:block;'+(gm.Float?'float:right;':'')+'border-width:5px;border:double rgb(0,0,255);background:#7EC0EE;"><div id="'+gm.SID+'Cmd" style="width:'+(gm.Width+60)+'px;">'+configureAndHelp(gm.SID)+'</div><div id="'+gm.SID+'Blk" style="background-color:#EEE5DE;width:'+(gm.Width+60)+'px;height:'+(gm.Height)+'px;display:block;'+(gm.Float?'float:right;':'')+'border-bottom:double rgb(0,0,255);border-top:double rgb(0,0,255);overflow:auto;"><span id="'+gm.SID+'" style="margin:10px 10px 10px 10px;position:relative;top:10px;left:0px;background:#FF8C00;"></span></div><div style="width:'+(gm.Width+60)+'px;display:block;'+(gm.Float?'float:right;':'')+'"><table style="width:'+(gm.Width+50)+'px;font-size:8pt;"><tr><td>Answer Here:<input type="text" size="3" id="'+gm.SID+'Ans" onkeyup="CheckAnswer(event)"/></td><td>QuestionNum<input type="text" size="2" id="'+gm.SID+'Num" value="'+gm.TotalNum+'" onchange="qNumchanged(event)" />:<span id="'+gm.SID+'Cnt">0</span></td><td><input type="button" id="'+gm.SID+'Run" onclick="reRun(\''+gm.SID+'\')" value="Start" ></td><td><input type="button" id="'+gm.SID+'Hlp" onclick="help(event)" value="Reset"/></td></tr></table></div></div>');
}

function help(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	var stid = tgt.id;
	var sid = stid.substring(0,stid.length-3);
    setHelp(sid);
}
function setHelp(sid)
{
	var gm=mData.get(sid);
	if (gm)
	{
	    if (gm.Running)
	    {
		   clearTimeout(gm.Cid);
		   document.getElementById(gm.SID+"Cnt").innerHTML=0;
		   gm.Running=false;
		}
		var tblk= document.getElementById(sid+"Blk");
		if (tblk)
		{
			tblk.innerHTML='<div style="width:'+(gm.Width+50)+'px;text-align:center;padding-top:3mm;"><div style="font-weight:bold">'+SName+' - '+SVersion+'</div><table align="center" style="font-size:10pt;text-align:left;margin-top:3mm;"><caption style="text-decoration:underline;margin-top:3mm;">You can change the settings at any time</caption><tr><th>Operations:</th><td>The arithmetic operations;</td></tr><tr><th>Ranges:</th><td>The number range of the arithmetic operations;</td></tr><tr><th>Speed:</th><td>The speed to present each question;</td></tr><tr><th>QuestionNum:</th><td>The question number of each run.</td></tr></table><div style="padding-left:5mm;text-align:left;padding-top:5mm;padding-bottom:5mm;">Type your answer in the blank after "<b>Answer Here</b>" and push "Enter" to finalize.</div>Click <b>Start</b> to start challenging yourself!</div>';
		}
	}
}
function qNumchanged(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	var stid = tgt.id;
	var sid = stid.substring(0,stid.length-3);
	var gm=mData.get(sid);
	if (gm)
	{
		try{
		    gm.TotalNum=eval(tgt.value);
		}catch(err)
		{
		    gm.TotalNum=10;
		}
	}
}

function reRun(sid)
{
	var gm=mData.get(sid);
	if (gm && !(gm.Running))
	{
		/* clear all  temp data*/
		gm.CorrectNum=0;
        gm.CurCnt=0;
	    gm.Store= new Array();
        gm.Top=gm.Height-Delta;
        var t=document.getElementById(sid);
		if (!t)
		{
			var tblk= document.getElementById(sid+"Blk");
			if (tblk)
			{
				tblk.innerHTML='<span id="'+sid+'" style="margin:10px 10px 10px 10px;position:relative;top:10px;left:0px;background:#FF8C00;"></span>';
			}
		}
		runNext(sid);
		var d = new Date();
		gm.StartMS = d.getTime();
	}
}

function operationChanged(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	var stid = tgt.id;
	var sid = stid.substring(0,stid.length-3);
	var gm=mData.get(sid);
	if (gm)
	{
		var v=tgt.value;
		if (tgt.checked)
		{
			for (var i=0;i<gm.Operations.length;i++)
			{
				if (gm.Operations[i]==v)
				{
					return;
				}
			}
			gm.Operations.push(v);
		}
		else
		{
			var newOps=new Array();
			for (var i=0;i<gm.Operations.length;i++)
			{
				if (gm.Operations[i]!=v)
				{
					newOps.push(gm.Operations[i]);
				}
			}
			if (newOps.length==0) {
				// do not let user clear the final operation
				newOps.push(v);
				tgt.checked=true;
			}
			gm.Operations=newOps;
		}
	}
}
function rangeChanged(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	var stid = tgt.name;
	var sid = stid.substring(0,stid.length-3);
	var gm=mData.get(sid);
	if (gm)
	{
		var v=eval(tgt.value);
		gm.High = v;
		for (var i=0;i<mRanges.length;i++)
		{
			if (mRanges[i] == v)
			{
				if (i>1)
				{
					gm.Low=mRanges[i-1];
				}
				else
				{
					gm.Low=0;
				}
				return;
			}
		}
	}
}
function speedChanged(event)
{
	if (!event) event= window.event;
	var tgt = event.srcElement || event.currentTarget || event.target;
	var stid = tgt.name;
	var sid = stid.substring(0,stid.length-3);
	var gm=mData.get(sid);
	if (gm)
	{
		gm.TimeOut = eval(tgt.value);
	}
}

function CheckAnswer(event)
{
	if (!event) event= window.event;
	if (event.keyCode == 13)
	{
		var tgt = event.srcElement || event.currentTarget || event.target;
		var stid = tgt.id;
		var sid = stid.substring(0,stid.length-3);
		var gm = mData.get(sid);
        gm.Top=gm.Height-Delta;
		clearTimeout(gm.Cid);
		runNext(gm.SID);
	}
}

function evalAnswer(gm)
{
	var stid = gm.SID+"Ans";
	var tgt = document.getElementById(stid);
	var uanswer;
	try{
		uanswer=eval(tgt.value);
	}catch(err)
	{
	}
	var s=gm.Nums[0]+"&nbsp;"+getDisplay(gm.CurOper)+"&nbsp;"+gm.Nums[1]+"&nbsp;=&nbsp;";
	if (gm && gm.Answer==uanswer)
	{
		s+=uanswer;
		gm.CorrectNum+=1;
	}
	else
	{
		s+='<span style="color:red;text-decoration:line-through">&nbsp;'+tgt.value+'&nbsp;</span>';
		s+='&nbsp;&nbsp; ===> &nbsp;&nbsp; '+gm.Answer;
	}
	gm.Store[gm.CurCnt-1]=s;
	tgt.value="";
	tgt.focus();
}

function addCalcGame(sid,nwidth,nheight,nlow,nhigh,aops,ntimeout,num,blogin)
{
	var gm = new MCalcGame(sid,nwidth,nheight,nlow,nhigh,aops,ntimeout,num,blogin,true);
	mData.put(sid,gm); 
    writeCalcGame(gm);
    setHelp(sid);
	document.getElementById(sid+"Ans").focus();
}

function addCalcGameNoFloat(sid,nwidth,nheight,nlow,nhigh,aops,ntimeout,num,blogin)
{
	var gm = new MCalcGame(sid,nwidth,nheight,nlow,nhigh,aops,ntimeout,num,blogin,false);
	mData.put(sid,gm); 
    writeCalcGame(gm);
    setHelp(sid);
	document.getElementById(sid+"Ans").focus();
}

function getDisplay(ch)
{
	if ('-' == ch)
	{
		return "&minus;";
	}
	else if ('*' == ch)
	{
		return "&times;";
	}
	else if ('/' == ch)
	{
		return "&divide;";
	}
	else
	{
		return ch;
	}
}

/*One operator selection */
function setNumsAndAnswer1(sid)
{
	var gm = mData.get(sid);
	if (gm == null)
	{
		return;
	}
    gm.CurCnt+=1;
	var ops = gm.Operations;
	if (ops && ops.length>0)
	{
        gm.CurOper = ops[Math.floor(Math.random()*ops.length)];
	}
	else
	{
        gm.CurOper = '+';
	}
	if (gm.Nums==null)
	{
		gm.Nums = new Array(2);
	}

	if (gm.CurOper == '-')
	{
		gm.Nums[0] = gm.Low+Math.round(Math.random()*(gm.High-gm.Low));
		gm.Nums[1] = Math.round(Math.random()*gm.Nums[0]);
	}
	else if (gm.CurOper == '*')
	{
		gm.Nums[0] = Math.round(Math.sqrt(gm.Low+Math.random()*(gm.High-gm.Low)));
		if (gm.Nums[0] == 0)
		{
		    gm.Nums[0] =1;
		}
		gm.Nums[1] = Math.round((1+Math.random()*(gm.High-1))/gm.Nums[0]);
	}
	else if (gm.CurOper == '/')
	{
		gm.Nums[0] = Math.round(Math.sqrt(Math.random()*gm.High));
		if (gm.Nums[0] == 0)
		{
		    gm.Nums[0] =1;
		}
		gm.Nums[1] = Math.ceil((1+Math.random()*(gm.High-1))/gm.Nums[0]);
		gm.Nums[0] = gm.Nums[0]*gm.Nums[1];
	}
    else	
	{
		gm.Nums[0] = Math.round(Math.random()*gm.High);
		if (gm.Nums[0]<gm.Low)
		{
		    gm.Nums[1] = gm.Low-gm.Nums[0]+Math.round(Math.random()*(gm.High-gm.Low));
		}
		else
		{
		    gm.Nums[1] = Math.round(Math.random()*(gm.High-gm.Nums[0]));
		}
	}
	gm.Answer=eval(gm.Nums[0]+gm.CurOper+gm.Nums[1]);
}

function runNext(sid)
{
	var gm = mData.get(sid);
	if (gm == null)
	{
		return;
	}
	if (gm)
	{
	    document.getElementById(gm.SID+"Ans").focus();
	}
	if (!(gm.Running))
	{
	    gm.Running=true;
	}

	if (gm.Top>=(gm.Height-Delta))
	{
        if (gm.CurCnt>0)
		{
            evalAnswer(gm);
		}
        if (gm.CurCnt>=gm.TotalNum)
		{
			var d = new Date();
			gm.TimeMS=Math.round((d.getTime()-gm.StartMS)/gm.TotalNum);
			var shtml = "<table width='300' border='1' align='center'><caption style=\"text-decoration:underline;\">Practice results</caption><tr><th>Total Questions</th><td>"+gm.TotalNum+"</td></tr>"+
			            "<tr><th>Correct Number</th><td>"+gm.CorrectNum+"</td></tr>"+
			            "<tr><th>Percentage</th><td>"+Math.round(gm.CorrectNum*100.0/gm.TotalNum)+"%</td></tr>"+
			            "<tr><th>Time/Question</th><td>"+gm.TimeMS+" ms</td></tr></table>";
			shtml+="<table align='center' width='300' ><caption style=\"text-decoration:underline;\">Details of all the questions</caption>";
			for (var i=0;i<gm.Store.length;i++)
			{
				shtml+= "<tr><td>"+gm.Store[i]+"</td></tr>";
			}
			shtml+="</table>";
            document.getElementById(gm.SID+"Blk").innerHTML=shtml;
	        gm.Running=false;
			if(gm.Login)
			{
			    saveGame(gm,"MGSAVE");
			}
			return;
		}
        setNumsAndAnswer1(sid);
        document.getElementById(gm.SID+"Cnt").innerHTML=gm.CurCnt;
		var nums = gm.Nums;
        document.getElementById(sid).innerHTML=nums[0]+"&nbsp;"+getDisplay(gm.CurOper)+"&nbsp;"+nums[1]+"&nbsp;=&nbsp;";
	    gm.Top=gm.Top%(gm.Height-Delta);
	    gm.Left=Math.round((gm.Width-50)*Math.random());
	}
    document.getElementById(sid).style.top=gm.Top+"px";
    document.getElementById(sid).style.left=gm.Left+"px";
    gm.Top=gm.Top+Math.round((gm.Height-Delta)/10);
	gm.Cid=setTimeout("runNext('"+sid+"');", Math.round(gm.TimeOut*Math.log(10+gm.High/20)/Math.log(10)));
}

function hasOperation(gm,op)
{
	if (gm && op)
	{
		var ops = gm.Operations;
		for (var i=0;i<ops.length;i++)
		{
			if (op==ops[i])
			{
				return true;
			}
		}
	}
	return false;
}

function configureAndHelp(sid)
{
	var gm = mData.get(sid);
    var shtml='<table align="center" style="border:solid 1px;width:'+(gm.Width+50)+'px;font-size:8pt;text-align:right;line-height:50%;margin-top:1mm;margin-left:0px;"><caption style="padding:2mm;"><span style="font-size:10pt;font-weight:bold;text-decoration:underline;">'+SName+'</span></caption>';
    shtml+='<tr><td style="margin-left:-50px"><b>Operations:</b></td>';
	for (var i=0;i<mOps.length;i++)
	{
	    if (hasOperation(gm,mOps[i]))
		{
             shtml+='<td>'+getDisplay(mOps[i])+'<input type="checkbox" value="'+mOps[i]+'" id="'+sid+'Op'+i+'" onclick="operationChanged(event)" checked /></td>';
		}
		else
		{
             shtml+='<td>'+getDisplay(mOps[i])+'<input type="checkbox" value="'+mOps[i]+'" id="'+sid+'Op'+i+'" onclick="operationChanged(event)" /></td>';
		}
	}
    shtml+='</tr><tr><td><b>Ranges:</b></td>';
	for (var i=0;i<mRanges.length;i++)
	{
	    if (gm && gm.High==mRanges[i])
		{
             shtml+='<td>'+mRangeNames[i]+'<input type="radio" value="'+mRanges[i]+'" name="'+sid+'Rng" onclick="rangeChanged(event)" checked /></td>';
		}
		else
		{
             shtml+='<td>'+mRangeNames[i]+'<input type="radio" value="'+mRanges[i]+'" name="'+sid+'Rng" onclick="rangeChanged(event)" /></td>';
		}
	}
    shtml+='</tr><tr><td><b>Speeds:</b></td>';
	for (var i=0;i<mSpeeds.length;i++)
	{
	    if (gm && gm.TimeOut==mSpeeds[i])
		{
             shtml+='<td>'+mSpeedNames[i]+'<input type="radio" value="'+mSpeeds[i]+'" name="'+sid+'Spd" onclick="speedChanged(event)" checked /></td>';
		}
		else
		{
             shtml+='<td>'+mSpeedNames[i]+'<input type="radio" value="'+mSpeeds[i]+'" name="'+sid+'Spd" onclick="speedChanged(event)" /></td>';
		}
	}
    shtml+='</tr></table>';
    return shtml;
}

function urlEncode(str) 
{
    var v;
    try { 
        v = encodeURIComponent(str); 
    } catch (e) 
    { 
        v = escape(str); 
    }
    return v.replace(/%20/g,"+");
}

function fetchData(str)
{
   // do the trim
   var idx1 = str.indexOf("[");
   var idx2 = str.lastIndexOf("]");
   if (idx1 == -1 || idx2 == -1)
   {
	   myWindow=window.open('','','width=600,height=400');
       myWindow.document.write(str);
       myWindow.focus();
       return;
   }
   str = str.substring(idx1+1,idx2);
   var idx = str.indexOf("|");
   if (idx != -1)
   {
       var sid = str.substring(0,idx);
       var obs = document.getElementById(sid);
       if (obs)
       {
           obs.innerHTML = "<div style=\"padding: 1mm 3mm;color:red;font-weight:bold;\">"+str.substring(idx+1)+"</div>"+obs.innerHTML;
       }
   }
}
function saveGame(gm,scmd)
{  
  if (!gm || gm.TotalNum<10 || gm.TotalNum > gm.CorrectNum)
  {
	  return;
  }
  else
  {
	  var sqstr = "MGID="+gm.SID+"Blk&MCMD="+scmd+"&MKEY="+urlEncode(gm.Operations.sort()+"_"+gm.High)+"&MGMS="+gm.TimeMS;
      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)
            {
				fetchData(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=MGame_4&'+sqstr);  
    }
}

