﻿var zzzz = 0;
function action(obj, from, to, type, timeLength, acceleration, callBack, id, timeInterval, styleToAfter, mode)
{
    // Animation action types definitions
    //-----------------------
    var Types = { Custom:0, Opacity:1, Display:2, Width:3, Height:4, Top:5, Left:6, Color:7, BorderColor:8, BackColor:9  }
    
    if(type == 'opacity')
    this.currentType = Types.Opacity;
    else 
        if(type == 'display')
        this.currentType = Types.Display;
        else 
            if(type == 'width')
            this.currentType = Types.Width;
            else 
                if(type == 'height')
                this.currentType = Types.Height;
                else
                    if(type == 'top')
                    this.currentType = Types.Top;
                    else
                        if(type == 'left')
                        this.currentType = Types.Left;
                        else
                            if(type == 'color')
                            this.currentType = Types.Color;
                            else
                                if(type == 'borderColor')
                                this.currentType = Types.BorderColor;
                                else
                                    if(type == 'backColor')
                                    this.currentType = Types.BackColor;
                                    else
                                        this.currentType = Types.Custom;
    
    this.id = id;
    if(!this.id)
        this.id = zzzz++;//(rnd4() + rnd4() + "-" + rnd4() + "-" + rnd4() + "-" + rnd4() + "-" + rnd4() + rnd4() + rnd4());

    this.idSeq = null;
    
    this.obj = obj;
    this.type = type ? type : '';
    
    this.startAfter = null;
    
    this.stateOnFinish = styleToAfter;
    
    this.displayOnBefore = null;
    this.displayOnAfter = null;
    this.styleToAfter = null;
    
    this.timer = null;
    this.currTime = 0;
    this.timeInterval = timeInterval;
    if(!this.timeInterval)
        this.timeInterval = actM.timeInterval       
    
    this.animationMode = mode || 0;
    this.timeLength = timeLength;
    
    this.timeInterval = this.timeLength / Math.round(this.timeLength / this.timeInterval + 0.5);    

    if( this.currentType == Types.Color ||
        this.currentType == Types.BorderColor ||
        this.currentType == Types.BackColor)
    {
        from = convertToRgb(from);
        to = convertToRgb(to);
    }
    
    this.fromBase = from;
    this.toBase = to;
    
    this.from = from;
    this.to = to;
    
    this.acceleration = acceleration ? acceleration : 0; // negative (min: -100) means "breaking", positive - acceleration. 0 == normal.
    
    this.prev = null;
    this.next = null;
    
    this.callBack = callBack;
    this.preCallBack = null;
    this.ontick = null;
    
    this.seq = null; // sequence
    this.start = function(isLanched)
    {
        if(this.timer)
            window.clearInterval(this.timer);
        
        this.currTime = 0;
        this.from = this.seq.reverseMode ? this.toBase : this.fromBase;
        this.to = this.seq.reverseMode ? this.fromBase : this.toBase;

            
        if(parseInt(this.startAfter) > 0 && !isLanched)
            window.setTimeout("actM.findAct(" + this.id + ").start(true);", this.startAfter);
        else
        {
            if(this.from != this.to)
            {
                try{
                eval(this.getEvalString(this.from));
                }catch(e){if(window.debugging)window.status = e;}
                
                {
                    if(this.preCallBack)
                        this.preCallBack(this.obj);

                    if(this.displayOnBefore != null && !this.seq.reverseMode || this.displayOnAfter != null && this.seq.reverseMode)
                        eval(this.getEvalString(this.displayOnBefore && !this.seq.reverseMode || !this.displayOnAfter && this.seq.reverseMode ? '' : 'none', Types.Display));
                        
                    this.timer = window.setInterval("actM.tickAct(" + this.id + ");", Math.round(this.timeInterval));
                }
            }
            else
            {
                if(this.preCallBack)
                    this.preCallBack(this.obj);
                if(this.callBack)
                    this.callBack(this.obj);
            }
        }
    }
    
    this.reverse = function()
    {
        this.from = this.currStep;
        this.to = this.seq.reverseMode ? this.toBase : this.fromBase;
        this.seq.reverseMode = true;
    }
    
    this.tick = function()
    {
        this.currTime += this.timeInterval;
        if(this.currTime > this.timeLength)
            this.currTime = this.timeLength;
            
        var currPercentage = this.currTime / this.timeLength;
        var accPer = this.acceleration * (1 - currPercentage) * (this.seq.reverseMode ? 1 : -1);
                
        try
        {
            if( this.currentType == Types.Color ||
                this.currentType == Types.BorderColor ||
                this.currentType == Types.BackColor)
            {
                // Separate the Rgb values from To/From colors 
                //----------------------------------
                var fromR = (this.from & 255);
                var fromG = (this.from >> 8) & 255;
                var fromB = (this.from >> 16) & 255;
                
                var toR = (this.to & 255);
                var toG = (this.to >> 8) & 255;
                var toB = (this.to >> 16) & 255;
                // ---------------------------------

                // Calculate the separated color steps
                //--------------------------------------
                var stepR = (toR - fromR) * currPercentage;
                stepR = stepR + stepR * accPer / 100;
                this.currStepR = stepR;
                
                var stepG = (toG - fromG) * currPercentage;
                stepG = stepG + stepG * accPer / 100;
                this.currStepG = stepG;
                
                var stepB = (toB - fromB) * currPercentage;
                stepB = stepB + stepB * accPer / 100;
                this.currStepB = stepB;
                // ------------------------------------
                                
                // Modify and combine the values back to RGB color
                //------------------------------------------
                var r = fromR + stepR;
                var g = fromG + stepG;
                var b = fromB + stepB;
                var x = '0123456789ABCDEF';
                var hrgb;
                hrgb = x.charAt(r >> 4) + x.charAt(r & 15);
                hrgb += x.charAt(g >> 4) + x.charAt(g & 15);
                hrgb += x.charAt(b >> 4) + x.charAt(b & 15);
                var rgb = convertToRgb(hrgb);
                //------------------------------------------
           
                eval(this.getEvalString(rgb));
            }
            else
            {
                var currStep = (this.to - this.from) * currPercentage;
                currStep = currStep + currStep * accPer / 100;
                this.currStep = currStep;
                
                eval(this.getEvalString(this.from + currStep));
            }
        }
        catch(e)
        {if(window.debugging)window.status = e;}
        
        if(this.ontick)
            this.ontick();
            
        if(this.currTime == this.timeLength)
            this.finish();
    }
    
    this.getEvalString = function(value, currType)
    {
        if(currType == Types.Display)
            return "actM.findAct('" + this.id + "').obj.style.display = '" + value + "';";
            
            switch(this.currentType)
            {
                case Types.Width: 
                    return "actM.findAct('" + this.id + "').obj.style.width = '" + value + "px';";
                
                case Types.Height:
                    return "actM.findAct('" + this.id + "').obj.style.height = '" + value + "px';";
                
                case Types.Top:
                    return "actM.findAct('" + this.id + "').obj.style.top = '" + value + "px';";
                
                case Types.Left:
                    return "actM.findAct('" + this.id + "').obj.style.left = '" + value + "px';";
                
                case Types.Opacity:
                {
                    if(value == 100 && ie)
                        return "actM.findAct('" + this.id + "').obj.style.filter = '';";
                    else if(ie)
                        return "actM.findAct('" + this.id + "').obj.style.filter = 'alpha(opacity=" + (value) + ")';";
                    else
                        return "var _obj = actM.findAct('" + this.id + "'); _obj.obj.style.MozOpacity = " + (Math.round(value) / 100) + ";_obj.obj.style.opacity = " + (Math.round(value) / 100) + ";";
                }
                
                case Types.Color:
                    return "actM.findAct('" + this.id + "').obj.style.color = '#" + convertFromRgb(value) + "';";
                    
                case Types.BorderColor:
                    return "actM.findAct('" + this.id + "').obj.style.borderColor = '#" + convertFromRgb(value) + "';";
                    
                case Types.BackColor:
                    return "actM.findAct('" + this.id + "').obj.style.backgroundColor = '#" + convertFromRgb(value) + "';";
                    
                default:
                    return this.type.replace(/\{0\}/g, "actM.findAct('" + this.id + "').obj").replace(/\{1\}/g, value);
            }
            
//        else if(this.currentType == this.typeWidth)
//            return "actM.findAct('" + this.id + "').obj.style.width = '" + value + "px';"
//        else if(this.currentType == this.typeHeight)
//            return "actM.findAct('" + this.id + "').obj.style.height = '" + value + "px';"
//        else if(this.currentType == this.typeTop)
//            return "actM.findAct('" + this.id + "').obj.style.top = '" + value + "px';"
//        else if(this.currentType == this.typeLeft)
//            return "actM.findAct('" + this.id + "').obj.style.left = '" + value + "px';"
//        else if(this.currentType == this.typeOpacity)
//        {
//            if(value == 100 && ie)
//            {
//                return "actM.findAct('" + this.id + "').obj.style.filter = '';"
//            }
//            else if(ie)
//            {
//                return "actM.findAct('" + this.id + "').obj.style.filter = 'alpha(opacity=" + (value) + ")';"
//            }
//            else
//            {
//                return "var _obj = actM.findAct('" + this.id + "'); _obj.obj.style.MozOpacity = " + (Math.round(value) / 100) + ";_obj.obj.style.opacity = " + (Math.round(value) / 100) + ";";
//            }
//        }
//        else if(this.currentType == this.typeColor)
//            return "actM.findAct('" + this.id + "').obj.style.color = '#" + convertFromRgb(value) + "';"
//        else if(this.currentType == this.typeBorderColor)
//            return "actM.findAct('" + this.id + "').obj.style.borderColor = '#" + convertFromRgb(value) + "';"
//            
//        else if(this.currentType == this.typeBackColor)
//            return "actM.findAct('" + this.id + "').obj.style.backgroundColor = '#" + convertFromRgb(value) + "';"
//        else 
//            return this.type.replace("{0}", "actM.findAct('" + this.id + "').obj").replace("{1}", value);
    }
    
    this.finish = function()
    {
        eval(this.getEvalString(this.styleToAfter == null ? this.to : this.styleToAfter));

        if(this.displayOnAfter != null && !this.seq.reverseMode || this.displayOnBefore != null && this.seq.reverseMode)
            eval(this.getEvalString(this.displayOnAfter && !this.seq.reverseMode || !this.displayOnBefore && this.seq.reverseMode ? 'block' : 'none', "display"));
            
        this.stop();
        
        if(this.next && !this.seq.reverseMode)
            this.next.start();
        else if(this.prev && this.seq.reverseMode)
            this.prev.start();
        else //if(this.clearAfterUsing)
            window.setTimeout('actM.remove(' + this.id + ', \'' + this.seq.id + '\');', 0);
    }
    
    this.stop = function()
    {
        if(this.timer)
        {
            window.clearInterval(this.timer);
            this.timer = null;
        }

        if(this.callBack)
            this.callBack(this.obj);
    }
}

function sequence(actionsList, id)
{
    this.id = id;
    this.reverseMode = false;

    if(!this.id)
        this.id = (rnd4() + rnd4() + "-" + rnd4() + "-" + rnd4() + "-" + rnd4() + "-" + rnd4() + rnd4() + rnd4());
    
    this.items = actionsList ? actionsList : new Array();
    
    for(var i = 0; i < this.items.length; i++)
    {
        if(i < this.items.length - 1)
            this.items[i + 1].prev = this.items[i];
        
        if(i < this.items.length - 1)
            this.items[i].next = this.items[i + 1];
        
        this.items[i].seq = this;
    }
    
    this.findAct = function(id)
    {
        for(var i = 0; i < this.items.length; i++)
        {
            if(this.items[i].id == id)
                return this.items[i];
        }
        
        return null;
    }
    
    this.remove = function(id)
    {
        for(var i = 0; i < this.items.length; i++)
        {
            if(this.items[i].id == id)
            {
                this.items.splice(i, 1);
                break;
            }
        }
    }
    
    this.start = function(reverseMode)
    {
        this.reverseMode = reverseMode == true; // false or undefined == false

        this.items[this.reverseMode ? this.items.length - 1 : 0].start();
    }
}

function actionsManager()
{
    this.timeInterval = 50;
    
    this.sequences = new Array();
    
    this.addAction = function(actionObj, toStart)
    {
        actionObj.idSeq = actionObj.id;
        this.addSequence(new sequence(new Array(actionObj), actionObj.id), toStart);
    }
    
    this.addSequence = function(seqObj, toStart)
    {
        if(!seqObj.id)
            seqObj.id = zzzz++;// (rnd4() + rnd4() + "-" + rnd4() + "-" + rnd4() + "-" + rnd4() + "-" + rnd4() + rnd4() + rnd4());

        this.sequences.push(seqObj);
        if(toStart != false)
            seqObj.start();
        
        return seqObj.id;
    }
    
    this.startSeq = function(id)
    {
    }
    
    this.reverseSeq = function(id)
    {
    }
    
    this.cancelSeq = function(id)
    {
    }
    
    this.stopSeq = function(id)
    {
    }

    this.findSeq = function(id)
    {
        for(var i = 0; i < this.sequences.length; i++)
        {
            if(this.sequences[i].id == id)
                return this.sequences[i];
        }
        return null;
    }
    
    this.findAct = function(id)
    {
        for(var i = 0; i < this.sequences.length; i++)
        {
            var f = this.sequences[i].findAct(id);
            if(f)
                return f;
        }
        return null;
    }
    
    this.tickAct = function(id)
    {
        var a = this.findAct(id);
        if(a)
            a.tick();
    }
    
    this.remove = function(id, sid)
    {
        for(var i = 0; i < this.sequences.length; i++)
        {
            this.sequences[i].remove(id);
        }
        for(var i = 0; i < this.sequences.length; i++)
        {
            if(this.sequences[i].id == sid)
            {
                this.sequences.splice(i, 1);
                break;
            }
        }
    }
}

function rnd4() 
{
   return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}

var actM = new actionsManager();

function convertFromRgb(rgb)
{
    //var decColor = red + 256 * green + 65536 * blue;
  /*  var rgb = parseInt(rgb);
    var char = "0123456789ABCDEF"; 
    var result = String(char.charAt(Math.floor(rgb / 16))) + String(char.charAt(rgb - (Math.floor(rgb / 16) * 16))); 
    alert(result);
    return result;
    */
    //return value.toString(16);
    
    
     var x = '0123456789ABCDEF';

    var r = rgb & 255;
    var g = (rgb >> 8) & 255;
    var b = (rgb >> 16) & 255;
    
    var res;
    res = x.charAt(r >> 4) + x.charAt(r & 15);
    res += x.charAt(g >> 4) + x.charAt(g & 15);
    res += x.charAt(b >> 4) + x.charAt(b & 15);

    return res;
}

function convertToRgb(value)
{                
    var x = '0123456789ABCDEF', c = 0;
    value = value.toUpperCase().replace('#', '');
    for (var i = 0; i < 6; i += 2)
    {
         c += parseInt(16 * x.indexOf(value.charAt(i)) + x.indexOf(value.charAt(i + 1)) << (8 * (i / 2)));
    }
    return c;
}
