// Lightsout cube source
// (c) 2000 Gareth Richards


function behaveMap(){
	this.behave=null;
	this.event=null;
	this.id=0;
}

var m;
var ev1,ev2,ev3,ev4,ev5,ev6,ev7,ev8,evRot,AboutEvent;
var evv1,evv2,evv3,evv4,evv5,evv6,evv7,evv8;
var	_rotLeft,_rotRight,_rotUp,_rotDown;
var cubeBvh;
var beginTran;

var butTime=.3;
var slowTime=2.0;
var cubeSize=.3;

var cube=new Array(); // the DAGeometry array
var scene;
var camera;

var model=new Array(1,2,3,4,5,6,7,8,9,39,36,33,38,35,32,37,34,31,53,52,51,56,55,54,59,58,57,23,26,29,22,25,28,21,24,27,49,46,43,48,45,42,47,44,41,11,12,13,14,15,16,17,18,19);
var reverse=new Array(0,0,1,2,3,4,5,6,7,8,0,45,46,47,48,49,50,51,52,53,0,33,30,27,34,31,28,35,32,29,0,17,14,11,16,13,10,15,12,9,0,44,41,38,43,40,37,42,39,36,0,20,19,18,23,22,21,26,25,24);
var behavemap=new Array(); // our array of objects
var opabehave;

var loc;
var locm;
var oldloc;

var fullyloaded=false;
var opac;
var opacEvent;

var fadeRed;
var fadeBlue;
var fadeGreen;
var fadeUpRed;
var fadeUpBlue;
var fadeUpGreen;
var fadeRedS;
var fadeBlueS;
var fadeGreenS;
var fadeUpRedS;
var fadeUpBlueS;
var fadeUpGreenS;
var noChange;
var tbut;
var tsbut;
var rotBehave;
var solveMode=false;
var setItMode=false;
var solutionArray;
var OffColor;
var OnColor;
var OnColorAnim;
var OffColorAnim;
var OnColorAnimSlow;
var OffColorAnimSlow;
var NoChangeAnim;

function initEvents(){
	ev1 = m.AppTriggeredEvent();
	evv1=m.OrEvent(ev1,m.KeyDown(0x10025));
	ev2 = m.AppTriggeredEvent();
	evv2=m.OrEvent(ev2,m.KeyUp(0x10025));

	ev3 = m.AppTriggeredEvent();
	evv3=m.OrEvent(ev3,m.KeyDown(0x10027));
	ev4 = m.AppTriggeredEvent();
	evv4=m.OrEvent(ev4,m.KeyUp(0x10027));

	ev5 = m.AppTriggeredEvent();
	evv5=m.OrEvent(ev5,m.KeyDown(0x10026));
	ev6 = m.AppTriggeredEvent();
	evv6=m.OrEvent(ev6,m.KeyUp(0x10026));

	ev7 = m.AppTriggeredEvent();
	evv7=m.OrEvent(ev7,m.KeyDown(0x10028));
	ev8 = m.AppTriggeredEvent();
	evv8=m.OrEvent(ev8,m.KeyUp(0x10028));

	evRot = m.AppTriggeredEvent();
	evRotStart = m.AppTriggeredEvent();
	evRotEnd = m.AppTriggeredEvent();
	evRot2Start = m.AppTriggeredEvent();
	evRot2End = m.AppTriggeredEvent();

	_rotLeft = m.Rotate3RateDegrees(m.YVector3, -75);
	_rotRight = m.Rotate3RateDegrees(m.YVector3, +75);
	_rotUp = m.Rotate3RateDegrees(m.XVector3, -75);
	_rotDown = m.Rotate3RateDegrees(m.XVector3, 75);

	var leftRotBvr = getLeftBvr();			
	var rightRotBvr = getRightBvr();			
	var upRotBvr = getUpBvr();			
	var downRotBvr = getDownBvr();
	var rotateBvr = getRot1Bvr();
	var rotateBvr2= getRot2Bvr();
	cubeRot=m.IdentityTransform3;
	cubeBvh=m.ModifiableBehavior(cubeRot);
	rotbehave=m.Compose3Array(new Array(upRotBvr,downRotBvr,leftRotBvr,rightRotBvr,rotateBvr,rotateBvr2,cubeBvh));
}

function getRot1Bvr(){
	var rotAround = m.Rotate3RateDegrees(m.Vector3(0,-1,-1), -60);	
	return m.Until(m.IdentityTransform3, evRotStart, m.UntilEx(rotAround, m.Timer(1).Snapshot( rotAround ).NotifyScript( "notifier5" )) );
}

function getRot2Bvr(){
	rotAround2 = m.Rotate3RateDegrees(m.Vector3(1,-1,1), -60);	
	return m.Until(m.IdentityTransform3, evRot2Start, m.UntilEx(rotAround2, m.Timer(1).Snapshot( rotAround2 ).NotifyScript( "notifier6" )) );
}

function getLeftBvr(){
	return m.Until(m.IdentityTransform3, evv1, m.UntilEx(_rotLeft, evv2.Snapshot( _rotLeft ).NotifyScript( "notifier1" ) ));
}

function getRightBvr(){
	return m.Until(m.IdentityTransform3, evv3, m.UntilEx(_rotRight, evv4.Snapshot( _rotRight ).NotifyScript( "notifier2" ) ));
}

function getUpBvr(){
	return m.Until(m.IdentityTransform3, evv5, m.UntilEx(_rotUp, evv6.Snapshot( _rotUp ).NotifyScript( "notifier3" ) ));
}

function getDownBvr(){
	return m.Until(m.IdentityTransform3, evv7, m.UntilEx(_rotDown, evv8.Snapshot( _rotDown ).NotifyScript( "notifier4" ) ));
}


function initCube(){
//	try{
		var light = m.DirectionalLight.LightColor(m.ColorRGB255(128, 128, 128));
		var light2 = m.AmbientLight.LightColor(m.ColorRGB255(64, 64, 64));

		var i,j,a;
		var tc;
		var cs=1.5;
		var id;
		var scaleRange;
		var scaleRange1;
		var scaleRange2;
		var mainCube;

		OffColor=m.ColorRGB255(128, 64, 196);
		OnColor=m.Red;

		scaleRange1=m.InterpolateAnim(m.DANumber(.01),m.DANumber(.1),m.DANumber(butTime));
		scaleRange2=m.InterpolateAnim(m.DANumber(.1),m.DANumber(.01),m.DANumber(butTime));

		mainCube=m.ImportGeometry("cube.x");

		for (i=0; i<3; i++){
			for (j=0; j<3; j++){
				scaleRange=new ActiveXObject("DirectAnimation.DANumber");
				tc = mainCube.Transform(m.Scale3Anim(m.DANumber(cubeSize), m.DANumber(cubeSize), scaleRange))
								.Transform(m.Translate3(i-1, j-1, -1*cs));
		       	tc=setBvr(tc);
    			activate(tc,i*3+j,scaleRange,scaleRange1,scaleRange2);
			}
		}

		for (i=0; i<3; i++){
			for (j=0; j<3; j++){
				scaleRange=new ActiveXObject("DirectAnimation.DANumber");
				tc = mainCube.Transform(m.Scale3Anim(m.DANumber(cubeSize), m.DANumber(cubeSize), scaleRange))
								.Transform(m.Translate3(i-1, j-1, +cs))
				tc=setBvr(tc);
				activate(tc,9+i*3+j,scaleRange,scaleRange1,scaleRange2);
			}
		}

		for (i=0; i<3; i++){
			for (j=0; j<3; j++){
				scaleRange=new ActiveXObject("DirectAnimation.DANumber");
				tc = mainCube.Transform(m.Scale3Anim(m.DANumber(cubeSize), scaleRange, m.DANumber(cubeSize)))
								.Transform(m.Translate3(i-1,-1*cs, j-1 ))
				tc=setBvr(tc);
				activate(tc,18+i*3+j,scaleRange,scaleRange1,scaleRange2);
			}
		}

		for (i=0; i<3; i++){
			for (j=0; j<3; j++){
				scaleRange=new ActiveXObject("DirectAnimation.DANumber");
				tc = mainCube.Transform(m.Scale3Anim(m.DANumber(cubeSize), scaleRange, m.DANumber(cubeSize)))
								.Transform(m.Translate3(i-1,cs, j-1 ));
				tc=setBvr(tc);
				activate(tc,27+i*3+j,scaleRange,scaleRange1,scaleRange2);
			}
		}

		for (i=0; i<3; i++){
			for (j=0; j<3; j++){
				scaleRange=new ActiveXObject("DirectAnimation.DANumber");
				tc = mainCube.Transform(m.Scale3Anim(scaleRange, m.DANumber(cubeSize), m.DANumber(cubeSize)))
								.Transform(m.Translate3(-1*cs,j-1,i-1 ));
				tc=setBvr(tc);
				activate(tc,36+i*3+j,scaleRange,scaleRange1,scaleRange2);
			}
		}

		for (i=0; i<3; i++){
			for (j=0; j<3; j++){
				scaleRange=new ActiveXObject("DirectAnimation.DANumber");
				tc = mainCube.Transform(m.Scale3Anim(scaleRange, m.DANumber(cubeSize), m.DANumber(cubeSize)))
								.Transform(m.Translate3(cs,j-1, i-1 ));
				tc=setBvr(tc);
				activate(tc,45+i*3+j,scaleRange,scaleRange1,scaleRange2);
			}
		}
		cube[54] = mainCube.Transform(m.Scale3(cs, cs, cs)).SpecularColor(m.ColorRGB255(128, 128, 128));

		opac = new ActiveXObject("DirectAnimation.DANumber");
		opacEvent=m.AppTriggeredEvent();
		toSolid=m.InterpolateAnim(m.DANumber(0.5),m.DANumber(1.0),m.DANumber(2.0));
		toOpac=m.InterpolateAnim(m.DANumber(1.0),m.DANumber(.5),m.DANumber(2.0));

		opac.Init( m.Until( toSolid, opacEvent, m.Until( toOpac, opacEvent, opac )));
		cube[54]=setBvr(cube[54].OpacityAnim( opac ));

		cube[55]=light;
		cube[56]=light2;
		
//	}
//	catch(e){
//		alert("Failed "+e);
//	}
}

function directXinit(){

// set up the cube
	oldloc=new LightsOutCube();
	loc=new LightsOutCube();
	locm=new LightsOutCubeModel();
	locm.init();

	m = DA.MeterLibrary;
	opac = m.DANumber(0.5);
	
	initEvents();
	initCube();
	initColorAnim();
	
	fullyloaded=true;
	fnStartInitPuzzle();

	scene = m.UnionGeometryArray(cube);

	camera  = m.PerspectiveCamera(10,5).Transform(m.Scale3(55, 55, 1));

// The about text
	AboutEvent=m.AppTriggeredEvent();
	period = 5;  // in seconds

	var BackColor=m.ColorRGB255(128, 196, 128);
	hueNum = m.Div(m.LocalTime, m.DANumber(period));  //m.LocalTime/period
	basicClr = m.ColorHslAnim(hueNum, m.DANumber(0.5), m.DANumber(0.5));
	textClr = new ActiveXObject("DirectAnimation.DAColor");
	textClr.Init(m.Until(BackColor, AboutEvent,m.Until(basicClr, m.Timer(10), textClr)));
	font = m.DefaultFont.Size(15.0).Color(textClr);
	textImg = m.TextImage("Lightsout Cube (C) 2000 Gareth Richards", font).Transform(m.Translate2(.01,-.055));

	var backGround=m.Overlay(textImg,m.SolidColorImage(BackColor))
// put it all together
	DA.Image = m.Overlay(scene.render(camera), backGround);

	DA.Start();
}

function setBvr(x){
	return x.Transform(rotbehave);
}

function activate(unpickedGeo,x,sr,r1,r2){

	var pickImg = unpickedGeo.Pickable();
	var myEvent = m.AndEvent(m.LeftButtonDown, pickImg.pickEvent);

	sr.Init( m.Until( r1, myEvent, m.Until( r2, m.Timer(butTime),  sr )));
	var b=m.ModifiableBehavior( m.UntilEx(OffColor, myEvent.ScriptCallback( "f("+x+")","JScript" )));
	cube[x]=pickImg.Geometry.DiffuseColor(b);
	var bm=new behaveMap();
	bm.behave=b;
	bm.event=myEvent;
	bm.id=model[x];
	behavemap[x]=bm;
}


function isLightChanged(old,newl,but){
	return !(((old.high & but.high)==(newl.high & but.high)) && ((newl.low & but.low)==(old.low & but.low)));
}

var bclrs,rclrs;
var bclrsDA,rclrsDA;
var bclr,rclr;


function CreateColorAnim(SCol,ECol,Time){
	var fadeColorRed=m.InterpolateAnim(m.DANumber(SCol.Red.Extract()),m.DANumber(OffColor.Red.Extract()),m.DANumber(Time));
	var fadeColorBlue=m.InterpolateAnim(m.DANumber(SCol.Blue.Extract()),m.DANumber(OffColor.Blue.Extract()),m.DANumber(Time));
	var fadeColorGreen=m.InterpolateAnim(m.DANumber(SCol.Green.Extract()),m.DANumber(OffColor.Green.Extract()),m.DANumber(Time));
	
	var fRed = new ActiveXObject("DirectAnimation.DANumber");
	fRed.Init( m.Until( fadeColorRed, tbut, m.DANumber(0)));
	var fBlue = new ActiveXObject("DirectAnimation.DANumber");
	fBlue.Init( m.Until( fadeColorBlue, tbut, m.DANumber(0)));
	var fGreen = new ActiveXObject("DirectAnimation.DANumber");
	fGreen.Init( m.Until( fadeColorGreen, tbut, m.DANumber(0)));
	
	return m.ColorRgbAnim(fRed,fBlue,fGreen);
}


function initColorAnim(){
	tbut=m.Timer(butTime*2);
	tsbut=m.Timer(slowTime);

	var noColor=m.InterpolateAnim(m.DANumber(0.0),m.DANumber(0.0),m.DANumber(butTime*2));

	noChange = new ActiveXObject("DirectAnimation.DANumber");
	noChange.Init( m.DANumber(0.0));

	bclrs = new Array( OnColor, m.Yellow);
	rclrs = new Array( OffColor, m.Yellow);
	bclrsDA = m.Array(bclrs);
	rclrsDA = m.Array(rclrs);
  	index = m.Floor(m.Mod(m.LocalTime, m.DANumber(bclrs.length)));
	bclr = bclrsDA.NthAnim(index);
	rclr = rclrsDA.NthAnim(index);
	
	OnColorAnim=CreateColorAnim(OffColor,OnColor,butTime*2);
	OffColorAnim=CreateColorAnim(OnColor,OffColor,butTime*2);
	OnColorAnimSlow=CreateColorAnim(OffColor,OnColor,slowTime);
	OffColorAnimSlow=CreateColorAnim(OnColor,OffColor,slowTime);
	NoChangeAnim=CreateColorAnim(OnColor,OnColor,butTime);
}



function setCube(slow,full){
	tloc=new LightsOutCube();
	var ii,x,b,jj,t,upBlue,upRed,bLightChanged;

	if (slow){
		t=tsbut;
		upOn=OnColorAnimSlow;
		upOff=OffColorAnimSlow;
		solvedMode=false;
	}else{
		t=tbut;
		upOn=OnColorAnim;
		upOff=OffColorAnim;
	}
	for (ii=1;ii<60;ii++){
		tloc.low=0;
		tloc.high=0;
		if (ii%10 != 0){
			locm.tog1(ii,tloc);
			bLightChanged=isLightChanged(oldloc,loc,tloc);
			if (bLightChanged || full){ // check for no change
				var jj=reverse[ii];
				var bm=behavemap[jj];
				if (bLightChanged) {
					if (((loc.high & tloc.high) | (loc.low & tloc.low))!=0){
						b=m.UntilEx(OnColor, bm.event.ScriptCallback( "f("+jj+")","JScript" ));
				  		bm.behave.SwitchTo(m.Until(upOn , t, b));
					}
					else{
						b=m.UntilEx(OffColor, bm.event.ScriptCallback( "f("+jj+")","JScript" ));
				  		bm.behave.SwitchTo(m.Until(upOff, t, b));
					}
				}
				else {
					if (((loc.high & tloc.high) | (loc.low & tloc.low))!=0){
						b=m.UntilEx(OnColor, bm.event.ScriptCallback( "f("+jj+")","JScript" ));
				  		bm.behave.SwitchTo(b);
					}
					else{
						b=m.UntilEx(OffColor, bm.event.ScriptCallback( "f("+jj+")","JScript" ));
				  		bm.behave.SwitchTo(b);
					}
				}
			}
			
		}
	}

	if (solvedMode){
		for (i=0; i<solutionArray.length; i++){
			ii=solutionArray[i];
			var jj=reverse[ii];
			tloc.low=0;
			tloc.high=0;
			locm.tog1(ii,tloc);
			var bm=behavemap[jj];
			if (((loc.high & tloc.high) | (loc.low & tloc.low))!=0){
				b=m.UntilEx(bclr, bm.event.ScriptCallback( "f("+jj+")","JScript" ));
			  	bm.behave.SwitchTo(b);
			}
			else{
				b=m.UntilEx(rclr, bm.event.ScriptCallback( "f("+jj+")","JScript" ));
			  	bm.behave.SwitchTo(b);
			}		
		}
	}
}

function notifier1(edata, cur)  {
	cubeRot = m.Compose3(edata,cubeRot);
	cubeBvh.SwitchTo(cubeRot);
	return getLeftBvr();
}

function notifier2(edata, cur)  {
	cubeRot = m.Compose3(edata,cubeRot);
	cubeBvh.SwitchTo(cubeRot);
	return getRightBvr();
}

function notifier3(edata, cur)  {
	cubeRot = m.Compose3(edata,cubeRot);
	cubeBvh.SwitchTo(cubeRot);
	return getUpBvr();
}

function notifier4(edata, cur)  {
	cubeRot = m.Compose3(edata,cubeRot);
	cubeBvh.SwitchTo(cubeRot);
	return getDownBvr();
}

function notifier5(edata, cur)  {
	cubeRot = m.Compose3(edata,cubeRot);
	cubeBvh.SwitchTo(cubeRot);
	m.TriggerEvent( evRot2Start, m.DANumber(0) );
	return getRot1Bvr();	
}

function notifier6(edata, cur)  {
	cubeRot = m.Compose3(edata,cubeRot);
	cubeBvh.SwitchTo(cubeRot);
	return getRot2Bvr();
}

function f(x){
	oldloc.low=loc.low;
	oldloc.high=loc.high;
	var i=behavemap[x].id;
	if (setItMode)
		locm.tog1(i,loc);
	else
		locm.tog5(i,loc);
	if (solvedMode){
		setSolvedButton(i);
	}
	setCube(false,false);
	if (loc.low==0 && loc.high==0){
		m.TriggerEvent( evRotStart, m.DANumber(0) );
		solvedMode=false;
		var selPuz=document.getElementById("selPuzzle");
		setCookie("Level",selPuz.value);
		setPuzzle(selPuz.value);
		changePuzzle();
	}
}

function setTransparent(v){
	cube[54].SwitchTo( m.Gray.Opacity( v ));
}

function TogTransparency(){
	m.TriggerEvent( opacEvent, m.DANumber(0) );
}

function togSetup(){
	setItMode=(setItMode==false);
}

function StartRotateLeft(){
	m.TriggerEvent( ev1, m.DANumber(0) );
}
function StopRotateLeft(){
	m.TriggerEvent( ev2, m.DANumber(0) )
}

function StartRotateRight(){
	m.TriggerEvent( ev3, m.DANumber(0) );
}
function StopRotateRight(){
	m.TriggerEvent( ev4, m.DANumber(0) )
}

function StartRotateUp(){
	m.TriggerEvent( ev5, m.DANumber(0) );
}
function StopRotateUp(){
	m.TriggerEvent( ev6, m.DANumber(0) )
}

function StartRotateDown(){
	m.TriggerEvent( ev7, m.DANumber(0) );
}
function StopRotateDown(){
	m.TriggerEvent( ev8, m.DANumber(0) )
}

function resetCube(){
	solvedMode=false;
	changePuzzle();
}

function solveCube(){
	var locs=new LightsOutCubeSolver();
	var d1=new Date() ;
	var res=locs.solve(loc);
	var d2=new Date();
	if (res){
		solvedMode=true;
		var i;
		solutionArray=locm.dumpArray(locs.solution);
		setCube();
	}
	else
		alert("No Solution");
}

function setSolvedButton(x){
	var i;
	for (i=0; i<solutionArray.length; i++){
		if (solutionArray[i]==x){
			solutionArray.splice(i,1);
			return;
		}
	}
	solutionArray.push(x);
}

function about(){
	m.TriggerEvent( AboutEvent, m.DANumber(0) );
}

function rotate(){
	m.TriggerEvent( evRotStart, m.DANumber(0) );
}
