var START_LENGTH = 4;
var START_X = 20;
var START_Y = 15;

function Coordinate(x,y)
{
	this.x = x;
    this.y = y;
}

var boardManager =
{    
    width: 32,
    height: 24,
    snakeMaxLength: Math.floor(32*24/2),
    currentLab: 0,
    score: 0,
    bestScore: 0,

    bloc: false,
    
    init: function()
    {
		this.bloc = blocManager.createBloc("snakeBloc", "Snake", "", function() {boardManager.closeSnake()}, 200, 0, 200, 360, 200, 60, 500, 360);
		dom.addEvent(document, "keydown", function(event) { snakeManager.handleKey(event); });
		var container = this.bloc.contentElement;
		var snakeDiv = dom.addElement(container, "div");
		snakeDiv.id = "snakeBoard";
		
    	var table = dom.addElement(dom.addElement(snakeDiv, "table"), "tbody");  
      	for (var j=0; j<this.height; j++)
      	{
        	var tr = dom.addElement(table, "tr");
        	for (var i=0; i<this.width; i++)
        	{
          		var td = dom.addElement(tr, "td");
          		td.id = this.getBoardElementId(i, j);
          		td.className = "off";
          		dom.addEvent(td, "click", function() { boardManager.toggle(this) });
        	}
      	}
      	
      	var parameterDiv =  dom.addElement(container, "form");
      	parameterDiv.id = "snakeParameters";

		var start = dom.addElement(parameterDiv, "button");
		start.setAttribute("type", "button");
		dom.addText(start, "Start");
		dom.addEvent(start, "click", function() { snakeManager.startStop(); return false;});


      	var speedLabel = dom.addElement(parameterDiv, "label");
      	dom.addText(speedLabel, "Vitesse ");
      	var speedSelect = dom.addElement(speedLabel, "select");
      	dom.addEvent(speedSelect, "change", function() {snakeManager.changeWaitTime(this.options[this.selectedIndex].value); this.blur();});
		for (var i=1; i<10; i++)
		{
			var option = dom.addElement(speedSelect, "option");
			option.value = 100 - 10 * i;
			if (i==7)
			{
				option.selected = "selected";
			}
			dom.addText(option, i);
		}
		var lablabel = dom.addElement(parameterDiv, "label");
		dom.addText(lablabel, "Labyrinthe ");
		var labselect = dom.addElement(lablabel, "select");
		dom.addEvent(labselect, "change", function() { boardManager.changeLab(this.options[this.selectedIndex].value); this.blur();});

		var opt0 = dom.addElement(labselect, "option");
		opt0.selected = "selected";
		opt0.value = 0;
		dom.addText(opt0, "Aucun");

		var opt1 = dom.addElement(labselect, "option");
		opt1.value = 1;
		dom.addText(opt1, "Ferm?");
		
		var opt2 = dom.addElement(labselect, "option");
		opt2.value = 2;
		dom.addText(opt2, "Simple");
		
		var scoreDiv = dom.addElement(container, "div");
		scoreDiv.id = "snakeScore";
		var dl = dom.addElement(scoreDiv, "dl");
		var scoredt = dom.addElement(dl, "dt");
		dom.addText(scoredt, "Score");
		var scoredd = dom.addElement(dl, "dd");
		scoredd.id = "snakeCurrentScore";
		dom.addText(scoredd, "0");
		var bestdt = dom.addElement(dl, "dt");
		dom.addText(bestdt, "Best Score");
		var bestdd = dom.addElement(dl, "dd");
		bestdd.id = "snakeBestScore";
		dom.addText(bestdd, "0");

      	this.resetBoard();
    },
    
    closeSnake: function()
    {
		snakeManager.running = false;
    	blocManager.removeBloc(this.bloc);
    	this.bloc = false;
		moduleManager.unloadModule("snake");
    },
    
    resetBoard: function()
    {
      	if (this.score > this.bestScore)
      	{
        	alert("Best Score !");
        	this.bestScore =  this.score;
        	dom.get("snakeBestScore").childNodes[0].data = this.bestScore;
      	}
      	this.score = 0;

      	for (var j=0; j<this.height; j++)
      	{
        	for (var i=0; i<this.width; i++)
        	{
          		var c = new Coordinate(i,j);
	            this.updateBoard(c, "off");
        	}
      	}

      	snakeManager.resetSnake();
      	this.drawLab();
      	this.putMouse();
    },
    
    increaseScore: function()
    {
		this.score += 100 - snakeManager.waitTime;
    	dom.get("snakeCurrentScore").childNodes[0].data = this.score;
    },
    
    toggle: function(element)
    {
      	if (element.className=="off")
      	{
        	element.className="wall";
      	}
      	else if (element.className=="wall")
      	{
        	element.className="off";
      	}
    },
    
    putMouse: function()
    {
      	var c;
      
      	do
      	{
        	var x = Math.floor(Math.random()* this.width);
        	var y = Math.floor(Math.random()* this.height);
        	c = new Coordinate(x,y);
      	} while (!this.isEmpty(c));
      
      	this.updateBoard(c, "mouse");
    },
    
    changeLab: function(i)
  	{
    	this.currentLab = i;
    	this.resetBoard();
  	},
  	
  	    win: function()
    {
      	alert("win... Score : " + this.score);
      	this.resetBoard();
    },
    
    loose: function()
    {
      	alert("loose... Score : " + this.score);
      	this.resetBoard();
    },
    
    drawLab: function()
    {
      	eval("boardManager.drawLab" + this.currentLab + "()");
    },
    
    drawLab0: function() {},
    
    drawLab1: function()
    {
      	this.hWall(0, this.width, 0);
      	this.vWall(this.width-1, 0, this.height);
      	this.hWall(0, this.width, this.height-1);
      	this.vWall(0, 0, this.height);
    },
    
    drawLab2: function()
    {
      	this.hWall(Math.floor(this.width/4), Math.floor(3*this.width/4), Math.floor(this.height/2));
    },
    
    
    hWall: function(startX, endX, y)
    {
      	for (var i=startX; i<endX; i++)
      	{
        	var c = new Coordinate(i,y);
        	this.updateBoard(c, "wall");
      	}
    },
    
    vWall: function(x, startY, endY)
    {
      	for (var j=startY; j<endY; j++)
      	{
        	var c = new Coordinate(x,j);
        	this.updateBoard(c, "wall");
      	}
    },
    
    hasMouse: function(c)
    {
      	return this.getBoardElementAt(c).className == "mouse";      
    },
    
    isEmpty: function(c)
    {
      	return this.getBoardElementAt(c).className == "off";      
    },
    
    updateBoard: function(c, styleClass)
    {
      	this.getBoardElementAt(c).className = styleClass;      
    },
    
    getBoardElementAt: function(c)
    {
      return dom.get(this.getBoardElementId(c.x, c.y));
    },
    
    getBoardElementId: function(x, y)
    {
      return "board" + x + "-" + y;
    }
}

var snakeManager = 
{
    waitTime: 30,
    theSnake: false,
    running: false,
    
    resetSnake: function()
    {
    	this.running = false;
      	this.theSnake = new Snake();
    },

    run: function()
    {
      	this.running = true;
      	this.runSnake();
    },
    
    stop: function()
    {
      	this.running = false;
    },
    
    startStop: function()
    {
      	if (this.running)
      	{
        	this.stop();
      	}
      	else
      	{
        	this.run();
      	}
    },
    
    up: function()
    {
      	this.theSnake.changeDirection(0, -1);
    },
    
    down: function()
    {
      	this.theSnake.changeDirection(0, 1);
    },
    
    left: function()
    {
      	this.theSnake.changeDirection(-1, 0);
    },
    
    right: function()
    {
      	this.theSnake.changeDirection(1, 0);
    },
    
    runSnake: function()
    {
      	if (this.running)
      	{
        	this.theSnake.ramp();
        	window.setTimeout("snakeManager.runSnake()", this.waitTime)
      	}
    },
    
    handleKey: function(event)
    {
		if (!event)
		{
			event = window.event;
		}
      	switch (event.keyCode)
      	{
        	case 37:
          		this.left();
          		break;
        	case 38:
          		this.up();
          		break;
        	case 39:
          		this.right();
          		break;
        	case 40:
          		this.down();
          		break;
        	default:
          		return true;// alert(event.keyCode);
      	}
      	return false;
    },

  	changeWaitTime: function(newWaitTime)
  	{
    	this.waitTime = parseInt(newWaitTime);
  	}
    
}
    
	function Snake()
	{
      	this.positions = new Array(boardManager.snakeMaxLength);
      	this.tailIndex = 0;
      	this.headIndex = START_LENGTH;
      	this.xDirection = 1;
      	this.yDirection = 0;
      	this.oldXDirection = 1;
      	this.oldYDirection = 0;
      	this.wall = false;
      	
      
      	this.getTailStyle = function()
      	{
      		var currentC = this.getPosition(this.tailIndex);
      		var newC = this.getPosition((this.tailIndex + 1)%boardManager.snakeMaxLength);
      		var xDir = newC.x - currentC.x;
      		var yDir = newC.y - currentC.y;

      		return "tail" + xDir + "" + yDir;
      	}
      	
      	this.getBodyStyle = function()
      	{
      		return "body" + this.xDirection + "" + this.yDirection + "" + this.oldXDirection + "" + this.oldYDirection;
      	}

      	this.getHeadStyle = function()
    	{
      		return "head" + this.xDirection + "" + this.yDirection;
    	}
      	
      
      	this.setPosition = function(index, x, y)
        {
      		while (x<0)
      		{
        		x+=boardManager.width;
      		}
      		x = x%boardManager.width;
      
      		while (y<0)
      		{
        		y+=boardManager.height;
      		}
      		y = y%boardManager.height;
      
      		this.positions[index] = new Coordinate(x, y);
    	}
      
      
      	this.getPosition = function(index)
        {
      		return this.positions[index];
    	}
      
      	this.ramp = function()
    	{
      		var c = this.getPosition(this.headIndex);
      		var newHeadIndex = (this.headIndex + 1)%boardManager.snakeMaxLength;
      		this.setPosition(newHeadIndex, c.x + this.xDirection, c.y + this.yDirection);
      
      		if (!boardManager.hasMouse(this.getPosition(newHeadIndex)))
      		{
        		if (!boardManager.isEmpty(this.getPosition(newHeadIndex)))
        		{
          			if (this.wall)
          			{
            			boardManager.loose();
          			}
          			else
          			{
            			this.wall = true;
          			}
          			return;
        		}
        		else
       			{
          			boardManager.updateBoard(this.getPosition(this.tailIndex), "off");
          			this.tailIndex = (this.tailIndex + 1)%boardManager.snakeMaxLength;
          			boardManager.updateBoard(this.getPosition(this.tailIndex), this.getTailStyle());
        		}
      		}
      		else
      		{
        		boardManager.increaseScore();
        		boardManager.putMouse();
      		}
      
      		this.wall = false;
      
      		if (this.tailIndex == this.headIndex)
     		{
        		boardManager.win();
        		return;
      		}

      		boardManager.updateBoard(c, this.getBodyStyle());
      		this.headIndex = newHeadIndex;
      		boardManager.updateBoard(this.getPosition(this.headIndex), this.getHeadStyle());
      
      		this.oldXDirection = this.xDirection;
      		this.oldYDirection = this.yDirection;
    	}
      
      	this.changeDirection = function(x, y)
    	{
      		if (x == -this.xDirection || y == -this.yDirection || this.oldXDirection != this.xDirection || this.oldYDirection != this.yDirection)
      		{
        		return;
      		}
      		else
      		{
        		this.oldXDirection = this.xDirection;
        		this.oldYDirection = this.yDirection;
        		this.xDirection = x;
        		this.yDirection = y;
      		}
    	}
      
      
      	for (var i=this.tailIndex + 1; i<this.headIndex; i++)
      	{
        	this.setPosition(i, START_X + i, START_Y);
        	boardManager.updateBoard(this.getPosition(i), this.getBodyStyle());
      	}

      	this.setPosition(this.tailIndex, START_X, START_Y);
      	boardManager.updateBoard(this.getPosition(this.tailIndex), this.getTailStyle());

      	this.setPosition(this.headIndex, START_X + this.headIndex, START_Y);
      	boardManager.updateBoard(this.getPosition(this.headIndex), this.getHeadStyle());
    }
    
function snakeInit()
{
	boardManager.init();
}

