﻿/// <reference path="global.js" />
/// <reference path="validation.js" />
/*************************************************
 *     Эффекты                                   *   
 *                                               *
 *     Автор:                     Агроник А.Ю.   *
 *     Дата создания:             18.08.2007     *
 *     Дата изменения:            21.07.2008     * 
 *                                               *
 *                                               *
 *		Внимание! данный файл является           *
 *		частью программного продукта SCSC        *
 *      и не поставляется отдельно. Права        *
 *      на программный продукт SCSC              *
 *      принадлежат компании A2 www.a2soft.ru    *
 *											   	 *
 *************************************************/
 
 $effect = 
 {
    Info:new Array(), // Массив текущих анимаций
    GetInfo:function(obj, formal) // Получает текущую анимацию по объекту, к которому она применятеся
    {
        var result = null;
        for(var i=0;i<this.Info.length;i++)
        {
            if(obj == this.Info[i].obj && (this.Info[i].formal != null && this.Info[i].formal == formal))
            {
                result = this.Info[i];
                break;
            }
        }
        return result;
    },
    ClearInfo:function(obj, formal) // Удаляет анимацию привязаную в заданому объекту
    { 
        var arr = new Array();
        for(var i=0;i<this.Info.length;i++)
            if(obj != this.Info[i].obj || !(this.Info[i].formal != null && this.Info[i].formal == formal))
                arr.push(this.Info[i]);
        this.Info = arr; 
    },
    Timer:null, // -- проверить необходимость - не вижу
    AnimationTime:1500, // Длительность анимации (в милисекундах)
    AnimationInterval:100, // Интервал в милисекундах между итерациями анимационного процесса
    AnimationType:"sin", // Тип изменения скорости анимации. Возможные значения: "sin", "cos"
    Default:function() // Сброс параметров в значения по-умолчанию
    {
        this.Timer = null;
        this.AnimationTime = 1500;
        this.AnimationInterval = 10;
        this.AnimationType = "sin";
    }, 
    Time:function(_time) // Задает время Анимации и возвращает управляющий объект (для конструкций типа $effect.Time(1000).FadeIn(this))
    {
        this.AnimationTime = _time;
        return this;
    },
    Interval:function(_interval) // Задает интервал Анимации и возвращает управляющий объект (аналогично .Time().)
    {
        this.AnimationInterval = _interval;
        return this;
    },
    Type:function(_type) // Задает Тип Анимации и возвращает управляющий объект (аналогично .Time().)
    {
        this.AnimationType = _type;
        return this;
    },
    FadeIn:function(obj, end, formal) // Постепенное проявление объекта (из прозрачности)
    {
        if(obj)
        {  
            this.AnimateOpacity(obj, 100, 0, end, formal); 
        }
    },
    FadeOut:function(obj, end, formal) // Постепенное исчезновение объекта (прозрачность)
    {
        if(obj)
        {
            this.AnimateOpacity(obj, -100, 100, end, formal);
        }
    },
    Scroll:function(obj, disp, bord, onEnd, onRun, formal)
    {
        var border = bord == null ? null : bord;
        var x0 = 0;
        var a = x0 + disp;
        var displace = border != null ? (disp > 0 ? a < border : a > border) ? disp : (x0 - border)*(-1) : disp;
        var time = Math.abs(Math.round(displace*$effect.AnimationTime/disp));
        var info = this.GetInfo(obj, formal);
        if(info != null)
        {
            info.Stop();
        }    
        var run = function(f)
        {
            obj.scrollBy(0, Math.round(f*displace - x0));
            var x0 = Math.round(f*displace);
            if(onRun)
				onRun();
        }		
        var end = function()
        {
            obj.scrollBy(0, Math.round(displace - x0));
            $effect.Default(); 
            if(onEnd)
                onEnd(obj);
        }
        this.Animate(obj, time, null, run, end, formal);
    },
    MorphColors:function(obj, start, end, style, onEnd, onRun, formal)
    {
        if(obj)
        {
            var _up = 16777215;
            var _down = 0;
            var start = start ? start : $G.Browser.Detect.gecko ? eval($G.GetStyle(obj, style)) : $G.GetStyle(obj, style);
            var _c0 = $G.Number.toDecRGB(start ? start : $G.GetStyle(obj, style));
            var _c1 = $G.Number.toDecRGB(end);
            var _cd = $G.Color.Minus(_c1, _c0);
            var time = $effect.AnimationTime;
            var info = this.GetInfo(obj, formal);
            if(info != null)
                info.Stop();
            var run = function(f)
            {
                var _n = $G.Color.Plus($G.Color.Mult(_cd, f), _c0);
                //alert($G.Color.fromRGB(_n));
                $G.SetStyle($global.NormCssStr(style), $G.Color.fromRGB(_n), obj);
                if(onRun)
                    onRun();
            }
            var end = function()
            {
                var _n = $G.Color.Plus(_cd, _c0);
                $G.SetStyle($global.NormCssStr(style), $G.Color.fromRGB(_n), obj);
                $effect.Default(); 
                if(onEnd)
                    onEnd(obj);
            }
            this.Animate(obj, time, null, run, end, formal);
        }
    },
    AnimateOpacity:function(obj, disp, start, onEnd, formal) // Анимирует изменение непрозрачности
    {
        var border  = disp < 0 ? 0 : 100;
        var x0 = start;
        var a = x0 + disp;
        var displace = border != null ? (disp > 0 ? a < border : a > border) ? disp : (x0 - border)*(-1) : disp;
        var time = Math.abs(Math.round(displace*$effect.AnimationTime/disp));
        var info = this.GetInfo(obj, formal);
            if(info != null)
                info.Stop();
                
        var run = function(f)
        {
            $global.SetOpacity(obj, Math.round(f*displace + x0)/100);
        }    
        var end = function()
        {
            $global.SetOpacity(obj, Math.round(displace + x0)/100);
            $effect.Default(); 
            if(onEnd)
                onEnd(obj);
        }
        this.Animate(obj, time, null, run, end, formal);
    },
    Page:
    {
        InitFader:function(color, op, fromChild)
        {
            var fader = $G.Get.ById("A2-Page-Fader");
            if(! fader)
            {
                fader = $G.Append(document.body, $G.Tag("div", {id:"A2-Page-Fader"}));
                if(op != null)
                    $G.Opacity.Set(fader, op);
                fader.style.top = "0px";
                fader.style.left = "0px";
            }
            fader.style.position = "absolute";
            fader.style.width = document.body.offsetWidth+"px";

            fader.style.height = (fromChild ? document.getElementsByTagName("form")[0].offsetHeight : document.body.offsetHeight)+"px";
            if(color)
                fader.style.backgroundColor = color;
            return fader;
        },
        FadeIn:function(color, max, onEnd, fromChild)
        {
            var fader = $effect.Page.InitFader(color, 0.0, fromChild);
            var cOpacity = $G.Opacity.Get(fader);
            $effect.AnimateOpacity(fader, (max-cOpacity), cOpacity, onEnd, "A2-Page-Fading");
            return $effect;
        },
        FadeOut:function(color, onEnd, fromChild)
        {
            var fader = $effect.Page.InitFader(color, null, fromChild)
            $effect.AnimateOpacity(fader, -100, $G.Opacity.Get(fader), onEnd, "A2-Page-Fading");
            return $effect;
        },
        CleanUp:function()
        {
            document.body.removeChild($G.Get.ById("A2-Page-Fader"));
        }
    },
    AnimateStyle:function(obj, style, disp, bord, onEnd, onRun, formal) // Анимирует измение параметра стиля заданого в style
    {
        var border = bord == null ? null : bord;
        var x0 = $global.GetStyle(obj, style, true);
        var a = x0 + disp;
        var displace = border != null ? (disp > 0 ? a < border : a > border) ? disp : (x0 - border)*(-1) : disp;
        var time = Math.abs(Math.round(displace*$effect.AnimationTime/disp));
        var info = this.GetInfo(obj, formal);
        if(info != null)
        {
            info.Stop();
        }    
        var run = function(f)
        {
            $global.SetStyle($global.NormCssStr(style), Math.round(f*displace + x0)+"px", obj);
            if(onRun)
				onRun(Math.round(f*displace + x0));
        }		
        var end = function()
        {
            $global.SetStyle($global.NormCssStr(style), (x0 + displace) + "px", obj);
            $effect.Default(); 
            if(onEnd)
                onEnd(obj);
        }
        this.Animate(obj, time, null, run, end, formal);
    },
    SlideH:function(obj, disp, bord, onEnd) // Перемещение объекта по горизонтали
    {
        this.AnimateStyle(obj, "left", disp, bord, onEnd);
    },
    SlideV:function(obj, disp, bord, onEnd) // Перемещение объекта по вертикали
    {
        this.AnimateStyle(obj, "top", disp, bord, onEnd);
    },
    SlideToPoint:function(obj, x, y, formal)
    {
        var info = this.GetInfo(obj, formal);
            if(info != null)
                info.Stop();
                
        var pos = $global.FindPosition(obj);
        var x0 = Number(pos[0]);
        var y0 = Number(pos[1]); 
        var dispX = x - x0;
        var dispY = y - y0;
        var start = function()
        {
        }   
        var run = function(f)
        {
            obj.style.top = Math.round(f*dispY + y0)+"px";
            obj.style.left = Math.round(f*dispX + x0)+"px";
        }
        var end = function()
        {
            obj.style.top = y + "px";
            obj.style.left = x + "px";
            $effect.Default(); 
        }
        this.Animate(obj, start, run, end);
    },
    // Необходим для изменения ускорения согласно выбранному типу
    // type - варианты "sin" : sin(value), "cos" : cos(value)
    TypedChange:function(value, type)
    {
        if(type == "sin")
            return Math.sin(value);
        else if(type == "cos")
            return Math.cos(value);
        else
            return value;
    },
    // Функция - движок, изменяет параметры в течение времени (плавно)
    //           obj - объект анимации
    //    uTotalTime - общее время анимации
    //     fnOnStart - функция выполняющаяся до начала анимации
    //       fnOnRun - функция выполняющаяся на каждом шаге анимации func(f), f - ускорение?!
    //       fnOnEnd - функция выполняющаяся после завершения анимации
    Animate:function(obj, uTotalTime, fnOnStart, fnOnRun, fnOnEnd, formal)
    {
        if (fnOnStart) { fnOnStart(); }
        var freq = Math.PI / (2 * uTotalTime); // частота
        var startTime = new Date().getTime();
        var info = null;
        var type = this.AnimationType;
        var loop = function() 
        {
            var elapsedTime = new Date().getTime() - startTime;
            if (elapsedTime < uTotalTime) 
            {
                var f = Math.abs($effect.TypedChange(elapsedTime * freq, type)); 
                if (fnOnRun) { fnOnRun(f); }
            }
            else 
            {
                if (fnOnEnd) { info.Stop(); fnOnEnd(); }
            }
        }
        var tmr = setInterval(loop, $effect.AnimationInterval);
        info = new AnimInfo(tmr, obj, formal);
        $effect .Info.push(info);
    },
    Reflection:
    {
        Add:function(obj, height, opacity)
        {
            if(obj)
            {
                var refHeight = Math.floor(obj.offsetHeight*height);
                var refWidth = obj.offsetWidth;
                var divHeight = Math.floor(obj.offsetHeight*(1+height));
                var wrap = document.createElement("div");
                
                wrap.className = obj.className;
                wrap.style.cssText = obj.style.cssText;
                
                $global.SetStyle("width", refWidth+"px", wrap);
                $global.SetStyle("height", divHeight+"px", wrap);
                $global.SetStyle($global.NormCssStr("vertical-align"), "bottom", wrap);
                $global.SetStyle($global.NormCssStr("overflow"), "hidden", wrap);
                
                var reflect = null;
                
                if(document.all && !window.opera)
                {
                    reflect = document.createElement("img");
                    reflect.src = obj.src;
                    $global.SetStyle("width", refWidth+"px", reflect);
                    $global.SetStyle($global.NormCssStr("margin-bottom"), "-"+(obj.offsetHeight-refHeight)+"px", reflect);
                    reflect.style.filter = 'flipv Alpha(opacity='+(opacity*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(height*100)+')';
                }
                else
                {
                    reflect = document.createElement("canvas");
					var context = reflect.getContext("2d");
				
					$global.SetStyle("height", refHeight+"px", reflect); 
					$global.SetStyle("width", refWidth+"px", reflect); 
					
					reflect.width = refWidth;
					reflect.height = refHeight;
					
					// append ?
					context.save();
					
					context.translate(0, obj.offsetHeight-1);
					context.scale(1, -1);
					
					context.drawImage(obj, 0, 0, refWidth, obj.offsetHeight);
	
					context.restore();
					
					context.globalCompositeOperation = "destination-out";
					var gradient = context.createLinearGradient(0, 0, 0, refHeight);
					
					gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
					gradient.addColorStop(0, "rgba(255, 255, 255, "+(1-opacity)+")");
		
					context.fillStyle = gradient;
					if (navigator.appVersion.indexOf('WebKit') != -1) {
						context.fill();
					} else {
						context.fillRect(0, 0, refWidth, refHeight*2);
					}
                }			    
                
                obj.className = "reflected";
                obj.style.cssText = ""; 
                
                obj.parentNode.replaceChild(wrap, obj);
                wrap.appendChild(obj);
                wrap.appendChild(reflect);
            }
        },
        Remove:function(obj) // Несовершенен...
        {
		    if (obj.className == "reflected") 
		    {
			    obj.className = obj.parentNode.className;
			    obj.parentNode.style.height = obj.style.height;
			    obj.parentNode.style.width = obj.style.width;
			    obj.style.cssText = obj.parentNode.style.cssText;
			    obj.parentNode.parentNode.replaceChild(obj, obj.parentNode);
		    }
	    }
    }
 }; 

$FX = $effect; //Алиас на $effect

function AnimInfo(interval, obj, formal)
{
    this.obj = obj;
    this.Interval = interval;
    this.formal = formal;
    this.Stop = function()
    {
        clearInterval(this.Interval);
        $effect.ClearInfo(this.obj, this.formal);
    }
}

function MultyAnimInfo()
{
	this.obj = null;
	
}
