globals.board=null;
globals.timer=0;
globals.paused=false;
constants.minimumBoardSize=4;
constants.maximumBoardSize=16;
constants.deltaX=[0,1,0,-1];
constants.deltaY=[-1,0,1,0];
constants.opposite=[2,3,0,1];
constants.directionCount=4;
globals.title="Pipes";
globals.instructions="Rotate the cells until all cells in the grid are interconnected and 'lit' (colored green).  To rotate a cell, simply click on it.  To 'lock' or 'unlock' a cell(locked cells are colored differently), hold down control while clicking.";
function getCellElement(x,y)
{
	return(document.getElementById("cell_"+x+"_"+y));
}
function clickCell(x,y,event)
{
	if(event.ctrlKey)
	{
		globals.board.getCell(x,y).locked=!globals.board.getCell(x,y).locked;
		globals.board.getCell(x,y).update();
	}
	else
	{
		globals.paused=false;
		globals.board.turnCell(x,y);
	}
}
generator["play"]=function()
{
	var result="";
	for(var y=0;y<globals.board.height;++y)
	{
		for(var x=0;x<globals.board.width;++x)
		{
			result+="<img style=\"position:absolute;left:"+x*32+";top:"+y*32+";clip:rect(0px 32px 32px 0px);\" id=\"cell_"+x+"_"+y+"\" onclick=\"clickCell("+x+","+y+",event);\" onmouseover=\"globals.board.setCellSelected("+x+","+y+",true);\" onmouseout=\"globals.board.setCellSelected("+x+","+y+",false)\" src=\"images/jspipes/tileset.png\">";
		}
	}
	result+="<div style=\"position:absolute;top:"+globals.board.height*32+"\">";
	result+="<p id=\"timer\">Time: "+globals.timer+"</p>";
	result+="</div>";
	return(result);
}
function Cell(x,y)
{
	this.x=x;
	this.y=y;
    this.locked=false;
    this.selected=false;
	this.lit=false;
	this.neighbors=new Array();
	this.directions=new Array();
    for(var index=0;index<constants.directionCount;++index)
    {
        this.neighbors.push(null);
        this.directions.push(false);
    }
	this.update=function()
	{
	    var cellImage = getCellElement(this.x,this.y);
		if(cellImage!=null)
		{
			var value=this.getValue();
			cellImage.style.left=this.x*32-(value&15)*32;
			cellImage.style.top=this.y*32-Math.floor(value/16)*32
			cellImage.style.clip="rect("+Math.floor(value/16)*32+"px "+((value&15)*32+32)+"px "+(Math.floor(value/16)*32+32)+"px "+(value&15)*32+"px)";
			//cellImage.src="images/"+this.getFileName();
		}
	}
	this.getValue=function()
	{
		return(
			(this.directions[0]?(1):(0))+
			(this.directions[1]?(2):(0))+
			(this.directions[2]?(4):(0))+
			(this.directions[3]?(8):(0))+
			(this.lit?(16):(0))+
			(this.locked?(32):(0))+
			(this.selected?(64):(0))
		);
	}
    this.rotateCW=function()
    {
        var temp=this.directions[constants.directionCount-1];
        for(var index=constants.directionCount-1;index>0;--index)
        {
            this.directions[index]=this.directions[index-1];
        }
        this.directions[0]=temp;
    }
    this.rotateCCW=function()
    {
        var temp=this.directions[0];
        for(var index=0;index<constants.directionCount-1;++index)
        {
            this.directions[index]=this.directions[index+1];
        }
        this.directions[constants.directionCount-1]=temp;
    }
    this.scramble=function()
    {
        var turns=new Array();
        var originalValue=this.getValue();
        for(var index=0;index<constants.directionCount;++index)
        {
            if(originalValue!=this.getValue()) turns.push(index);
            this.rotateCW();
        }
        if(turns.length>0)
        {
            turns=turns[Math.floor(Math.random()*turns.length)];
            while(turns>0)
            {
                this.rotateCW();
                turns--;
            }
        }
        else
        {
            this.locked=true;
        }
    }
    this.light=function()
    {
        if(!this.lit)
        {
            this.lit=true;
            for(var direction=0;direction<constants.directionCount;++direction)
            {
                if(this.directions[direction]&&this.neighbors[direction]!=null&&this.neighbors[direction].directions[constants.opposite[direction]])
                {
                    this.neighbors[direction].light();
                }
            }
        }
    }
}
function Board(width,height)
{
	this.width=width;
	this.height=height;
	this.cells = new Array();
	var y;
	var x;
	for(y=0;y<height;++y)
	{
		this.cells.push(new Array());
		for(x=0;x<width;++x)
		{
			this.cells[y].push(new Cell(x,y));
            if(y>0)
            {
                this.cells[y][x].neighbors[0]=this.cells[y-1][x];
                this.cells[y-1][x].neighbors[2]=this.cells[y][x];
            }
            if(x>0)
            {
                this.cells[y][x].neighbors[3]=this.cells[y][x-1];
                this.cells[y][x-1].neighbors[1]=this.cells[y][x];
            }
		}
	}
	this.setCellSelected = function (x,y,value)
	{
	    this.getCell(x,y).selected=value;
	    this.getCell(x,y).update();
	}
	this.turnCell = function (x,y)
	{
	    if(this.getCell(x,y).locked) return;
	    this.getCell(x,y).rotateCW();
	    this.light();
	    if(this.getLitCount()==this.width*this.height) 
	    {
	        this.setCellSelected(x,y,false);
			clearInterval(globals.timerId);
	        setGameState("solved");
	    }
	    this.update();
	}
	this.getCell=function(x,y)
	{
		return(this.cells[y][x]);
	}
	this.getLitCount=function()
	{
	    var result=0;
	    for(var y=0;y<this.height;++y)
	    {
	        for(var x=0;x<this.width;++x)
	        {
	            if(this.getCell(x,y).lit)result++;
	        }
	    }
	    return(result);
	}
	this.clearLights=function()
	{
	    for(var y=0;y<this.height;++y)
	    {
	        for(var x=0;x<this.width;++x)
	        {
	            this.getCell(x,y).lit=false;
	        }
	    }
	}
	this.update=function()
	{
	    for(var y=0;y<this.height;++y)
	    {
	        for(var x=0;x<this.width;++x)
	        {
	            this.getCell(x,y).update();
	        }
	    }
	}
	this.scramble=function()
	{
		for(var y=0;y<this.height;++y)
		{
			for(var x=0;x<this.width;++x)
			{
				this.getCell(x,y).scramble();
			}
		}
	}
	this.light=function()
	{
		this.clearLights();
		this.getCell(Math.floor(this.width/2),Math.floor(this.height/2)).light();
	}
	this.generate=function()
	{
		var litCount=this.getLitCount();
		if(litCount<(this.width*this.height))
		{
		    var x=Math.floor(Math.random()*this.width);
	        var y=Math.floor(Math.random()*this.height);
	        if((litCount>0)&&(!this.getCell(x,y).lit)) return(false);
	        if(!this.getCell(x,y).lit)
	        {
	            this.getCell(x,y).lit=true;
	        }
	        var passable=new Array(constants.directionCount);
	        var direction=0;
	        var found=false;
	        for(direction=0;direction<constants.directionCount;++direction)
	        {
	            if(this.getCell(x,y).neighbors[direction]==null) continue;
	            if(this.getCell(x,y).neighbors[direction].lit) continue;
	            passable[direction]=true;
	            found=true;
	        }
	        if(found)
	        {
	            do
	            {
	                direction=Math.floor(Math.random()*passable.length);
	            }
	            while(!passable[direction]);
	            this.getCell(x,y).directions[direction]=true;
	            x+=constants.deltaX[direction];
	            y+=constants.deltaY[direction];
	            direction=constants.opposite[direction];
	            this.getCell(x,y).directions[direction]=true;
	            this.getCell(x,y).lit=true;
				return(true);
	        }
			else
			{
				return(false);
			}
		}
		else
		{
			return(false);
		}
	}
}
generator["generate"]=function()
{
	var result="Generating Board...."+Math.floor((globals.board.getLitCount()*100)/(globals.board.width*globals.board.height))+"%";
	setTimeout("generate()",0);
	return(result);
}
function incrementTimer()
{
	if(!globals.paused)
	{
		globals.timer++;
	}
	document.getElementById("timer").innerHTML="Time: "+globals.timer;
}
function generate()
{
	if(globals.board.getLitCount()==globals.board.width*globals.board.height)
	{
		globals.board.clearLights();
		globals.board.scramble();
		globals.board.light();
		setGameState("play");
		globals.board.update();
		globals.timer=0;
		globals.paused=true;
		globals.timerId=setInterval("incrementTimer();",1000);
	}
	else
	{
		while(!globals.board.generate()){}
		refreshGameState();
	}
}
function startGame()
{
	var size=Number(document.getElementById("boardSize").value);
	globals.board=new Board(size,size);
	setGameState("generate");
}
generator["solved"]=function()
{
	var result="";
	for(var y=0;y<globals.board.height;++y)
	{
		for(var x=0;x<globals.board.width;++x)
		{
			result+="<img style=\"position:absolute;left:"+x*32+";top:"+y*32+";clip:rect(0px 32px 32px 0px);\" id=\"cell_"+x+"_"+y+"\" src=\"images/jspipes/tileset.png\">";
		}
	}
	result+="<div style=\"position:absolute;top:"+globals.board.height*32+"\">";
	result+="<p id=\"timer\">Total Time: "+globals.timer+"</p>";
    result+="<p><button onclick=\"setGameState('start');\">Play Again</button></p>";
	result+="</div>";
	return(result);
}
generator["start"]=function()
{
	var result="";
	result+="<p>Select Board Size:";
	result+="<select id=\"boardSize\">";
	for(var index=constants.minimumBoardSize;index<=constants.maximumBoardSize;++index)
	{
		result+="<option value=\""+index+"\""+((globals.board!=null&&index==globals.board.width)?(" selected"):(""))+">"+index+"x"+index;
	}
	result+="</select>";
	result+="<button onclick=\"startGame();\">Start Game</button>";
	result+="</p>";
	return(result);
}
setGameState("title");