﻿// Implements animation tweening effects for html boxes.
// Greg Edwards, 2011

var ia_spritemanager_ie = false;

try
{
    if (document.all)
    {
        ia_spritemanager_ie = true;
        if (document.documentMode >= 9) ia_spritemanager_ie = false;
    }
}
catch (ex)
{
}

function Sprite(element, sprite_manager, x, y, mx, my, rotation, alpha, vectorScale)
{
    if (rotation == null) rotation = 0;
    if (alpha == null) alpha = 1.0;
    if (vectorScale == null) vectorScale = false;

    this.Element = element;
    this.SpriteManager = sprite_manager;
    this.X = x;
    this.Y = y;
    this.MX = mx;
    this.MY = my;
    this.Rotation = rotation;
    this.Alpha = alpha;
    this.VectorScale = vectorScale;
    this.tX = new Array();
    this.tY = new Array();
    this.tMX = new Array();
    this.tMY = new Array();
    this.tRotation = new Array();
    this.tAlpha = new Array();
    sprite_manager.Sprites.push(this);
    element.style.position = "absolute";
    element.style.right = "auto";
    element.style.bottom = "auto";
    ia_spritemanager_setStyle(element, x, y, mx, my, rotation, alpha, vectorScale);

    this.moveTo = ia_spritemanager_moveTo;
    this.moveBy = ia_spritemanager_moveTo;
    this.scaleTo = ia_spritemanager_scaleTo;
    this.fadeIn = ia_spritemanager_fadeIn;
    this.fadeOut = ia_spritemanager_fadeOut;
    this.rotateTo = ia_spritemanager_rotateTo;
    this.rotateBy = ia_spritemanager_rotateBy;
    this.stop = ia_spritemanager_stop;
}

function Transformation(t1, t2, v1, v2)
{
    if (t1 > t2) throw "SpriteManager: Ending time must be greater than or equal to starting time.";
    this.T1 = t1;
    this.T2 = t2;
    this.V1 = v1;
    this.V2 = v2;
}

function SpriteManager(surface, refresh_rate)
{
    this.Surface = surface;
    this.Frame = 0;
    this.StartTime = new Date().getTime();
    this.RefreshRate = refresh_rate;
    this.Sprites = new Array();
    this.Begin = ia_spritemanager_Begin;
    this.End = ia_spritemanager_End;
    this.Update = ia_spritemanager_Update;
    this.timeout = null;
}

function ia_spritemanager_Begin()
{
    if (this.timeout == null) ia_spritemanager_Run(this);
}

function ia_spritemanager_Run(sprite_manager)
{
    sprite_manager.timeout = null;
    sprite_manager.Update();
    sprite_manager.Frame = new Date().getTime() - sprite_manager.StartTime;
    sprite_manager.timeout = setTimeout(function () { ia_spritemanager_Run(sprite_manager); }, sprite_manager.RefreshRate);
}

function ia_spritemanager_End()
{
    clearTimeout(this.timeout);
    this.timeout = null;
}

function ia_spritemanager_Update()
{
    // update positions of all objects
    for (x in this.Sprites)
    {
        var sprite = this.Sprites[x];
        var transform = ia_spritemanager_getActiveTransform(sprite.tX, this.Frame);
        if (transform != null) sprite.X = ia_spritemanager_lerp(transform.V1, transform.V2, transform.T1, transform.T2, this.Frame);

        transform = ia_spritemanager_getActiveTransform(sprite.tY, this.Frame);
        if (transform != null) sprite.Y = ia_spritemanager_lerp(transform.V1, transform.V2, transform.T1, transform.T2, this.Frame);

        transform = ia_spritemanager_getActiveTransform(sprite.tMX, this.Frame);
        if (transform != null) sprite.MX = ia_spritemanager_lerp(transform.V1, transform.V2, transform.T1, transform.T2, this.Frame);

        transform = ia_spritemanager_getActiveTransform(sprite.tMY, this.Frame);
        if (transform != null) sprite.MY = ia_spritemanager_lerp(transform.V1, transform.V2, transform.T1, transform.T2, this.Frame);

        transform = ia_spritemanager_getActiveTransform(sprite.tRotation, this.Frame);
        if (transform != null) sprite.Rotation = ia_spritemanager_lerp(transform.V1, transform.V2, transform.T1, transform.T2, this.Frame);

        transform = ia_spritemanager_getActiveTransform(sprite.tAlpha, this.Frame);
        if (transform != null) sprite.Alpha = ia_spritemanager_lerp(transform.V1, transform.V2, transform.T1, transform.T2, this.Frame);
    }

    // apply changes to attached DOM elements
    for (x in this.Sprites)
    {
        var sprite2 = this.Sprites[x];
        ia_spritemanager_setStyle(sprite2.Element, sprite2.X, sprite2.Y, sprite2.MX, sprite2.MY, sprite2.Rotation, sprite2.Alpha, sprite2.VectorScale);
    }
}

function ia_spritemanager_getActiveTransform(transforms, frame)
{
    var result = null;
    for (x in transforms)
    {
        var t = transforms[x];
        if (t.T1 >= frame) continue;
        if (result == null) result = t;
        if (t.T2 > result.T2) result = t;
    }
    return result;
}

function ia_spritemanager_lerp(v1, v2, t1, t2, t)
{
    var weight = (t - t1) / (t2 - t1);
    if (t2 == t1) weight = 1;
    if (weight > 1) weight = 1;
    if (weight < 0) weight = 0;
    var result = v2 * weight + v1 * (1 - weight);
    return result;
}

function ia_spritemanager_setStyle(element, x, y, mx, my, rotation, alpha, vectorScale)
{
    if (alpha <= 0)
    {
        element.style.visibility = "hidden";
        return;
    }
    else
    {
        element.style.visibility = "visible";
    }

    element.style.left = x.toString() + "px";
    element.style.top = y.toString() + "px";

    if (!vectorScale)
    {
        element.style.width = mx.toString() + "px";
        element.style.height = my.toString() + "px";
    }

    if (ia_spritemanager_ie)
    {
        element.style.filter = "Alpha(opacity=" + (100 * alpha) +
                               ") Matrix(M11=" + Math.cos(rotation) + ", M12=" + (-Math.sin(rotation)) +
                               ", M21=" + Math.sin(rotation) + ", M22=" + Math.cos(rotation) + ");";
    }
    else
    {
        element.style.Transform = "rotate(" + rotation.toString() + "rad)";
        element.style.MozTransform = "rotate(" + rotation.toString() + "rad)";
        element.style.WebkitTransform = "rotate(" + rotation.toString() + "rad)";
        element.style.msTransform = "rotate(" + rotation.toString() + "rad)";
        element.style.OTransform = "rotate(" + rotation.toString() + "rad)";
        element.style.opacity = alpha.toString();

        if (vectorScale)
        {
            element.style.Transform += " scale(" + mx.toString() + ", " + my.toString() + ")";
            element.style.MozTransform += " scale(" + mx.toString() + ", " + my.toString() + ")";
            element.style.WebkitTransform += " scale(" + mx.toString() + ", " + my.toString() + ")";
            element.style.msTransform += " scale(" + mx.toString() + ", " + my.toString() + ")";
            element.style.OTransform += " scale(" + mx.toString() + ", " + my.toString() + ")";
        }
    }
}

function ia_spritemanager_moveTo(x, y, time)
{
    this.tX = new Array();
    this.tX.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.X, x));

    this.tY = new Array();
    this.tY.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.Y, y));
}

function ia_spritemanager_moveBy(x, y, time)
{
    this.tX = new Array();
    this.tX.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.X, this.X + x));

    this.tY = new Array();
    this.tY.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.Y, this.Y + y));
}

function ia_spritemanager_scaleTo(mx, my, time)
{
    this.tMX = new Array();
    this.tMX.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.MX, mx));

    this.tMY = new Array();
    this.tMY.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.MY, my));
}

function ia_spritemanager_fadeIn(time)
{
    this.tAlpha = new Array();
    this.tAlpha.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.Alpha, 1));
}

function ia_spritemanager_fadeOut(time)
{
    this.tAlpha = new Array();
    this.tAlpha.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, this.Alpha, 0));
}

function ia_spritemanager_rotateTo(rotation, time)
{
    var rot = this.Rotation % (2 * Math.PI);
    this.tRotation = new Array();
    this.tRotation.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, rot, rotation));
}

function ia_spritemanager_rotateBy(rotation, time)
{
    var rot = this.Rotation % (2 * Math.PI);
    this.tRotation = new Array();
    this.tRotation.push(new Transformation(this.SpriteManager.Frame, this.SpriteManager.Frame + time, rot, rot + rotation));
}

function ia_spritemanager_stop()
{
    this.tX = new Array();
    this.tY = new Array();
    this.tMX = new Array();
    this.tMY = new Array();
    this.tRotation = new Array();
    this.tAlpha = new Array();
}


