var gDoneButton;
var gInfoButton;
//arays of values for each wheel - here they are all the same but needn't be. Should be a prime number of entries, otherwise it may not be solvable!
v1 = new Array("evo5.jpg", "evo8.jpg", "evo9.jpg", "evo7.jpg", "evo10.jpg", "evo12.jpg", "evo13.jpg", "evo11.jpg", "evo1.jpg", "evo2.jpg", "evo3.jpg", "evo4.jpg", "evo6.jpg"); 
v2 = new Array("evo5.jpg", "evo8.jpg", "evo9.jpg", "evo7.jpg", "evo10.jpg", "evo12.jpg", "evo13.jpg", "evo11.jpg", "evo1.jpg", "evo2.jpg", "evo3.jpg", "evo4.jpg", "evo6.jpg");  
v3 = new Array("evo5.jpg", "evo8.jpg", "evo9.jpg", "evo7.jpg", "evo10.jpg", "evo12.jpg", "evo13.jpg", "evo11.jpg", "evo1.jpg", "evo2.jpg", "evo3.jpg", "evo4.jpg", "evo6.jpg");  
v4 = new Array("evo5.jpg", "evo8.jpg", "evo9.jpg", "evo7.jpg", "evo10.jpg", "evo12.jpg", "evo13.jpg", "evo11.jpg", "evo1.jpg", "evo2.jpg", "evo3.jpg", "evo4.jpg", "evo6.jpg");   
v5 = new Array("evo5.jpg", "evo8.jpg", "evo9.jpg", "evo7.jpg", "evo10.jpg", "evo12.jpg", "evo13.jpg", "evo11.jpg", "evo1.jpg", "evo2.jpg", "evo3.jpg", "evo4.jpg", "evo6.jpg");   

//set up matrices: mat1 will be moves of each button: eg if mat1[2][4]=3,  clicking the 2nd button will move wheel 4 by 3
//mat3 is a copy of mat1 for solving, mat2 will hold the results. 
mysize=4; 
mat1 = new Array(mysize); 
mat2 = new Array(mysize); 
mat3= new Array(mysize); 
for (i=0;i<mysize;i++) { 
	mat1[i]=new Array(mysize); 
	mat2[i]=new Array(mysize); 
	mat3[i]=new Array(mysize); 
} 

var i1, i2, i3, i4, i5,num1,num2,num3,num4,level=0,nwins=0,ntries=0,haveTried=false,hasWon; 

//possible words for this game: wordarray1 is start, 2 is the target


function getIndex(c1, arr1) {
	// returns the index of c1 in arr1
	ind = -1;
	for(i=0;i<arr1.length;i++) {
		if (c1==arr1[i]) {
			ind=i;
			break;
		}
	}
	return ind;
}

function setupMat() {
	//creates a matrix mat1 which determines the effects the buttons will have on each wheel
	//uses a random method, but diagonal is never 0!
	//the harder the level, the more non zero elements there will be (ie the more interactions between the wheels)
	for(i=0;i<f1.r1.length;i++) {
		if(f1.r1[i].checked) level=i;
	}
	do {
		for(i=0;i<mysize;i++) { 
        	for(j=0;j<mysize;j++) { 
				rnd = Math.floor(Math.random()*2)+1;
				sign = Math.floor(Math.random()*2)*2-1;
				if(Math.floor(Math.random()*(mysize))<level+1) {
					levfac=1;
				} else {
					levfac=0;
				}
                if(i==j) { 
					mat1[i][j]= 1 *rnd*sign;
                } else { 
					mat1[i][j]=rnd*sign*levfac; 
                } 
        	} 
		} 
		//alert(mat1[0]+"\n"+mat1[1]+"\n"+mat1[2]+"\n"+mat1[3]+"\n"+mat1[4]+"\n")
	} while (!solveit())
}

function initialise() { 
	//get random number:
	num1=Math.floor(Math.random()*13);
	num2=Math.floor(Math.random()*13);
	num3=Math.floor(Math.random()*13);
	num4=Math.floor(Math.random()*13);
	haveTried=false;
	setupMat();
	reset();
	
}

function mySetup() {
	getLevel();	
	tries.innerText = "Tries: " + ntries + ", Wins: " + nwins; 
	initialise();
}

function getLevel() {
	if (!level || level.length == 0) level=0;
	for(i=0;i<f1.r1.length;i++) {
		f1.r1[i].checked=false;
	}
	f1.r1[level].checked=true;
}

function setLevel() {
	for(i=0;i<f1.r1.length;i++) {
		if(f1.r1[i].checked) level=i;
	}
}


function reset() {
	//resets wheels to start values
	i1=num1;//getIndex(wordarray1[n][0],v1); 
	i2=num2;//getIndex(wordarray1[n][1],v2); 
        i3=num3;//getIndex(wordarray1[n][2],v3); 
			i4=num4;//getIndex(wordarray1[n][3],v4); 
				hasWon=false;
				winmess.innerText="";
				winmess2.innerText="";
				setValues();  
} 

function setValues() { 
	//sets the values of the wheels and start/target
	w1.src=v1[i1]; 
	w2.src=v2[i2]; 
	w3.src=v3[i3]; 
	w4.src=v4[i4]; 
} 

function minimiseRow(r1,r2) {
	//find lowest common denominator of two rows and reduces them by this
	primes = new Array(2,3,5,7,11,13,17,19,23,29,31);
	for(x=0;x<primes.length;x++) {
		done=false
		while(!done) {
			for(y=0;y<r1.length;y++) {
				if (r1[y]%primes[x]!=0 || r2[y]%primes[x]!=0) {
					done=true;
					break;
				}
			}
			if(!done) {
				for(y=0;y<r1.length;y++) {
					r1[y]=r1[y]/primes[x];
					r2[y]=r2[y]/primes[x];
				}
			}
		}
	}
}

function solveit() { 
	//does gaussian elimination to figure out which button combinations equate to movement of just one wheel returns true if solvable - results in mat3; returns false if no solution exists
	//IE, after solveit() has run (and returned true), mat3 will be a diagonal matrix with the elements representing how many clicks of a wheel can be acheived by the combination of clicks given by that row in mat2
	//IE if mat3[2][2] is 1, mat2[2]=0,1,-2,0,1, clicking button 2 once, button 3 -2 times, button 5 once will turn wheel 2 by 1 and not affect any of the other wheels.
	
	//copy matrix and build answer matrix
	for(i=0;i<mysize;i++) { 
        for(j=0;j<mysize;j++) { 
			mat3[i][j]=mat1[i][j]; 
			if(i==j) { 
				mat2[i][j]=1 
			} else { 
				mat2[i][j]=0 
			} 
        } 
	} 
	
	//do bottom left of matrix
	for(j=0;j<mysize;j++) { 
		//check if diagonal is 0. If so try and swap with a lower row where it isn't zero
		if(mat3[j][j]==0) { 
			solvable=false;
			for(i=j+1;i<mysize;i++) {
				if(mat3[i][j]!=0) {
					solvable=true;
					for(z=0;z<mysize;z++) { 
						swap1 = mat3[j][z];
						swap2 = mat2[j][z];
						mat3[j][z] = mat3[i][z];
						mat2[j][z] = mat2[i][z];
						mat3[i][z] = swap1;
						mat2[i][z] = swap2;
					} 
				}
			}
			if(!solvable) return false;
		}
		//walk down column, eliminating term under diagonal
        for(i=j+1;i<mysize;i++) { 
			if(mat3[i][j]!=0) { 
				fac1 = mat3[j][j]; 
				fac2 = mat3[i][j];
				for(z=0;z<mysize;z++) { 
					mat3[i][z]=mat3[i][z]*fac1-mat3[j][z]*fac2 
					mat2[i][z]=mat2[i][z]*fac1-mat2[j][z]*fac2 
				} 
				minimiseRow(mat3[i],mat2[i]);
			} 
        }  
	} 
	
	//Now do top right of matrix
	for(j=mysize-1;j>=0;j--) { 
        if(mat3[j][j]==0) { 
			solvable=false;
			for(i=j-1;i>=0;i--) {
				if(mat3[i][j]!=0) {
					solvable=true;
					for(z=0;z<mysize;z++) { 
						swap1 = mat3[j][z];
						swap2 = mat2[j][z];
						mat3[j][z] = mat3[i][z];
						mat2[j][z] = mat2[i][z];
						mat3[i][z] = swap1;
						mat2[i][z] = swap2;
					} 
				}
			}
			if(!solvable) return false;
		}
        for(i=j-1;i>=0;i--) { 
			if(mat3[i][j]!=0) { 
				fac1 = mat3[j][j]; 
				fac2 = mat3[i][j];
				for(z=0;z<mysize;z++) { 
					mat3[i][z]=mat3[i][z]*fac1-mat3[j][z]*fac2 
					mat2[i][z]=mat2[i][z]*fac1-mat2[j][z]*fac2 
				} 
				minimiseRow(mat3[i],mat2[i]);
			} 
        } 
	} 
	//return true as this is solvable
	return true;
} 

function cheat() {
	//shows results of gaussian elimination matrix
	alert(mat3[0][0]+"; "+mat2[0]+"\n"+mat3[1][1]+"; "+mat2[1]+"\n"+mat3[2][2]+"; "+mat2[2]+"\n"+mat3[3][3]+"; "+mat2[3]+"\n") 
}

function checkSolution() { 
	if (!haveTried) {
		haveTried=true;
		addTry();
	}
	//see if current wheel values match target
	if(i1==8 && i2==9 && i3==10 && i4==11) { 
		//alert("well done!!"); 
		//initialise(); 
		addWin();
	} 
	if(i1==12 && i2==12 && i3==12 && i4==12) { 
		//alert("well done!!"); 
		//initialise(); 
		addWin();
	} 

} 

function addWin() {
	nwins++;
	tries.innerText = "Tries: " + ntries + ", Wins: " + nwins; 
	hasWon=true;
	winmess.innerText="Win!";
	winmess2.innerText="Win!";
}

function addTry() {
	ntries++;
	tries.innerText = "Tries: " + ntries + ", Wins: " + nwins; 
}

function rotate(i,x) { 
	//turn the wheels: x represnts + or -, i is which button was clicked
	if(!hasWon) {
		if(x==1) { 
			i1=(v1.length+i1+mat1[i][0])%v1.length 
			i2=(v2.length+i2+mat1[i][1])%v2.length 
			i3=(v3.length+i3+mat1[i][2])%v3.length 
			i4=(v4.length+i4+mat1[i][3])%v4.length 
			i5=(v5.length+i5+mat1[i][4])%v5.length 
		} else { 
			i1=(v1.length+i1-mat1[i][0])%v1.length 
			i2=(v2.length+i2-mat1[i][1])%v2.length 
			i3=(v3.length+i3-mat1[i][2])%v3.length 
			i4=(v4.length+i4-mat1[i][3])%v4.length 
			i5=(v5.length+i5-mat1[i][4])%v5.length 
		} 
		
		setValues(); 
		checkSolution(); 
	} 
}
