/*
Script: Fx.Base.js
        Contains <Fx.Base>, the foundamentals of the MooTools Effects.

License:
        MIT-style license.
*/

var Fx = {};

/*
Class: Fx.Base
        Base class for the Effects.

Options:
        transition - the equation to use for the effect see <Fx.Transitions>; default is <Fx.Transitions.Sine.easeInOut>
        duration - the duration of the effect in ms; 500 is the default.
        unit - the unit is 'px' by default (other values include things like 'em' for fonts or '%').
        wait - boolean: to wait or not to wait for a current transition to end before running another of the same instance. defaults to true.
        fps - the frames per second for the transition; default is 50

Events:
        onStart - the function to execute as the effect begins; nothing (<Class.empty>) by default.
        onComplete - the function to execute after the effect has processed; nothing (<Class.empty>) by default.
        onCancel - the function to execute when you manually stop the effect.
*/

Fx.Base = new Class({

        options: {
                onStart: Class.empty,
                onComplete: Class.empty,
                onCancel: Class.empty,
                transition: function(p){
                        return -(Math.cos(Math.PI * p) - 1) / 2;
                },
                duration: 500,
                unit: 'px',
                wait: true,
                fps: 50
        },

        initialize: function(options){
                this.element = this.element || null;
                this.setOptions(options);
                if (this.options.initialize) this.options.initialize.call(this);
        },

        step: function(){
                var time = $time();
                if (time < this.time + this.options.duration){
                        this.delta = this.options.transition((time - this.time) / this.options.duration);
                        this.setNow();
                        this.increase();
                } else {
                        this.stop(true);
                        this.set(this.to);
                        this.fireEvent('onComplete', this.element, 10);
                        this.callChain();
                }
        },

        /*
        Property: set
                Immediately sets the value with no transition.

        Arguments:
                to - the point to jump to

        Example:
                >var myFx = new Fx.Style('myElement', 'opacity').set(0); //will make it immediately transparent
        */

        set: function(to){
                this.now = to;
                this.increase();
                return this;
        },

        setNow: function(){
                this.now = this.compute(this.from, this.to);
        },

        compute: function(from, to){
                return (to - from) * this.delta + from;
        },

        /*
        Property: start
                Executes an effect from one position to the other.

        Arguments:
                from - integer: staring value
                to - integer: the ending value

        Examples:
                >var myFx = new Fx.Style('myElement', 'opacity').start(0,1); //display a transition from transparent to opaque.
        */

        start: function(from, to){
                if (!this.options.wait) this.stop();
                else if (this.timer) return this;
                this.from = from;
                this.to = to;
                this.change = this.to - this.from;
                this.time = $time();
                this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
                this.fireEvent('onStart', this.element);
                return this;
        },

        /*
        Property: stop
                Stops the transition.
        */

        stop: function(end){
                if (!this.timer) return this;
                this.timer = $clear(this.timer);
                if (!end) this.fireEvent('onCancel', this.element);
                return this;
        }/*compatibility*/,

        custom: function(from, to){
                return this.start(from, to);
        },

        clearTimer: function(end){
                return this.stop(end);
        }

        /*end compatibility*/

});

Fx.Base.implement(new Chain, new Events, new Options);
