
// tp (c) 2009 Konstantin Kirillov. MIT License.
// dependent on opacity.js

tj$ = window.tj$ || {};

tj$.effector = {

             //Creates effect for give html-element (he).
             //Effect is a set of transformations.
             //Transformation usually is a smooth change of he property.
             //Set of properties along with their transformation is supplied in this.init().
   create :  function (he) { 

     return ( new ( function () {
        var that = this;
        var ob = he;
        var interval;
        var prop; 
        var dorepeatedly = false;
        var pulsate = false;
        var finalFunction = null;
        //Setup HTML element:
        this.resetHE = function (he) {
            ob = he;
            return that;
        };

        //Setters:
        this.setFinalFunction = function( fun ){ finalFunction = fun; };
        var unhide = false;
        //TODO: this is a sign of poor design:
        this.unhide = function( value ){ unhide = value; };

        this.init = function (a) {
            interval = a.interval;
            prop = a.prop;
            if( a.unhide ) unhide = a.unhide;
            //ob = document.getElementById( a.name );
            for(var i=prop.length-1; i>= 0; i--){
                var p = prop[i];
                //Either start or attr must be set: { start : 1, ... or { attr : 'width' ...
                if( typeof p.start === 'undefined' || p.start == null || p.start === '' ) { 
                    //Sugar:
                    var attr = ob[ p.attr ];
                    if( !attr ) {
                        //TODO fails:
                        throw  "Attribute " + p.attr + " is not set for " + ob + ".";
                    }
                    var ps = attr[p.prop]; 
                    //console.log(p.attr + p.prop + " " + attr + ps);
                    //TODO better: be ready: no stile properties exist:
                    if( typeof ps === 'undefined' || !ps ) ps = 0;
                    if( p.unit == 'px' ) {
                       ps = parseInt(ps);
                    }    
                    p.start = ps;
                }
                p.value = p.start;

                //f i n a l   v a l u e
                if( a.action == 'vanish' ){
                    if( p.prop == 'height' || p.prop == 'width' || p.prop == 'opacity' ) {
                        p.finalv = 0;
                    }
                }

                //s e t t e r
                var setter = p.setter;
                if( !p.setter ){
                    if( p.attr == 'opacity' ){
                       //Sugar:
                       p.setter = function (ob, v) { tj$.opacity.set(v,ob); }; //TODO: remove tj$.
                    }else{
                       p.setter = ( function (obj, v, p) {
                                      var unit =  p.unit  ?  p.unit  :   '';
                                      obj[p.attr][p.prop] = Math.floor(v) + unit; 
                                    } );
                       //var w = "p.setter = ( function (obj, v) { obj." + p.attr + "." + p.prop + " = Math.floor(v) + " + unit + "; } ); ";
                       //eval(w);
                    }
                }                     
                //At this point, the object can be invisible to not
                //affect currently displayed instance:
                p.setter(ob, p.value, p);
            } 
            return that;
        };


        this.updater = function(){
            for(var i=prop.length-1; i>= 0; i--){
                var p = prop[i];
                p.value += p.increment;
                //One of values done. Stop job. Set finals and leave: 
                if( p.increment * (p.value - p.finalv) >= 0 ) {
                        for(var j=prop.length-1; j>= 0; j--){
                            p = prop[j];
                            p.setter(ob, p.finalv, p); 
                        }
                        if( finalFunction ) finalFunction();
                        finalFunction = null; //Don't play with chains.
                        if( pulsate ) back();
                        if( dorepeatedly || pulsate ) that.repeat();
                        return; 
                }
                p.setter(ob, p.value, p);
                if( unhide || p.unhide ) ob.style.visibility = 'visible';
            } 
            setTimeout(that['updater'], interval);
        };


        this.repeat = function() {
            for(var i=prop.length-1; i>= 0; i--){
               prop[i].value = prop[i].start;
            }
            setTimeout(that['updater'], interval);
        };
        var back = function() {
            for(var i=prop.length-1; i>= 0; i--){
               var swap = prop[i].start;
               prop[i].start = prop[i].finalv;
               prop[i].finalv = swap;
               prop[i].increment = -prop[i].increment;
               //console.log( "start, final=" + prop[i].start + ", " + prop[i].finalv );
            }
        };
        this.back = back; //TODO simpler
        this.revert = function(){
            back();
            that.repeat();
        }; 
        this.repeatedly = function() {
            dorepeatedly = true;
            that.repeat();
        };
        this.pulsate = function() {
            pulsate = true;
            that.repeat();
        };
        this.stop = function() {
            pulsate = false;
            dorepeatedly = false;
        };
      })() ); }
};


