


function sodokoGame(pGameName,pDivName,pInitArray,pSolutionArray)
{
  divsodoko=document.getElementById(pDivName)
  divsodoko.innerHTML="";
  divsodoko.appendChild(baseBuilder(pGameName))
  initEvents4Fields(pGameName)
  
  divsodoko.oncontextmenu=showContextMenu
  
  document.onclick=hideContextMenu
  this.initArray=pInitArray
  this.solutionArray=pSolutionArray
  this.gameName=pGameName
  this.initGame=fillsodokoInputValues
  this.showSolutionGame=fillsodokoSolution
  this.getSolutionArrayFormatted=getSolutionArrayFormatted
  
  this.isValidSolution = isValidGameSolution;
  this.isValidMatrix=quickIsValidMatrix
  this.quickUniqueMatrix=quickUniqueMatrix
  this.quickSmallMatrix=quickSmallMatrix
  
  this.isValidField=isValidField
  this.sodokoSolver=callsodokoSolver;
  this.initGame();
}

function baseBuilder(pGameName)
{
  table=document.createElement("table")
  table.className="mainTable aBig"
  table.cellPadding=0
  table.cellSpacing=0  
  tbody=document.createElement("tbody")
  for(var i=0;i<9;i++)
  {
    tr=document.createElement("tr")
	for(var j=0;j<9;j++)
	{
	  td=document.createElement("td")
	  td.className=getTdClass(i,j)
	  input=document.createElement("input")
	  input.setAttribute("type","text")
	  input.setAttribute("name","n"+i+""+j)
	  input.setAttribute("id",pGameName+"_n"+i+""+j)	
	  td.appendChild(input)
	  tr.appendChild(td)
	}
	tbody.appendChild(tr)
  }
  table.appendChild(tbody)
  return table
}

function fillsodokoInputValues()
{
  pGameName=this.gameName
  pArrInit=this.initArray
  for(var i=0;i<9;i++)
  {
    for(var j=0;j<9;j++)
	{
	  input=getGameField(pGameName,i,j)
	  input.className=getInputClass(pArrInit[i][j])
	  input.readOnly=(""!=pArrInit[i][j])?true:false
	  input.style.color=(""!=pArrInit[i][j])?"black":"#8a8a8a";
	  input.value=pArrInit[i][j]	  	  
	}
  }
}

function fillsodokoSolution()
{
  pGameName=this.gameName
  pArrInit=this.solutionArray
  for(var i=0;i<9;i++)
  {
    for(var j=0;j<9;j++)
	{
	  input=getGameField(pGameName,i,j)
	  input.value=pArrInit[i][j]	  	  
	}
  }
}

function getInputClass(pValue)
{
  if(pValue!="")
  {
    return "init"
  }
  else
  {
    return "play"
  }
}

function getTdClass(pI,pJ)
{
	return getLightDark(pI,pJ)+" "+getAij(pI,pJ)	
}

function getLightDark(p_I,p_J)
{
  var result="";
  if((p_I<3||p_I>5)&&(p_J<3||p_J>5)||(p_I>2&&p_I<6&&p_J>2&&p_J<6))
  {
    result="light"
  }
  else
  {
    result="dark"
  }
  return result;  
}

function getAij(p_I,p_J)
{
  return "a"+getNormIndex(p_I)+""+getNormIndex(p_J)
}

function getNormIndex(pI)
{
  var lI=0;
  if(pI<3) lI=pI+1;
  if(pI>2&&pI<6) lI=pI+1-3;
  if(pI>5) lI=pI+1-6;
  return lI
}

function getGameArray(pGameName)
{
  var gameArray=new Array();
  for(var i=0;i<9;i++)
  {
    gameArray[i]=new Array()
	for(var j=0;j<9;j++)
	{
	  gameArray[i][j]=getGameField(pGameName,i,j).value
	}
  }
  return gameArray;
}

function getGameField(pGameName,pI,pJ)
{
  return document.getElementById(pGameName+"_n"+pI+""+pJ)
}


function allRemoveRed(pGameName,pI,pJ)
{
  var larSetRed=getInd4Check(pI,pJ)
  removeRed(getGameField(pGameName,pI,pJ))
  for(var i=0;i<larSetRed.length;i++)
  {
    removeRed(getGameField(pGameName,larSetRed[i][0],larSetRed[i][1]))
  }
}


function callCheckField(evt)
{
	var pI;
	var pJ;
	var pGameName;
	var ie_var = "srcElement";
	var moz_var = "target";
	
	var prop_var = "pi";
	
	evt[moz_var] ? pI = evt[moz_var][prop_var] : pI = evt[ie_var][prop_var];
	prop_var = "pj";
	evt[moz_var] ? pJ = evt[moz_var][prop_var] : pJ = evt[ie_var][prop_var];
	prop_var = "gamename";
	evt[moz_var] ? pGameName = evt[moz_var][prop_var] : pGameName = evt[ie_var][prop_var];
	checkField(pGameName,pI,pJ)
}

function checkField(pGameName,pI,pJ)
{
  var larSetRed=getInd4Check(pI,pJ)
  
  var loGameArray=getGameArray(pGameName)
  var checkedValue=loGameArray[pI][pJ]
  var counter=0;
  for(var i=0;i<larSetRed.length;i++)
  {
    loI=larSetRed[i][0]
	loJ=larSetRed[i][1]	
	if(checkedValue==loGameArray[loI][loJ])
	{
	  setRed(getGameField(pGameName,loI,loJ))
	  counter++;
	}
	else
	{
	  removeRed(getGameField(pGameName,loI,loJ))
	}
  }
  if(counter>0) 
  { 
	setRed(getGameField(pGameName,pI,pJ))
	getGameField(pGameName,pI,pJ).focus()
  }else{allRemoveRed(pGameName,pI,pJ)}
}

function isValidGameSolution()
{
  this.initArray=getGameArray(this.gameName)
  return this.isValidMatrix()   
}

function getInd4Check(pI,pJ)
{
  var loInd4Check=new Array()
  for(var i=0;i<9;i++)
  {
    if(pI!=i) loInd4Check[loInd4Check.length]=[i,pJ]
  }
  for(var j=0;j<9;j++)
  {
    if(pJ!=j) loInd4Check[loInd4Check.length]=[pI,j]
  }
  for(var i=getTopIndex(pI);i<=getBottomIndex(pI);i++)
  {
    for(var j=getTopIndex(pJ);j<=getBottomIndex(pJ);j++)
	{	  
	  if ((pJ!=j)&&(pI!=i)) loInd4Check[loInd4Check.length]=[i,j]
	}
  }
  return loInd4Check;
}

function setRed(obj)
{
  obj.style.color="red"
}
function removeRed(obj)
{
  obj.style.color=(true==obj.readOnly)?"black":"#8a8a8a";
}

function initEvents4Fields(pGameName)
{
  for(var i=0;i<9;i++)
  {
    for(var j=0;j<9;j++)
	{
	  getGameField(pGameName,i,j).pi=i
	  getGameField(pGameName,i,j).pj=j
	  getGameField(pGameName,i,j).gamename=pGameName
	  addEvent(getGameField(pGameName,i,j),"change",callCheckField)
	}
  }
}

function addEvent(Obj,evName,evValue)
{
  if(Obj.addEventListener)
  {
    Obj.addEventListener(evName, evValue, false);
  }
  else//ie
  {
    Obj.attachEvent("on"+evName, evValue);
  }
}

var targetInput=null;

function showContextMenu(e)
{
  ns6=!document.all
  var etarget=ns6?e.target:event.srcElement
  var corX=ns6?e.pageX:event.x+document.body.scrollLeft
  var corY=ns6?e.pageY:event.y+document.body.scrollTop
  if (etarget.tagName=="INPUT") 
  {
    targetInput = etarget;
	menuObj = document.getElementById("numbers_menu")
    menuObj.style.top=corY
    menuObj.style.left=corX
    menuObj.style.visibility="visible"
  }
  return false;
}

function setTargetValue(obj)
{  
  if(null!=targetInput)
  {
    if(false==targetInput.readOnly||arguments.length>1) targetInput.value=obj.value
	if(arguments.length>1) 
	{
	  targetInput.className=arguments[1];
	  document.getElementById(targetInput.id).style.color='black'
	  targetInput.readOnly=true
	}
  } 
  checkField(targetInput.gamename,targetInput.pi,targetInput.pj)
  hideContextMenu("");
}

function hideContextMenu(e)
{
  menuObj = document.getElementById("numbers_menu")
  menuObj.style.visibility="hidden"
}

function callsodokoSolver()
{
  var solver = new sodokoSolverMain(getGameArray(this.gameName));
  if(solver.allFree.length>71)
  {
	return;
  }
  cont=true
  while(cont)
  {
    solver.sodokoSolve()
	if(solver.isValidMatrix()) break;
  }
  
  this.solutionArray = solver.initArray
  this.showSolutionGame();
}


function getSolutionArrayFormatted()
{
  arr=getGameArray(this.gameName)
  return getArrayFormatted(arr);
}

function sodokoSolverMain(pInitArray)
{
  this.initArray=pInitArray
  
  this.getAllFree=getAllFree
  this.getNextFree=getNextFree
  this.getPrevFree=getPrevFree
  this.isValidField=isValidField
  this.sodokoSolve=sodokoSolve
  
  this.isValidMatrix=quickIsValidMatrix
  this.quickUniqueMatrix=quickUniqueMatrix
  this.quickSmallMatrix=quickSmallMatrix
  
  this.allFree=new Array();
  this.allFreePointer=-1;
  this.count=-1  
  this.exitCount=0;
  this.getAllFree();
  this.larInd=this.getNextFree();  
  
  this.allPossible=new Array();
  this.getAllPossible=getAllPossible
  this.getPossibleValues=getPossibleValues
  this.getAllPossible(); 
}


function getAllPossible()
{
  for(var i=0;i<this.allFree.length;i++)
  {
    this.allPossible[i]=this.getPossibleValues(this.allFree[i][0],this.allFree[i][1])
  }
}

function getPossibleValues(pI,pJ)
{
  var arrPossible=new Array();
  for (var i=1;i<10;i++)
  {
    this.initArray[pI][pJ]=i;
	if(this.isValidField(pI,pJ))
	{
	  arrPossible[arrPossible.length]=i;
	}
  }
  this.initArray[pI][pJ]="";
  return arrPossible
}

function quickUniqueMatrix(pStart,pEnd)
{
  var numJ=new Array();
  var numJT=new Array();
  for(var i=pStart;i<pEnd;i++)
  {    		
	numJ=new Array();
	numJT=new Array();
	for(var j=pStart;j<pEnd;j++)
	{	  
	  if(""==this.initArray[i][j]||this.initArray[i][j]<1||this.initArray[i][j]>9)
	  {
	    return false;
	  }
	  else
	  {
	    if("x"==numJ[this.initArray[i][j]])
		{
		  return false;
		}
		else
		{
		  numJ[this.initArray[i][j]]="x"
		}
	    if("x"==numJT[this.initArray[j][i]])
		{
		  return false;
		}
		else
		{
		  numJT[this.initArray[j][i]]="x"
		}
	  }	  
	}
  }
  return true;
}

function quickSmallMatrix(pStartI,pStartJ,pEndI,pEndJ)
{
  var numJ=new Array();
  for(var i=pStartI;i<pEndI;i++)
  {    		
	for(var j=pStartJ;j<pEndJ;j++)
	{	  
	  if("x"==numJ[this.initArray[i][j]])
		{
		  return false;
		}
		else
		{
		  numJ[this.initArray[i][j]]="x"
		}
	}
  }
  return true;
}

function quickIsValidMatrix()
{

  if(false==this.quickUniqueMatrix(0,9)) return false;
  if(false==this.quickSmallMatrix(0,0,3,3)) return false;
  if(false==this.quickSmallMatrix(0,3,3,6)) return false;
  if(false==this.quickSmallMatrix(0,6,3,9)) return false;
  
  if(false==this.quickSmallMatrix(3,0,6,3)) return false;
  if(false==this.quickSmallMatrix(3,3,6,6)) return false;
  if(false==this.quickSmallMatrix(3,6,6,9)) return false;
  
  if(false==this.quickSmallMatrix(6,0,9,3)) return false;
  if(false==this.quickSmallMatrix(6,3,9,6)) return false;
  if(false==this.quickSmallMatrix(6,6,9,9)) return false;
    
  return true;  
}


function sodokoSolve()
{
  while (!this.isValidMatrix())
  {
    this.exitCount++;
	if(0==this.exitCount%15000) {return;}
	this.count++;
	
	this.initArray[this.larInd[0]][this.larInd[1]]=this.allPossible[this.allFreePointer][this.count]
	
	if(this.isValidField(this.larInd[0],this.larInd[1]))
	{
	  this.larInd=this.getNextFree();
	  this.count=-1;
	  continue;
	}
	
	while(this.count>=this.allPossible[this.allFreePointer].length-1)
	{
	  this.initArray[this.larInd[0]][this.larInd[1]]="";
	  this.larInd=this.getPrevFree();
	  var c=-1;
	  for(c=0;c<this.allPossible[this.allFreePointer].length;c++)
	  {
	    if(this.allPossible[this.allFreePointer][c]==this.initArray[this.larInd[0]][this.larInd[1]]) break;
	  }  
      this.count=c;
	}					 
  }
}


function isValidField(pI,pJ)
{
  var checkedValue = this.initArray[pI][pJ];
  if(""==checkedValue) return false;
  for(var i=0;i<9;i++)
  {
    if ( (pI!=i)&&(this.initArray[i][pJ]==checkedValue) ) return false;
	if ( (pJ!=i)&&(this.initArray[pI][i]==checkedValue) ) return false;
  }

  for(var i=getTopIndex(pI);i<=getBottomIndex(pI);i++)
  {
    for(var j=getTopIndex(pJ);j<=getBottomIndex(pJ);j++)
	{	  
	  if ( ((pJ!=j)&&(pI!=i))&&(this.initArray[i][j]==checkedValue) ) return false; 
	}
  }
  return true;
}

function getAllFree()
{
  for(var i=0;i<9;i++)
  {
    for(var j=0;j<9;j++)
	{
	  if(""==this.initArray[i][j]) this.allFree[this.allFree.length]=[i,j]
	}
  }
  return null;
}

function getNextFree()
{
  this.allFreePointer++;
  if(this.allFreePointer>this.allFree.length-1)
  {
    this.allFreePointer=this.allFree.length-1;
	return null;
  }  
  return this.allFree[this.allFreePointer]
}

function getPrevFree()
{
  this.allFreePointer--;
  if(this.allFreePointer<0)
  {
    this.allFreePointer=0;
  }  
  return this.allFree[this.allFreePointer]
}

function fillReserved()
{
  var i=-1;
  var c=0;

  while(i<this.numField)
  {
    i++;
	bFill=true;
	while(bFill)
	{
	  ind=getRandom80();
	  corI=this.allFree[ind][0]
	  corJ=this.allFree[ind][1]
	  if(""==this.initArray[corI][corJ])
	  {
	    bValid=true;
		while(bValid)
		{
		  this.initArray[corI][corJ]=c
		  if(this.isValidField(corI,corJ))
		  {
		    bValid=false;
			break;
		  }else
		  {
		    c++;
			if(9<c)
			{
			  c=1;
			  bValid=false;
			  break;
			}
		  }
		}
		if(this.isValidField(corI,corJ)) 
		{
		  bFill = false;
		}else{this.initArray[corI][corJ]=""}
	  }
	}
  }
}


function getDataArrayInit(level,ind)
{
  arr = eval("db_s"+level)

  return arr[ind].arrInit;
}

function getDataArraySolution(level,ind)
{
  arr = eval("db_s"+level)

  return arr[ind].arrSolution;
}

function getRandom99()
{
  r=Math.round(Math.random()*100)
  r=(99<r)?99:r
  return r
}

function getRandomMax(level)
{
  arr = eval("db_s"+level)
  maxInd = arr.length - 1;

  r=Math.round(Math.random()*maxInd)
  r=(maxInd<r)?maxInd:r
  return r
}

function getRandom10()
{
  r=Math.round(Math.random()*10)
  r=(9<r)?9:r
  r=(1>r)?1:r
  return r
}

function getEmptyArray()
{
  var emptyArray=new Array();
  for(var i=0;i<9;i++)
  {
    emptyArray[i]=new Array()
	for(var j=0;j<9;j++)
	{
	  emptyArray[i][j]="";
	}
  }
  return emptyArray;
}

function getTopIndex(pI)
{
  var loI=0;
  if(pI>=0&&pI<=2) loI=0;
  if(pI>=3&&pI<=5) loI=3;
  if(pI>=6&&pI<=8) loI=6;
  return loI;
}

function getBottomIndex(pI)
{
  var loI=0;
  if(pI>=0&&pI<=2) loI=2;
  if(pI>=3&&pI<=5) loI=3;
  if(pI>=6&&pI<=8) loI=8;
  return loI;
}

function getArrayFormatted(arr)
{
  str="=[\n"
  for(var i=0;i<9;i++)
  {
    str+=((i!=0)?",":"")+"["
	for(var j=0;j<9;j++)
	{	  
	  str+=((""==arr[i][j])?'""':arr[i][j])  +((j!=8)?",":"")  	  
	}
	str+="]\n"
  }
  str+="]"
  return str;
}

function getArrayFromSlashes(pStr)
{
  lStr=pStr.replace(/\r\n/gi,"/")
  lStr=lStr.replace(/\//gi,",")
  lStr="new Array("+lStr+")"
  return eval(lStr)  
}

function getDoubleArray(lAr)
{
  retArray=new Array()
  if(lAr.length==81)
  {
    lAr_count=-1
	for(var i=0;i<9;i++)
    {
      retArray[i]=new Array()
	  for(var j=0;j<9;j++)
	  {
	    lAr_count++;
		retArray[i][j]=(0==lAr[lAr_count])?"":lAr[lAr_count]
	  }
    }
  }
  else
  {
   
  }
  return retArray
}
/////////////////////////////////////////////



encodeALPH=new Array()
encodeALPH['']=''
encodeALPH[1]='a'
encodeALPH[2]='b'
encodeALPH[3]='c'
encodeALPH[4]='d'
encodeALPH[5]='e'
encodeALPH[6]='f'
encodeALPH[7]='g'
encodeALPH[8]='h'
encodeALPH[9]='i'

decodeALPH=new Array()
decodeALPH['']=''
decodeALPH['a']=1
decodeALPH['b']=2
decodeALPH['c']=3
decodeALPH['d']=4
decodeALPH['e']=5
decodeALPH['f']=6
decodeALPH['g']=7
decodeALPH['h']=8
decodeALPH['i']=9

CODE_ALPH={enc:encodeALPH, dec:decodeALPH}

function Translator(pCodeObj)
{
  this.codeObj=pCodeObj
  this.encodeMatrix=encodeMatrix
  this.decodeMatrix=decodeMatrix
  this.encodeSym=encodeSym
  this.decodeSym=decodeSym
}
function encodeMatrix(pMatrix)
{
  for(var i=0;i<pMatrix.length;i++)
  {
    for(var j=0;j<pMatrix[i].length;j++)
	{
	  pMatrix[i][j]=this.codeObj.enc[pMatrix[i][j]]
	}
  }
  return pMatrix;
}
function decodeMatrix(pMatrix)
{
  for(var i=0;i<pMatrix.length;i++)
  {
    for(var j=0;j<pMatrix[i].length;j++)
	{
	  pMatrix[i][j]=this.codeObj.dec[pMatrix[i][j]]
	}
  }
  return pMatrix;
}

function encodeSym(pS)
{
  return this.codeObj.enc[pS];
}

function decodeSym(pS)
{
  return this.codeObj.dec[pS];
}



function loadNewGame(goo)
{
 

     levelNum=goo

 loadJSScript(levelNum);
 
 rNum = getRandomMax(levelNum);
 oSudo = new sodokoGame("s","sodoko",getDataArrayInit(levelNum,rNum),getDataArraySolution(levelNum,rNum))
 
}

var loadedArray=new Array()
var loadedArrayFlag=new Array()

function loadJSScript(level)
{

  
  
  sVal=loadedArrayFlag["s"+level]
  if("x"==sVal)
  {
	return;
  }
  else
  {
    loadedArrayFlag["s"+level]="x"
	var req = new ajaxRequest();

	url = "data/data"+level+"soduko.js"
	req.open("GET", url, false);
	req.send("");
	if (req.status == 200) 
	{
	    eval(req.responseText);
		loadedArray["db_s"+level]=eval("db_s"+level);
	}

  }
  
}


function ajaxRequest() 
{

    if (window.XMLHttpRequest) 
	{
        return new XMLHttpRequest();

    } else if (window.ActiveXObject) 
	{
        return new ActiveXObject((navigator.userAgent.toLowerCase().indexOf('msie 5') != -1) ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP');        
    }
	return false;	
};