"use strict";

var canvas = document.getElementById('game');
var context = canvas.getContext('2d');

//a global singleton instance of the game
var game = 
{
  state: "start",
  level: 0,
  timestep : 0.1
};

//a global singleton instance of dog
var dog = 
{
  x: 100,
  y: 300,
  mass: 1,
  vx: 1,
  vy: 0,
  width: 45,
  height: 40,
  counter: 0
};

//Sheep class
function Sheep (x,y,vx,vy,w,h,mass,view_radius)
{
  this.x=x;
  this.y=y;
  this.vx=vx;
  this.vy=vy;
  this.width=w;
  this.height=h;
  this.mass=mass;
  this.view_radius=view_radius;
  this.state="moving" //either moving or in_goal or in_obst
  this.radius=10;
}

function ob_circle(x,y,radius,color)
{
  this.x=x;
  this.y=y;
  this.radius=radius;
  this.color=color;
}

function ob_box(x,y,w,h,angle,color)
{
  this.x=x;
  this.y=y;
  this.width=w;
  this.height=h;
  this.angle=angle;  //degree
  this.color=color;
}

function goal(x,y,radius)
{
	this.x=x;
	this.y=y;
	this.radius=radius;
	this.sheep_ingoal=0; //no sheep in the goal
}

//////////////////////////////////////////////////////////
// Level 0
var level_0 =
{
	obst_boxes : [new ob_box(200,200,20,200,18,"#777777"), new ob_box(20,200,200,20,80,"#777777")],
	obst_circles : [new ob_circle(500,400,50,"#555555")],
	startPosition : {x:10, y:20},
	goal : new goal(400,40,100),
	flockSize: 10
};

//////////////////////////////////////////////////////////
// add more levels here
//////////////////////////////////////////////////////////

//TODO, 10 pts: Design 3 more interesting environments with increasing difficult 

var levels=[level_0];

//TODO, 5 pts: Add a time out function so that the game is over if the sheepdog
//             does not herd all sheep into the pen

//////////////////////////////////////////////////////////

var flock = [];
var keyboard = {};

//////////////////////////////////////////////////////////
// Assets
//////////////////////////////////////////////////////////
var dog_image;
var sheep_image;
var dog_sound;
var sheep_sound;
var play_again_sound;
var goal_sound;


var textOverlay = 
{
  counter: -1,
  title: "",
  subtitle: ""
};


function gameLoop() 
{
  //update
  updateGameState();  //check the game state 
  updateBackground(); //do nothing currently
  updateFlock();      //update the location of the flock (controlled by ODE)
  updateDog();        //update the location of the dog (controlled by user)

  //render
  drawBackground();
  drawLevel(levels[game.level]);
  drawDog();
  drawFlock(flock);
  drawTextOverlay();
}

function updateGameState() 
{
  if(game.state === "playing" && levels[game.level].goal.flocksize === levels[game.level].flockSize ) {
    game.state = "won";
    textOverlay.title = "Leve cleared. All sheep in the pen";
    
    //
    if(game.level+1<levels.length)
	    textOverlay.subtitle = "Press space bar to play the next level";
	else
		textOverlay.subtitle = "Congratulations! You have finished all levels";
    
    play_again_sound.play();
  }

  // time out
  if(game.state === "over" && keyboard[32]) 
  {
    game.state = "start";
    play_again_sound.pause();
    play_again_sound.currentTime = 0;
  }

  //level up
  if(game.state === "won" && keyboard[32]) {
    game.state = "start";
    if(game.level+1<levels.length) game.level++;

    play_again_sound.pause();
    play_again_sound.currentTime = 0;
  }

  if(textOverlay.counter >= 0 ) {
    textOverlay.counter++;
  }
}

function updateBackground() 
{
  // do nothing
}

//check if a given point is inside obstacles of a given level
function insideObst(level, p)
{
	//loop through the circles
	for(var i=0;i<level.obst_circles.length;i++){
		if(insideCircle(level.obst_circles[i],p)) return true;
	}
	
	//loop through the boxes
	for(var i=0;i<level.obst_boxes.length;i++){
		if(insideBox(level.obst_boxes[i],p)) return true;
	}
		
	return false;
}


function updateFlock() 
{
  	// populate flock array
  	if(game.state === "start") 
  	{

    	flock = []; // be sure to reset the flock array when starting a new game
    	for(var iter = 0; iter < levels[game.level].flockSize; iter++) 
    	{
    	    //
    		// TODO (5pts): replace the following code so that
    		// sheep starts around levels[game.level].startPosition
    		//
    		var p={x:Math.random()*canvas.width, y:Math.random()*canvas.height};
    		
    		if( insideObst(levels[game.level],p) ) //inside obst...
    		{
    			--iter;
    			continue;
    		}
    		
    		var vx=(Math.random()>0.5)?Math.random():-Math.random();
    		var vy=(Math.random()>0.5)?Math.random():-Math.random();    		
    		var nv=normalize({x:vx,y:vy});
    		
			//Sheep (x,y,vx,vy,w,h,mass,view_radius)
      		flock.push(new Sheep(p.x,p.y,nv.x,nv.y,25,25,1,50));
    	}
    	game.state = "playing";
	}
	else //in play
	{		
		levels[game.level].goal.sheep_ingoal=0;
			
		//update the position of the flock here...
		
		var active_flock=[];
		
		for(var iter in flock) 
		{
		
			var member = flock[iter];
			
			if(member.state==="in_goal")
			{
				//move to the center of the goal
				var goal=levels[game.level].goal;
				var vec=subtract(goal,member);
				if(normsqr(vec)>0.1)
				{
					var tangent={x:vec.y+vec.x/10,y:-vec.x+vec.y/10};
					member.x=member.x+tangent.x*game.timestep;
					member.y=member.y+tangent.y*game.timestep;		
				}
				
				levels[game.level].goal.sheep_ingoal++;
			}
			else if(member.state==="in_obst")
			{
				//do nothing now
			}
			else 
			{
				active_flock.push(member);
			}
			
		}//end for each sheep
		
		//Call updateFlockState here:
		//
		//updateFlockState(active_flock,dog,levels[game.level],game.timestep);
		//
						
		//now we handle active sheep
		for(var iter in active_flock) 
		{	
			var member = active_flock[iter];
			
			//-------------------------------------------------------------
			//TODO: you should replace the code below with your  
			//updateFlockState after it is implemented	
			//
			//-------------------------------------------------------------				
			member.x=member.x+member.vx*game.timestep;
			member.y=member.y+member.vy*game.timestep;			
			var r=10;
			if(member.x<r) member.x=r;
			if(member.x>canvas.width-r) member.x=canvas.width-r;	
			if(member.y<r) member.y=r;
			if(member.y>canvas.height-r) member.y=canvas.height-r;
			//-------------------------------------------------------------
			//TODO: you should replace the code above with your  
			//updateFlockState after it is implemented
			//-------------------------------------------------------------								
			
			
			//-------------------------------------------------------------	
			// In class: play sound when the dog is in the view area of the sheep
			//-------------------------------------------------------------	
			var distsqr= normsqr(subtract(member,dog));
			if( distsqr< member.view_radius*member.view_radius )
			{
				sheep_sound.play();
			}
			
			if( insideCircle(levels[game.level].goal, member) ) 
			{ 
				member.state="in_goal"; 
				goal_sound.play(); //this is a bit annoying...
			}
			else if( insideObst(levels[game.level], member) ) member.state="in_obst";
		
		}//end for each active sheep

	}//end if game state
}

function updateDog() 
{

	//bark
	if(keyboard[32]) 
	{
		dog_sound.play(); 
	}

  
  // move left
  if(keyboard[37]) {
    dog.x -= 2;
    if(dog.x < dog.width/2) { 
      dog.x = dog.width/2;
    }
  }
  
  // move down
  if(keyboard[38]) {
    dog.y -= 2;
    if(dog.y <dog.height/2) { 
      dog.y = dog.height/2;
    }
  }

  // move right 
  if(keyboard[39]) {
    dog.x += 2;
    var right = canvas.width - dog.width/2;
    if(dog.x > right) {
      dog.x = right;
    }
  }
  
  // move up
  if(keyboard[40]) {
      dog.y += 2;
    var top=canvas.height - dog.height/2;
    if(dog.y > top) { 
      dog.y = top;
    }
  }
}

function addEvent(node, name, func) 
{
  if(node.addEventListener) {
    node.addEventListener(name, func, false);
  } else if(node.attachEvent) {
    node.attachEvent(name, func);
  }
}

function addKeyboardEvents() 
{
  addEvent(document, "keydown", function(e) 
  {
    keyboard[e.keyCode] = true;
  });

  addEvent(document, "keyup", function(e) 
  {
    keyboard[e.keyCode] = false;
  });

}

function playSound(file) 
{
  var sound = document.createElement("audio");
  sound.setAttribute("src", "sounds/" + file + ".wav");
  sound.play();
}

function loadResources() 
{
  dog_image = new Image();
  dog_image.src = 'images/dog.png';
  
  sheep_image = new Image();
  sheep_image.src = 'images/sheep.png';

  sheep_sound = document.createElement("audio");
  document.body.appendChild(sheep_sound);
  sheep_sound.setAttribute("src", "sounds/sheep.mp3");

  dog_sound = document.createElement("audio");
  document.body.appendChild(dog_sound);
  dog_sound.setAttribute("src", "sounds/dog_bark.mp3");
  
  goal_sound = document.createElement("audio");
  document.body.appendChild(goal_sound);
  goal_sound.setAttribute("src", "sounds/appear.mp3");

  play_again_sound = document.createElement("audio");
  document.body.appendChild(play_again_sound);
  play_again_sound.setAttribute("src", "sounds/darkfactory.mp3");

}

//-----------------------------------------------------------------------------
//start the Game here
//-----------------------------------------------------------------------------

//listen to keyboard events
addKeyboardEvents();

//load assets
loadResources();

//enter game loop
setInterval(gameLoop, 1000 / 60);


