 /* 
 * Yuichi Tateno. <hotchpotch@N0!spam@gmail.com> 
 * http://rails2u.com/ 
 *  
 * The MIT License 
 * -------- 
 * Copyright (c) 2007 Yuichi Tateno. 
 *  
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal 
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions: 
 *  
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 * THE SOFTWARE. 
 * 
 */ 
function addSetterGetter (obj){
    obj.isAddSetterGetter = true;
    obj.__defineGetter__('x',function(){return this.translate[0]});
    obj.__defineSetter__('x',function(v){this.translate[0]=v});
    obj.__defineGetter__('y',function(){return this.translate[1]});
    obj.__defineSetter__('y',function(v){this.translate[1]=v});
    obj.__defineGetter__('z',function(){return this.translate[2]});
    obj.__defineSetter__('z',function(v){this.translate[2]=v});
    obj.__defineGetter__('rotationr',function(){return this.rotation[0]});
    obj.__defineSetter__('rotationr',function(v){this.rotation[0]=v});
    obj.__defineGetter__('rotationx',function(){return this.rotation[1]});
    obj.__defineSetter__('rotationx',function(v){this.rotation[1]=v});
    obj.__defineGetter__('rotationy',function(){return this.rotation[2]});
    obj.__defineSetter__('rotationy',function(v){this.rotation[2]=v});
    obj.__defineGetter__('rotationz',function(){return this.rotation[3]});
    obj.__defineSetter__('rotationz',function(v){this.rotation[3]=v});
    obj.__defineGetter__('scalex',function(){return this.scale[0]});
    obj.__defineSetter__('scalex',function(v){this.scale[0]=v});
    obj.__defineGetter__('scaley',function(){return this.scale[1]});
    obj.__defineSetter__('scaley',function(v){this.scale[1]=v});
    obj.__defineGetter__('fontsize',function(){return this.font_size;});
    obj.__defineSetter__('fontsize',function(v){this.font_size = v; setf_text (this, this.text);});
    obj.__defineGetter__('colr',function(){return this.color[0];});
    obj.__defineSetter__('colr',function(v){this.color[0] = v;});
    obj.__defineGetter__('colg',function(){return this.color[1];});
    obj.__defineSetter__('colg',function(v){this.color[1] = v;});
    obj.__defineGetter__('colb',function(){return this.color[2];});
    obj.__defineSetter__('colb',function(v){this.color[2] = v;});
    obj.__defineGetter__('cola',function(){return this.color[3];});
    obj.__defineSetter__('cola',function(v){this.color[3] = v;});
}

function dotween (obj, options){
    var defaultOptions = {time:1, delay:0, transition:'easeNone', onComplete: undefined, onCompleteParams: undefined};
    var interval = 50;
    var obj = obj || this;
    if (!obj.isAddSetterGetter)
	addSetterGetter (obj);
    obj.opt = {};
    obj.param = {};
    if (options === 'undefined'){
	return;
    }
    for (var key in defaultOptions)
    {
        if (typeof options[key] != 'undefined') { 
	    obj.opt[key] = options[key];
	    delete options[key]; 
	}
	else{
	    obj.opt[key] = defaultOptions[key];
	}
    }
    for (var key in options){
	obj.param[key] = {};
	obj.param[key].s = obj[key];
	obj.param[key].d = options[key] - obj[key];
    }    
    obj.stopcount = obj.opt.time*1000/interval;

    var run = function(){
	append_timer (obj, interval, 
		      function(obj, count){
			  var func = JSTweener.easingFunctions[obj.opt.transition];
			  for (var key in obj.param){
			      obj[key] = func (count, 
					       obj.param[key].s, obj.param[key].d,
					       obj.stopcount);
			  }
			  if(count === obj.stopcount){
			      delete_timer(obj);
			      if (typeof obj.opt.onComplete == 'function') {
				  if (obj.opt.onCompleteParams) { 
				      obj.opt.onComplete.apply(obj, obj.opt.onCompleteParams); 
	            		  } else {
				      obj.opt.onComplete(obj); 
				  }
			      }
			  }
			  force_redraw();
		      }
		     );
    }
    if(obj.opt.delay == 0){
	run ();
    } else {
	append_timer (obj, obj.opt.delay*1000, function(obj,count){run();});
    }
}

var JSTweener = { 
    looping: false, 
    frameRate: 50, 
    objects: [], 
    defaultOptions: { 
        time: 1, 
        transition: 'easeOutQuad', 
        delay: 0, 
        prefix: {}, 
        suffix: {}, 
        onStart: undefined, 
        onStartParams: undefined, 
        onUpdate: undefined, 
        onUpdateParams: undefined, 
        onComplete: undefined, 
        onCompleteParams: undefined 
    }, 
    inited: false, 
    easingFunctionsLowerCase: {}, 
    init: function() { 
        this.inited = true; 
        for (var key in JSTweener.easingFunctions) { 
            this.easingFunctionsLowerCase[key.toLowerCase()] = JSTweener.easingFunctions[key]; 
        } 
    }, 
    toNumber: function(value, prefix, suffix) { 
        // for style 
        return Number(value);
	/*
        return eval(value);

        if (!suffix) suffix = 'px'; 
 
        return value.toString().match(/[0-9]/) ? Number(value.toString().replace( 
										 new RegExp(suffix + '$'), '' 
										  ).replace( 
											    new RegExp('^' + (prefix ? prefix : '')), '' 
											     )) 
	: 0; 
	*/
    },
    isTween: function (obj){
	for (var i = 0; i < this.objects.length; i++) { 
	    if (obj == this.objects[i].target){
		return true;
	    }
	}
	return false;
    },
    stopTween: function(obj){
	for (var i = 0; i < this.objects.length; i++) { 
	    if (obj == this.objects[i].target)
	    {
		this.objects.splice(i, 1);
	    }
	}
	if (this.objects.length == 0)
	{
	    this.looping = false;
	}
    },
    addTween: function(obj, options) { 
        var self = this; 
        if (!this.inited) this.init(); 
	if (!obj.isAddSetterGetter)
	    addSetterGetter (obj);
        var o = {}; 
//	o.target = new mobj(obj);
	o.target = obj;
	o.target.tobj = {};//obj;
        o.targetPropeties = {}; 
         
        for (var key in this.defaultOptions) { 
            if (typeof options[key] != 'undefined') { 
                o[key] = options[key]; 
                delete options[key]; 
            } else { 
                o[key] = this.defaultOptions[key]; 
            } 
        }
 
        if (typeof o.transition == 'function') { 
            o.easing = o.transition; 
        } else { 
            o.easing = this.easingFunctionsLowerCase[o.transition.toLowerCase()]; 
        } 

        for (var key in options) { 
            if (!o.prefix[key]) o.prefix[key] = ''; 
            if (!o.suffix[key]) o.suffix[key] = ''; 
            var sB = this.toNumber(o.target[key], o.prefix[key], o.suffix[key]); 
            o.targetPropeties[key] = { 
                b: sB, 
                c: options[key] - sB 
            }; 
        }
	var tobj = o.target.tobj;
	tobj.obj = o;

        setTimeout(function(tobj) { 
	    delete_timer(tobj);
	    tobj.obj.startTime = (new Date() - 0); 
	    tobj.obj.endTime = tobj.obj.time * 1000 + tobj.obj.startTime; 
	    
	    if (typeof tobj.obj.onStart == 'function') { 
		if (tobj.obj.onStartParams) { 
		    tobj.obj.onStart.apply(tobj.obj, tobj.obj.onStartParams); 
		} else { 
		    tobj.obj.onStart(); 
		} 
	    } 
	    
	    self.objects.push(tobj.obj); 
	    if (!self.looping) {  
		self.looping = true; 
		self.eventLoop.call(self); 
	    }
	}, o.delay * 1000, tobj); 
    }, 
    eventLoop: function() { 
	var now = (new Date() - 0); 
	for (var i = 0; i < this.objects.length; i++) { 
	    var o = this.objects[i]; 
	    var t = now - o.startTime; 
	    var d = o.endTime - o.startTime; 
	    if (t >= d) { 
		for (var property in o.targetPropeties) { 
		    var tP = o.targetPropeties[property]; 
		    try { 
			//o.target.setProperty(property,(tP.b + tP.c));
			o.target[property] = tP.b + tP.c;
			force_redraw ();
		    } catch(e) {} 
		} 
		this.objects.splice(i, 1); 
  
		if (typeof o.onUpdate == 'function') { 
		    if (o.onUpdateParams) { 
			o.onUpdate.apply(o, o.onUpdateParams); 
		    } else { 
			o.onUpdate(); 
		    } 
		} 
  
		if (typeof o.onComplete == 'function') { 
		    if (o.onCompleteParams) { 
			o.onComplete.apply(o, o.onCompleteParams); 
		    } else { 
			o.onComplete(); 
		    } 
		}
	    } else { 
		for (var property in o.targetPropeties) { 
		    var tP = o.targetPropeties[property]; 
		    var val = o.easing(t, tP.b, tP.c, d); 
		    try { 
			//o.target.setProperty(property,val);
			//console.log(o.target.name,o.target[property]);
			o.target[property] = val;
			force_redraw ();
		    } catch(e) {} 
		} 
  
		if (typeof o.onUpdate == 'function') { 
		    if (o.onUpdateParams) { 
			o.onUpdate.apply(o, o.onUpdateParams); 
		    } else { 
			o.onUpdate(); 
		    } 
		} 
	    } 
	}
  
	if (this.objects.length > 0) { 
	    var self = this; 
	    var tobj = {};//o.target.tobj;
	    setTimeout(function(tobj) {delete_timer(tobj); self.eventLoop();}, self.frameRate, tobj); 
	} else {
	    this.looping = false; 
	} 
    }
};

  
/* 
 * JSTweener.easingFunctions is 
 * Tweener's easing functions (Penner's Easing Equations) porting to JavaScript. 
 * http://code.google.com/p/tweener/ 
 */ 
  
    JSTweener.easingFunctions = { 
	easeNone: function(t, b, c, d) { 
	    return c*t/d + b; 
	},     
	easeInQuad: function(t, b, c, d) { 
	    return c*(t/=d)*t + b; 
	},     
	easeOutQuad: function(t, b, c, d) { 
	    return -c *(t/=d)*(t-2) + b; 
	},     
	easeInOutQuad: function(t, b, c, d) { 
	    if((t/=d/2) < 1) return c/2*t*t + b; 
	    return -c/2 *((--t)*(t-2) - 1) + b; 
	},     
	easeInCubic: function(t, b, c, d) { 
	    return c*(t/=d)*t*t + b; 
	},     
	easeOutCubic: function(t, b, c, d) { 
	    return c*((t=t/d-1)*t*t + 1) + b; 
	},     
	easeInOutCubic: function(t, b, c, d) { 
	    if((t/=d/2) < 1) return c/2*t*t*t + b; 
	    return c/2*((t-=2)*t*t + 2) + b; 
	},     
	easeOutInCubic: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutCubic(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInCubic((t*2)-d, b+c/2, c/2, d); 
	},     
	easeInQuart: function(t, b, c, d) { 
	    return c*(t/=d)*t*t*t + b; 
	},     
	easeOutQuart: function(t, b, c, d) { 
	    return -c *((t=t/d-1)*t*t*t - 1) + b; 
	},     
	easeInOutQuart: function(t, b, c, d) { 
	    if((t/=d/2) < 1) return c/2*t*t*t*t + b; 
	    return -c/2 *((t-=2)*t*t*t - 2) + b; 
	},     
	easeOutInQuart: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutQuart(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInQuart((t*2)-d, b+c/2, c/2, d); 
	},     
	easeInQuint: function(t, b, c, d) { 
	    return c*(t/=d)*t*t*t*t + b; 
	},     
	easeOutQuint: function(t, b, c, d) { 
	    return c*((t=t/d-1)*t*t*t*t + 1) + b; 
	},     
	easeInOutQuint: function(t, b, c, d) { 
	    if((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 
	    return c/2*((t-=2)*t*t*t*t + 2) + b; 
	},     
	easeOutInQuint: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutQuint(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInQuint((t*2)-d, b+c/2, c/2, d); 
	},     
	easeInSine: function(t, b, c, d) { 
	    return -c * Math.cos(t/d *(Math.PI/2)) + c + b; 
	},     
	easeOutSine: function(t, b, c, d) { 
	    return c * Math.sin(t/d *(Math.PI/2)) + b; 
	},     
	easeInOutSine: function(t, b, c, d) { 
	    return -c/2 *(Math.cos(Math.PI*t/d) - 1) + b; 
	},     
	easeOutInSine: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutSine(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInSine((t*2)-d, b+c/2, c/2, d); 
	},     
	easeInExpo: function(t, b, c, d) { 
	    return(t==0) ? b : c * Math.pow(2, 10 *(t/d - 1)) + b - c * 0.001; 
	},     
	easeOutExpo: function(t, b, c, d) { 
	    return(t==d) ? b+c : c * 1.001 *(-Math.pow(2, -10 * t/d) + 1) + b; 
	},     
	easeInOutExpo: function(t, b, c, d) { 
	    if(t==0) return b; 
	    if(t==d) return b+c; 
	    if((t/=d/2) < 1) return c/2 * Math.pow(2, 10 *(t - 1)) + b - c * 0.0005; 
	    return c/2 * 1.0005 *(-Math.pow(2, -10 * --t) + 2) + b; 
	},     
	easeOutInExpo: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutExpo(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInExpo((t*2)-d, b+c/2, c/2, d); 
	},     
	easeInCirc: function(t, b, c, d) { 
	    return -c *(Math.sqrt(1 -(t/=d)*t) - 1) + b; 
	},     
	easeOutCirc: function(t, b, c, d) { 
	    return c * Math.sqrt(1 -(t=t/d-1)*t) + b; 
	},     
	easeInOutCirc: function(t, b, c, d) { 
	    if((t/=d/2) < 1) return -c/2 *(Math.sqrt(1 - t*t) - 1) + b; 
	    return c/2 *(Math.sqrt(1 -(t-=2)*t) + 1) + b; 
	},     
	easeOutInCirc: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutCirc(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInCirc((t*2)-d, b+c/2, c/2, d); 
	},     
	easeInElastic: function(t, b, c, d, a, p) { 
	    var s; 
	    if(t==0) return b;  if((t/=d)==1) return b+c;  if(!p) p=d*.3; 
	    if(!a || a < Math.abs(c)) { a=c; s=p/4; } else s = p/(2*Math.PI) * Math.asin(c/a); 
	    return -(a*Math.pow(2,10*(t-=1)) * Math.sin((t*d-s)*(2*Math.PI)/p )) + b; 
	},     
	easeOutElastic: function(t, b, c, d, a, p) { 
	    var s; 
	    if(t==0) return b;  if((t/=d)==1) return b+c;  if(!p) p=d*.3; 
	    if(!a || a < Math.abs(c)) { a=c; s=p/4; } else s = p/(2*Math.PI) * Math.asin(c/a); 
	    return(a*Math.pow(2,-10*t) * Math.sin((t*d-s)*(2*Math.PI)/p ) + c + b); 
	},     
	easeInOutElastic: function(t, b, c, d, a, p) { 
	    var s; 
	    if(t==0) return b;  if((t/=d/2)==2) return b+c;  if(!p) p=d*(.3*1.5); 
	    if(!a || a < Math.abs(c)) { a=c; s=p/4; }       else s = p/(2*Math.PI) * Math.asin(c/a); 
	    if(t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin((t*d-s)*(2*Math.PI)/p )) + b; 
	    return a*Math.pow(2,-10*(t-=1)) * Math.sin((t*d-s)*(2*Math.PI)/p )*.5 + c + b; 
	},     
	easeOutInElastic: function(t, b, c, d, a, p) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutElastic(t*2, b, c/2, d, a, p); 
	    return JSTweener.easingFunctions.easeInElastic((t*2)-d, b+c/2, c/2, d, a, p); 
	},     
	easeInBack: function(t, b, c, d, s) { 
	    if(s == undefined) s = 1.70158; 
	    return c*(t/=d)*t*((s+1)*t - s) + b; 
	},     
	easeOutBack: function(t, b, c, d, s) { 
	    if(s == undefined) s = 1.70158; 
	    return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 
	},     
	easeInOutBack: function(t, b, c, d, s) { 
	    if(s == undefined) s = 1.70158; 
	    if((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 
	    return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 
	},     
	easeOutInBack: function(t, b, c, d, s) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutBack(t*2, b, c/2, d, s); 
	    return JSTweener.easingFunctions.easeInBack((t*2)-d, b+c/2, c/2, d, s); 
	},     
	easeInBounce: function(t, b, c, d) { 
	    return c - JSTweener.easingFunctions.easeOutBounce(d-t, 0, c, d) + b; 
	},     
	easeOutBounce: function(t, b, c, d) { 
	    if((t/=d) <(1/2.75)) { 
		return c*(7.5625*t*t) + b; 
	    } else if(t <(2/2.75)) { 
		return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 
	    } else if(t <(2.5/2.75)) { 
		return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 
	    } else { 
		return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 
	    } 
	},     
	easeInOutBounce: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeInBounce(t*2, 0, c, d) * .5 + b; 
	    else return JSTweener.easingFunctions.easeOutBounce(t*2-d, 0, c, d) * .5 + c*.5 + b; 
	},     
	easeOutInBounce: function(t, b, c, d) { 
	    if(t < d/2) return JSTweener.easingFunctions.easeOutBounce(t*2, b, c/2, d); 
	    return JSTweener.easingFunctions.easeInBounce((t*2)-d, b+c/2, c/2, d); 
	} 
    }; 
JSTweener.easingFunctions.linear = JSTweener.easingFunctions.easeNone; 
