
// information about the sprites on the screen
var Sprites = {
  sprite1 : {
    moving : false,
		xPos   : 440,
		yPos   : 100,
		Width  : 60,
		Height : 100,
		Follow : true
  },
	sprite2 : {
	  moving : false,
		xPos   : 500,
		yPos   : 100,
		Width  : 60,
		Height : 100,
		Follow : false
	}
}

// arena and screen information
var Screen = {
	Width  : 500,
	Height : 250}
var Arena = {
	xPos        : -250,
	yPos        : 0,
	Width       : 1000,
	Height      : 200,
	Panning     : false,
	getLeftVis  : function() { return Math.abs(this.xPos); },
	getRightVis : function() { return (Math.abs(this.xPos) + Screen.Width); }
}
var Background = {
  back1 : {
    xPos : 450
  },
  back2 : {
    xPos : 450
  },
  back3 : {
    xPos : 450
  }
}

// movements queued up for the sprites to execute
var movementQueue = {
	sprite1 : new Array(),
	sprite2 : new Array()
}

// number of milliseconds to setTimeout when checking movement queue
const MOVEMENT_DELAY = 50;

// log levels
const LOG_GAME = 1;
const LOG_NOTICE = 2;
const LOG_WARNING = 4;
const LOG_ERROR = 8;
const LOG_TESTING_PAN = 16;
const LOG_TESTING_SPRITES = 32;
const LOG_TESTING_CAMERA = 64;

// active logging level
var logLevel = LOG_GAME | LOG_WARNING | LOG_ERROR;
							//| LOG_TESTING_PAN;
							//| LOG_TESTING_SPRITES;
							//| LOG_TESTING_CAMERA;


// test routines
function button1()
{
	panLeft(100);
}

function button2()
{
	oldtest();
}

function button3()
{
	panRight(100);
}

function oldtest()
{
	var s1MoveX = rand(0, 25);
	var s1MoveY = rand(0, 30);
	var s2MoveX = rand(0, 25);
	var s2MoveY = rand(0, 30);
	
	queueMovement('sprite1', -s1MoveX, s1MoveY);
	queueMovement('sprite1', -s1MoveX, -s1MoveY);
	queueMovement('sprite1', -s2MoveX, s2MoveY); //-
	queueMovement('sprite1', -s2MoveX, -s2MoveY); //-
	queueMovement('sprite1', -s1MoveX, s1MoveY);
	queueMovement('sprite1', -s1MoveX, -s1MoveY);
	
	queueMovement('sprite2', s2MoveX, s2MoveY);
	queueMovement('sprite2', s2MoveX, -s2MoveY);
	queueMovement('sprite2', -s1MoveX, s1MoveY);
	queueMovement('sprite2', -s1MoveX, -s1MoveY);
	queueMovement('sprite2', s2MoveX, s2MoveY);
	queueMovement('sprite2', s2MoveX, -s2MoveY);

  queueMovement('sprite1', -s1MoveX, s1MoveY);
  queueMovement('sprite1', -s1MoveX, -s1MoveY);
  queueMovement('sprite1', s2MoveX, s2MoveY);
  queueMovement('sprite1', s2MoveX, -s2MoveY);
  queueMovement('sprite1', -s1MoveX, s1MoveY);
  queueMovement('sprite1', -s1MoveX, -s1MoveY);
  
  queueMovement('sprite2', -s2MoveX, s2MoveY); //-
  queueMovement('sprite2', -s2MoveX, -s2MoveY); //-
  queueMovement('sprite2', -s1MoveX, s1MoveY);
  queueMovement('sprite2', -s1MoveX, -s1MoveY);
  queueMovement('sprite2', -s2MoveX, s2MoveY); //-
  queueMovement('sprite2', -s2MoveX, -s2MoveY); //-
}

/*
 *  Real work begins here
 *
 */

// write a line to the log
function log(/* string to log, [log level (defaults to LOG_NOTICE)] */)
{
  switch(arguments.length)
  {
    case 0 :
  		return;
  		break;
  	case 1 :
  		var level = LOG_NOTICE;
  		break;
  	default :
  		var level = arguments[1];
  		break;
  }
  var str = arguments[0];
  if((logLevel & level) == level)
  	document.getElementById('log').value += str + "\n";
}

// clear the log
function clearLog()
{
  document.getElementById('log').value = '';
}

// generate a random number between "low" and "high"
function rand(low, high)
{
	if(high < 0 || low < 0)
		return 0;

	if(high > low)
		return Math.floor(Math.random() * (high + 1 - low)) + low;
	else
		return low;
}

// queue up a movement for a given sprite
function queueMovement(id, dX, dY)
{
  log('entered queueMovement#' + id + "(" + dX + "," + dY + ")", LOG_TESTING_SPRITES);
  var _id = id;
  var _dX = dX;
  var _dY = dY
	var thisMove = function()
	{
	  //log('entered queueMovement#' + _id + '::thisMove', LOG_TESTING_SPRITES);
		return spriteMove(_id, _dX, _dY, 200, 5, 
											{complete:function() {blinkBorder('#ff0');}});
	}
	if(!thisMove())
	{
	  log('thisMove#' + _id + ' failed; setting timeout to try again', LOG_TESTING_SPRITES);
		movementQueue[id].push(thisMove);
		window.setTimeout("dequeueMovement('" + id + "')", MOVEMENT_DELAY);
	} else {
		log('thisMove#' + _id + ' succeeded');
	}
}

// check if the given sprite is moving; if not, dequeue and execute next move
function dequeueMovement(id)
{
  log('entered dequeueMovement#' + id, LOG_TESTING_SPRITES);
	if(movementQueue[id].length > 0)
	{
		var nextMove = movementQueue[id].shift();
		if(!nextMove())
		{
		  log('nextMove#' + id + ' failed; setting timeout to try again', LOG_TESTING_SPRITES);
			movementQueue[id].unshift(nextMove);
			window.setTimeout("dequeueMovement('" + id + "')", MOVEMENT_DELAY);
		} else {
			log('nextMove#' + id + ' succeeded');
		}
	}
}

// wrapper for Effect.Position that uses relative coordinates instead of
// absolute ones
function spriteMove(id, dX, dY, time, moves, options)
{
  // a sprite in motion cannot accept another motion
  if(Sprites[id].moving)
    return false;

  var _id = id;

  // turn that relative coordinate into an absolute one
	if(dX)
		var X = Sprites[id].xPos + dX;
	else
		var X = null;
	if(dY)
		var Y = Sprites[id].yPos - dY;
	else
		var Y = null;
	
	if(X)
	{
		Sprites[id].xPos = X;
		
		// sprites can have their "Follow" property set to make the camera
		// follow them
		if(Sprites[id].Follow)
		{
		  if(Sprites[id].xPos < Arena.getLeftVis())
		  {
		    // have the camera move left
		    panLeft(Arena.getLeftVis() - Sprites[id].xPos + 20);
		  } else if((Sprites[id].xPos + Sprites[id].Width) > Arena.getRightVis())
		  {
		    // have the camera move right
		    panRight((Sprites[id].xPos + Sprites[id].Width) - Arena.getRightVis() + 20);
		  }
		}
	}
	if(Y)
  	Sprites[id].yPos = Y;
	
	Sprites[id].moving = true;
	new Effect.Position(id, X, Y, time, moves, options);
	
	var notMoving = function() {
		Sprites[_id].moving = false;
	}
	window.setTimeout(notMoving, time);
	
	return true;
}

// move the camera "distance" pixels to the left, but not beyond the left
// boundary
function panLeft(distance)
{
  if(Arena.Panning)
  	return false;

  log('panLeft: new Arena.xPos would be ' + (Arena.xPos + distance), LOG_TESTING_PAN);
	if((Arena.xPos + distance) < 0)
	{
	  Arena.xPos += distance;
	} else {
		distance = -1 - Arena.xPos;
		Arena.xPos = -1;
	}
  log('panLeft: new Arena.xPos is ' + Arena.xPos, LOG_TESTING_PAN);
  Arena.Panning = true;
	new Effect.Position('arena', Arena.xPos, null, 
											distance, Math.floor(distance / 10),
											{complete:function() {Arena.Panning = false;}});
											
	/* parallax scroll code */
/* 	var parallax1 = Math.round(distance * .8); */
/* 	Background['back1'].xPos += parallax1; */
/* 	var parallax2 = Math.round(distance * .6); */
/* 	Background['back2'].xPos += parallax2; */
/* 	var parallax3 = Math.round(distance * .4); */
/* 	Background['back3'].xPos += parallax3; */
/* 	new Effect.Position('back1', Background['back1'].xPos, null,  */
/* 											distance, Math.floor(distance / 10), */
/* 											null); */
/* 	new Effect.Position('back2', Background['back2'].xPos, null,  */
/* 											distance, Math.floor(distance / 10), */
/* 											null); */
/* 	new Effect.Position('back3', Background['back3'].xPos, null,  */
/* 											distance, Math.floor(distance / 10), */
/* 											null); */
  /* end parallax code */

	return true;
}

// move the camera "distance" pixels to the right, but not beyond the right
// boundary
function panRight(distance)
{
	if(Arena.Panning)
		return false;
		
  log('panRight: new Arena.xPos would be ' + (Arena.xPos - distance), LOG_TESTING_PAN);
	if((Arena.xPos - distance) > -(Arena.Width - Screen.Width))
	{
	  Arena.xPos -= distance;
	} else {
		var oldPos = Arena.xPos;
		Arena.xPos = 1 - Arena.Width + Screen.Width;
		distance = oldPos - Arena.xPos;
	}
  log('panRight: new Arena.xPos is ' + Arena.xPos, LOG_TESTING_PAN);
  Arena.Panning = true;
	new Effect.Position('arena', Arena.xPos, null, 
											distance, Math.floor(distance / 10),
											{complete:function() {Arena.Panning = false;}});
	return true;
}

// move the camera back to the center of the window
function panCenter()
{
	if(Arena.Panning)
		return false;
		
	var oldPos = Arena.xPos;
	Arena.xPos = -Math.floor((Arena.Width - Screen.Width) / 2)
	log('panCenter: old Arena.xPos = ' + oldPos, LOG_TESTING_PAN);
	log('panCenter: new Arena.xPos = ' + Arena.xPos, LOG_TESTING_PAN);
	var distance = Math.abs(oldPos - Arena.xPos);
	Arena.Panning = true;
	new Effect.Position('arena', Arena.xPos, null, 
											distance, Math.floor(distance / 10),
											{complete:function() {Arena.Panning = false;}});
	return true;
}

// blinks the bezel in a specified color
function blinkBorder(color)
{
  return;
	_target = document.getElementById('bezel');
	var borderOn = function() {
		_target.style.borderColor = color;
	}
	var borderOff = function() {
		_target.style.borderColor = '#000';
	}
	window.setTimeout(borderOn,  0);
	window.setTimeout(borderOff, 100);
	window.setTimeout(borderOn,  200);
	window.setTimeout(borderOff, 300);
	window.setTimeout(borderOn,  400);
	window.setTimeout(borderOff, 500);
}
