/*
(c) Spellcoder (Mark de Jong) in 2009
*/
function blexeffectmanager()
{
  this.effects = [];                    // references to all effect instances

  this.timerrunning  = false;
  this.interval      = 50;
  this.intervalevent = null;
}

blexeffectmanager.prototype.addtochain = function(effectinstance)
{
  this.effects[this.effects.length] = effectinstance;

  _effectmanager = this;

//  this.activate();
}

blexeffectmanager.prototype.updateall = function()
{
  var ecount = this.effects.length;

  //console.log('Processing '+ecount+' active animations.');

  while(ecount-- > 0)
  {
    if (this.effects[ecount].active)
      this.effects[ecount].update(this.interval);

    if (this.effects[ecount].finished)
    {
      this.effects[ecount] = null; // FIXME: do we want to kill all used effects?
      this.effects.splice(ecount, 1)
    }
  }

  // if there are no effects to animate anymore throw away our interval timer
  if (this.effects.length == 0)
  {
    //console.log('No animations left, shutting down timer.');
    clearInterval(this.intervalevent);
    this.timerrunning = false;
  }
}

// call when we want to make sure our timer is running
blexeffectmanager.prototype.activate = function()
{
  if (!this.timerrunning)
  {
    //console.log('Starting animation timer.');
    this.timerrunning = true;
    this.intervalevent = setInterval( function() { _effectmanager.updateall() }, this.interval);
  }
}

effectmanager = new blexeffectmanager;




function blexeffect(options)
{
  this.options  = options;
  this.runtime  = 0;
  this.finished = false;
  this.activate = false;
  this.reverse  = false;

  this.onfinish = options.onfinish;

  // TODO: write synchronized single-reflow/repaint version if we ever need many effects at once

  this.precalc();
  
  effectmanager.addtochain(this);
}

blexeffect.prototype.precalc = function()
{
	for(var effectnr=0; effectnr < this.options.effects.length; effectnr++)
	{
		var effect = this.options.effects[effectnr];
	
		switch (effect.effect)
		{
			case 'fade':		break;

			case "setpxonprop":	break;
								
			case 'move':		break;

			case 'colorfade':	if (!effect.startcolors)
								{
									effect.startcolors = this.hexToRGB(effect.startvalue);
									effect.endcolors = this.hexToRGB(effect.endvalue);
								}
								
								if (effect.startcolors.alpha && !usingIE) // FIXME... IE will give JS errors when trying to use RGBA
								  effect.isrgba = true;

								break;
		}
	}
}

/* give 24 bit HEX as in FF00FF (without #) */
blexeffect.prototype.hexToRGB = function(hexstr)
{
	// TODO: check length, if 6 then RGB, if 8 the RGBA

	return	{ red:		parseInt(hexstr.substr(0,2), 16)
			, green:	parseInt(hexstr.substr(2,2), 16)
			, blue:		parseInt(hexstr.substr(4,2), 16)
			}
/*
Doesn't work in IE. Can't use array style access to seperate characters in a string.
	return	{ red:		parseInt(hexstr[0]+hexstr[1], 16)
			, green:	parseInt(hexstr[2]+hexstr[3], 16)
			, blue:		parseInt(hexstr[4]+hexstr[5], 16)
			}
*/
}

blexeffect.prototype.restart = function(settings)
{
  this.runtime = 0;
  this.start(settings);
}

blexeffect.prototype.start = function(settings)
{
  for(sname in settings)
	this.options[sname] = settings[sname];

  if (!this.options.element)
  {
    console.log('Cannot activate effect. No element was given.');
    return;
  }

  this.active = true;
  this.reverse = false;
  
  effectmanager.activate();
  
  this.update(0, true); // force initial animation start
}

blexeffect.prototype.startReverse = function(settings)
{
  for(sname in settings)
	this.options[sname] = settings[sname];

  if (!this.options.element)
  {
    console.log('Cannot activate effect. No element was given.');
    return;
  }

  this.active = true;
  this.reverse = true;
  
  effectmanager.activate();

  this.update(0, true); // force initial animation start
}

blexeffect.prototype.stop = function(settings)
{
  this.active = false;
}

blexeffect.prototype.kill = function()
{
  this.finished = true; // flag to be removed by effectmanager
  this.active = false;
  this.element = null;
}

blexeffect.prototype.update = function(interval, forcedupdate)
{
	if (!forcedupdate) // at initial start an update is forced to prevent flashes
	{
	  if (this.reverse)
	  {
	    this.runtime -= interval;

	    if (this.runtime < 0)
	      this.runtime = 0;
	  }
	  else
	  {
	    this.runtime += interval;

	    if (this.runtime > this.options.duration)
	      this.runtime = this.options.duration;
	  }
	}
	
	  // http://www.javafx.com/samples/SpringAnimation/

	  switch(this.options.method)
	  {
		case 'sqrt':	var effectstringth = Math.sqrt(10000 + x * x) + 100;
						break;

		case 'linear':  var effectstrength = this.runtime / this.options.duration;
	                    break;

		case 'sin':
	    default:        var effectstrength = Math.sin(Math.PI / 2 * this.runtime / this.options.duration);
	                    break;
	  }
	  
	for(var effectnr=0; effectnr < this.options.effects.length; effectnr++)
	{
		var effect = this.options.effects[effectnr];
	
		switch (effect.effect)
		{
			case 'fade':		var newopacity = effect.startvalue + (effect.endvalue - effect.startvalue) * effectstrength;
								setOpacity(this.options.element, newopacity);
								break;

			case "setpxonprop":	var newvalue = effect.startvalue + (effect.endvalue - effect.startvalue) * effectstrength;
								this.options.element.style[effect.prop] = newvalue+'px';
								break;
								
			case 'move':		var doXmove = (typeof effect.startX != 'undefined') && (typeof effect.endX != 'undefined');
								var doYmove = (typeof effect.startY != 'undefined') && (typeof effect.endY != 'undefined');
								
								if (doXmove)
									var newX = effect.startX + (effect.endX - effect.startX) * effectstrength;
								
								if (doYmove)
									var newY = effect.startY + (effect.endY - effect.startY) * effectstrength;

								if (doXmove)
									if (effect.hook == 'left')
										this.options.element.style.left = newX+'px';
									else if (effect.hook == 'right')
										this.options.element.style.right = newX+'px';
										
								if (doYmove)
									this.options.element.style.top = newY+'px';

								break;

			case 'colorfade':	var curr = effect.startcolors.red   + (effect.endcolors.red   - effect.startcolors.red)   * effectstrength;
								var curg = effect.startcolors.green + (effect.endcolors.green - effect.startcolors.green) * effectstrength;
								var curb = effect.startcolors.blue  + (effect.endcolors.blue  - effect.startcolors.blue)  * effectstrength;

								// Firefox doesn't like R/G/B as floats in colors.

								if (effect.isrgba)
								{
									var cura = effect.startcolors.alpha  + (effect.endcolors.alpha - effect.startcolors.alpha) * effectstrength;
									var colorstring = 'rgba('+Math.round(curr)+', '+Math.round(curg)+', '+Math.round(curb)+', '+cura+')';
									this.options.element.style[effect.prop] = colorstring;
								}
								else
								  this.options.element.style[effect.prop] = 'rgb('+Math.round(curr)+', '+Math.round(curg)+', '+Math.round(curb)+')';

								break;
			
			default:			console.log('Unknown transistion effect setting.');
								break;
		}
	}

//	console.log(this.reverse+ ' runtime: '+this.runtime);
	
  if ((!this.reverse && (this.runtime == this.options.duration))
       ||this.reverse && (this.runtime == 0))
  {
 // console.log('finishing');
//    effectmanager.removefromchain(this);
//    this.finished = true; // flag to be removed by effectmanager
	this.active = false;

    if (this.options.onfinish)
      this.options.onfinish();
  }
}

blexeffect.prototype.toHex = function () {
	var r = this.r.toString(16);
	var g = this.g.toString(16);
	var b = this.b.toString(16);
	if (r.length == 1) r = '0' + r;
	if (g.length == 1) g = '0' + g;
	if (b.length == 1) b = '0' + b;
	return '#' + r + g + b;
}
