﻿var AnimationUtilities = {
    getStyleValue: function(element, style) {
        var computedStyle = "";

        if (document.defaultView && document.defaultView.getComputedStyle) {
            computedStyle = document.defaultView.getComputedStyle(element, "").getPropertyValue(style);
        } else if (element.currentStyle) {
            style = style.replace(/\-(\w)/g, function(match, p1) { return p1.toUpperCase(); });
            computedStyle = element.currentStyle[style];
        }

        return computedStyle;
    },
    convertFromHex: function(value) {
        return parseInt(value, 16);
    },
    convertToHex: function(value) {
        var returnString = value.toString(16);

        if (returnString.length == 1) {
            returnString = "0" + returnString;
        }

        return returnString;
    },
    rgbToHex: function(input) {
        if (input.indexOf(",") > -1) {
            var arr = input.split(",");

            var r = parseInt(arr[0].substring(4));
            var g = parseInt(arr[1]);
            var b = parseInt(arr[2].substring(0, arr[2].length - 1));

            return "#" + this.convertToHex(r) + this.convertToHex(g) + this.convertToHex(b);
        } else {
            return input;
        }
    },
    fadeBackgroundToColor: function(obj, targetColor, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        var step = 10;
        var timeBetweenFrames = 0.1;

        var sourceColor = this.rgbToHex(obj.style.backgroundColor);

        var sourceR = this.convertFromHex(sourceColor.substring(1, 3));
        var sourceG = this.convertFromHex(sourceColor.substring(3, 5));
        var sourceB = this.convertFromHex(sourceColor.substring(5, 7));

        var targetR = this.convertFromHex(targetColor.substring(1, 3));
        var targetG = this.convertFromHex(targetColor.substring(3, 5));
        var targetB = this.convertFromHex(targetColor.substring(5, 7));

        var deltaR = targetR - sourceR;
        var deltaG = targetG - sourceG;
        var deltaB = targetB - sourceB;

        fade(0);

        function fade(currentValue) {
            var r = Math.min(Math.max(sourceR + Math.round(deltaR * (currentValue / 100)), 0), 255);
            var g = Math.min(Math.max(sourceG + Math.round(deltaG * (currentValue / 100)), 0), 255);
            var b = Math.min(Math.max(sourceB + Math.round(deltaB * (currentValue / 100)), 0), 255);

            obj.style.backgroundColor = "#" + AnimationUtilities.convertToHex(r) + AnimationUtilities.convertToHex(g) + AnimationUtilities.convertToHex(b);

            if (currentValue <= 100) {
                setTimeout(
                    function() {
                        fade(currentValue + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endFade();
            }
        }

        function endFade() {
            obj.style.backgroundColor = targetColor;

            if (callBack) {
                callBack();
            }
        }
    },
    fadeForegroundToColor: function(obj, targetColor, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        var step = 10;
        var timeBetweenFrames = 0.1;

        var sourceColor = this.rgbToHex(obj.style.color);

        var sourceR = this.convertFromHex(sourceColor.substring(1, 3));
        var sourceG = this.convertFromHex(sourceColor.substring(3, 5));
        var sourceB = this.convertFromHex(sourceColor.substring(5, 7));

        var targetR = this.convertFromHex(targetColor.substring(1, 3));
        var targetG = this.convertFromHex(targetColor.substring(3, 5));
        var targetB = this.convertFromHex(targetColor.substring(5, 7));

        var deltaR = targetR - sourceR;
        var deltaG = targetG - sourceG;
        var deltaB = targetB - sourceB;

        fade(0);

        function fade(currentValue) {
            var r = Math.min(Math.max(sourceR + Math.round(deltaR * (currentValue / 100)), 0), 255);
            var g = Math.min(Math.max(sourceG + Math.round(deltaG * (currentValue / 100)), 0), 255);
            var b = Math.min(Math.max(sourceB + Math.round(deltaB * (currentValue / 100)), 0), 255);

            obj.style.color = "#" + AnimationUtilities.convertToHex(r) + AnimationUtilities.convertToHex(g) + AnimationUtilities.convertToHex(b);

            if (currentValue <= 100) {
                setTimeout(
                    function() {
                        fade(currentValue + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endFade();
            }
        }

        function endFade() {
            obj.style.color = targetColor;

            if (callBack) {
                callBack();
            }
        }
    },
    flash: function(obj, color, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        var step = 1;
        var timeBetweenFrames = 0.1;

        var originalColor = this.rgbToHex(obj.style.color);

        var sourceR = this.convertFromHex(color.substring(1, 3));
        var sourceG = this.convertFromHex(color.substring(3, 5));
        var sourceB = this.convertFromHex(color.substring(5, 7));

        var targetR = this.convertFromHex(originalColor.substring(1, 3));
        var targetG = this.convertFromHex(originalColor.substring(3, 5));
        var targetB = this.convertFromHex(originalColor.substring(5, 7));

        var deltaR = targetR - sourceR;
        var deltaG = targetG - sourceG;
        var deltaB = targetB - sourceB;

        doFlash(0);

        function doFlash(currentValue) {
            var r = Math.min(Math.max(sourceR + Math.round(deltaR * (currentValue / 100)), 0), 255);
            var g = Math.min(Math.max(sourceG + Math.round(deltaG * (currentValue / 100)), 0), 255);
            var b = Math.min(Math.max(sourceB + Math.round(deltaB * (currentValue / 100)), 0), 255);

            obj.style.color = "#" + AnimationUtilities.convertToHex(r) + AnimationUtilities.convertToHex(g) + AnimationUtilities.convertToHex(b);

            if (currentValue <= 100) {
                setTimeout(
                    function() {
                        doFlash(currentValue + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endFlash();
            }
        }

        function endFlash() {
            obj.style.color = originalColor;

            if (callBack) {
                callBack();
            }
        }
    },
    fadeOut: function(obj, callBack, step) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        if (!step) {
            step = 0.1;
        }

        var timeBetweenFrames = 0.1;

        fade(1.00);

        function fade(currentValue) {
            obj.style.opacity = currentValue;
            obj.style.filter = "alpha(opacity=" + Math.round(currentValue * 100) + ");";

            if (obj.style.zoom == "") {
                obj.style.zoom = "1";
            }

            if (currentValue > 0.00) {
                setTimeout(function() { fade(currentValue - step); }, timeBetweenFrames);
            } else {
                endFade();
            }
        }

        function endFade() {
            obj.style.opacity = "0.00";
            obj.style.filter = "alpha(opacity=00);";

            if (callBack) {
                callBack();
            }
        }
    },
    rollUp: function(obj, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        if (obj.animating) {
            return;
        }

        obj.animating = true;

        var timeBetweenFrames = 0.1;

        var originalHeight = obj.clientHeight;

        if (obj.offsetHeight > originalHeight) {
            originalHeight = obj.offsetHeight;
        }

        var originalOverflow = obj.style.overflow ? obj.style.overflow : "auto";

        obj.style.overflow = "hidden";

        var step = 0;

        slide(0);

        function calculateHeightNeeded(increment) {
            var heightNeeded = 0;

            for (var i = increment; i > 0; i--) {
                heightNeeded += i;
            }

            return heightNeeded;
        }

        function slide(currentHeight) {
            if (originalHeight - currentHeight > 0) {
                obj.style.height = (originalHeight - currentHeight) + "px"
                obj.scrollTop = currentHeight;
            }

            if ((originalHeight - currentHeight) > calculateHeightNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentHeight < originalHeight) {
                setTimeout(
                    function() {
                        slide(currentHeight + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            obj.style.overflow = originalOverflow;
            obj.style.height = originalHeight + "px";
            obj.animating = null;

            if (callBack) {
                callBack();
            }
        }
    },
    rollLeft: function(obj, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        if (obj.animating) {
            return;
        }

        obj.animating = true;

        var timeBetweenFrames = 0.1;

        var originalOverflow = obj.style.overflow ? obj.style.overflow : "auto";

        obj.style.overflow = "hidden";

        var step = 0;

        slide(0);

        function calculateWidthNeeded(increment) {
            var widthNeeded = 0;

            for (var i = increment; i > 0; i--) {
                widthNeeded += i;
            }

            return widthNeeded;
        }

        function slide(currentMargin) {
            if (obj.offsetWidth - currentMargin >= 0) {
                obj.style.marginLeft = "-" + currentMargin + "px"
            }

            if ((obj.offsetWidth - currentMargin) > calculateWidthNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentMargin < obj.offsetWidth) {
                setTimeout(
                    function() {
                        slide(currentMargin + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            obj.style.overflow = originalOverflow;
            obj.animating = null;
            obj.style.marginLeft = "-" + obj.offsetWidth + "px";

            if (callBack) {
                callBack();
            }
        }
    },
    rollRight: function(obj, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        if (obj.animating) {
            return;
        }

        obj.animating = true;

        var timeBetweenFrames = 0.1;

        obj.style.overflow = "hidden";

        var step = 0;

        slide(0);

        function calculateWidthNeeded(increment) {
            var widthNeeded = 0;

            for (var i = increment; i > 0; i--) {
                widthNeeded += i;
            }

            return widthNeeded;
        }

        function slide(currentMargin) {
            if (obj.offsetWidth - currentMargin >= 0) {
                obj.style.marginLeft = currentMargin + "px";
            }

            if ((obj.offsetWidth - currentMargin) > calculateWidthNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentMargin < obj.offsetWidth) {
                setTimeout(
                    function() {
                        slide(currentMargin + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            obj.animating = null;
            obj.style.marginLeft = obj.offsetWidth + "px";

            if (callBack) {
                callBack();
            }
        }
    },
    rollDown: function(obj, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        if (obj.animating) {
            return;
        }

        obj.animating = true;

        var timeBetweenFrames = 0.1;

        var originalHeight = obj.clientHeight;

        if (obj.offsetHeight > originalHeight) {
            originalHeight = obj.offsetHeight;
        }

        var originalOverflow = obj.style.overflow ? obj.style.overflow : "auto";

        var step = 0;

        obj.style.overflow = "hidden";

        if (obj.style.zoom == "") {
            obj.style.zoom = "1";
        }

        slide(originalHeight);

        function calculateHeightNeeded(increment) {
            var heightNeeded = 0;

            for (var i = increment; i > 0; i--) {
                heightNeeded += i;
            }

            return heightNeeded;
        }

        function slide(currentHeight) {
            obj.style.height = (originalHeight - currentHeight) + "px"
            obj.scrollTop = currentHeight;

            if (currentHeight > calculateHeightNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentHeight > 0) {
                setTimeout(
                    function() {
                        slide(currentHeight - step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            obj.style.overflow = originalOverflow;
            //obj.style.height = originalHeight + "px";
            obj.style.height = "";
            obj.animating = null;

            if (callBack) {
                callBack();
            }
        }
    },
    rollUpAndFade: function(obj, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        var timeBetweenFrames = 0.1;

        var originalHeight = obj.clientHeight;

        if (obj.offsetHeight > originalHeight) {
            originalHeight = obj.offsetHeight;
        }

        var originalOverflow = obj.style.overflow ? obj.style.overflow : "auto";

        obj.style.overflow = "hidden";

        var step = 0;

        slide(0);

        function calculateHeightNeeded(increment) {
            var heightNeeded = 0;

            for (var i = increment; i > 0; i--) {
                heightNeeded += i;
            }

            return heightNeeded;
        }

        function slide(currentHeight) {
            if (originalHeight - currentHeight > 0) {
                obj.style.height = (originalHeight - currentHeight) + "px"
                obj.scrollTop = currentHeight;
            }

            obj.style.opacity = 1 - (Math.round((currentHeight / originalHeight) * 100)) / 100;
            obj.style.filter = "alpha(opacity=" + (100 - Math.round((currentHeight / originalHeight) * 100)) + ");";

            if ((originalHeight - currentHeight) > calculateHeightNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentHeight < originalHeight) {
                setTimeout(
                    function() {
                        slide(currentHeight + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            obj.style.overflow = originalOverflow;
            obj.style.height = "0px";

            if (callBack) {
                callBack();
            }
        }
    },
    rollDownAndFade: function(obj, callBack) {
        if (typeof (obj) == "string") {
            obj = document.getElementById(obj);
        }

        var timeBetweenFrames = 0.1;

        var originalHeight = obj.clientHeight;

        if (obj.offsetHeight > originalHeight) {
            originalHeight = obj.offsetHeight;
        }

        var originalOverflow = obj.style.overflow ? obj.style.overflow : "auto";

        var step = 0;

        obj.style.overflow = "hidden";

        if (obj.style.zoom == "") {
            obj.style.zoom = "1";
        }

        slide(originalHeight);

        function calculateHeightNeeded(increment) {
            var heightNeeded = 0;

            for (var i = increment; i > 0; i--) {
                heightNeeded += i;
            }

            return heightNeeded;
        }

        function slide(currentHeight) {
            obj.style.height = (originalHeight - currentHeight) + "px"
            obj.scrollTop = currentHeight;

            obj.style.opacity = 1 - (Math.round((currentHeight / originalHeight) * 100)) / 100;
            obj.style.filter = "alpha(opacity=" + (100 - Math.round((currentHeight / originalHeight) * 100)) + ");";

            if (currentHeight > calculateHeightNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentHeight > 0) {
                setTimeout(
                    function() {
                        slide(currentHeight - step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            obj.style.overflow = originalOverflow;
            obj.style.height = originalHeight + "px";

            if (callBack) {
                callBack();
            }
        }
    },
    transitionSlideLeft: function(oldObj, newObj, callBack) {
        if (typeof (oldObj) == "string") {
            oldObj = document.getElementById(oldObj);
        }

        if (typeof (newObj) == "string") {
            newObj = document.getElementById(newObj);
        }

        if (oldObj.animating) {
            return;
        }

        oldObj.animating = true;

        var timeBetweenFrames = 0.1;

        var originalOverflow = oldObj.style.overflow ? oldObj.style.overflow : "auto";

        oldObj.style.overflow = "hidden";

        var step = 0;

        slide(0);

        function calculateWidthNeeded(increment) {
            var widthNeeded = 0;

            for (var i = increment; i > 0; i--) {
                widthNeeded += i;
            }

            return widthNeeded;
        }

        function slide(currentMargin) {
            if (oldObj.offsetWidth - currentMargin >= 0) {
                oldObj.style.marginLeft = "-" + currentMargin + "px"
                newObj.style.marginLeft = (oldObj.offsetWidth - currentMargin) + "px";
            }

            if ((oldObj.offsetWidth - currentMargin) > calculateWidthNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentMargin < oldObj.offsetWidth) {
                setTimeout(
                    function() {
                        slide(currentMargin + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            oldObj.style.overflow = originalOverflow;
            oldObj.animating = null;
            oldObj.style.marginLeft = "-" + oldObj.offsetWidth + "px";

            if (callBack) {
                callBack();
            }
        }
    },
    transitionSlideRight: function(oldObj, newObj, callBack) {
        if (typeof (oldObj) == "string") {
            oldObj = document.getElementById(oldObj);
        }

        if (typeof (newObj) == "string") {
            newObj = document.getElementById(newObj);
        }

        if (oldObj.animating) {
            return;
        }

        oldObj.animating = true;

        var timeBetweenFrames = 0.1;

        var originalOverflow = oldObj.style.overflow ? oldObj.style.overflow : "auto";

        oldObj.style.overflow = "hidden";

        var step = 0;

        slide(0);

        function calculateWidthNeeded(increment) {
            var widthNeeded = 0;

            for (var i = increment; i > 0; i--) {
                widthNeeded += i;
            }

            return widthNeeded;
        }

        function slide(currentMargin) {
            if (oldObj.offsetWidth - currentMargin >= 0) {
                oldObj.style.marginLeft = currentMargin + "px";
                newObj.style.marginLeft = (currentMargin - oldObj.offsetWidth) + "px";
            }

            if ((oldObj.offsetWidth - currentMargin) > calculateWidthNeeded(step + 1)) {
                step++;
            } else {
                if (step > 1) {
                    step--;
                }
            }

            if (currentMargin < oldObj.offsetWidth) {
                setTimeout(
                    function() {
                        slide(currentMargin + step);
                    },
                    timeBetweenFrames
                );
            } else {
                endSlide();
            }
        }

        function endSlide() {
            oldObj.style.overflow = originalOverflow;
            oldObj.animating = null;
            oldObj.style.marginLeft = oldObj.offsetWidth + "px";

            if (callBack) {
                callBack();
            }
        }
    }
};




var GPAnimation = function() {
    this.defaultInterval = 10;
    this.defaultAnimationLength = 300;
}

GPAnimation.prototype.convertFromHex = function(value) {
    return parseInt(value, 16);
};

GPAnimation.prototype.convertToHex = function(value) {
    var returnString = value.toString(16);
    
    if (returnString.length == 1) {
        returnString = "0" + returnString;
    }
    
    return returnString;
};

GPAnimation.prototype.normalizeColor = function(input) {
    var output,
        i,
        length;

    if (input.length == 4) {
        output = "#";
    
        for (i = 1, length = input.length; i < length; i++) {
            output += input.charAt(i) + input.charAt(i);
        }
    } else {
        output = input;
    }
    
    return output;
}

GPAnimation.prototype.rgbToHex = function(input) {
    if (input.indexOf(",") > -1) {
        var arr = input.split(","),
            r = parseInt(arr[0].substring(4)),
            g = parseInt(arr[1]),
            b = parseInt(arr[2].substring(0, arr[2].length - 1));

        return "#" + this.convertToHex(r) + this.convertToHex(g) + this.convertToHex(b);
    } else {
        return input;
    }
};

GPAnimation.prototype.getStyleValue = function(element, style) {
    var computedStyle = "";
	
    if (document.defaultView && document.defaultView.getComputedStyle) {
	    computedStyle = document.defaultView.getComputedStyle(element, "").getPropertyValue(style);
    } else if (element.currentStyle) {
	    style = style.replace(/\-(\w)/g, function (match, p1) { return p1.toUpperCase(); });
	    computedStyle = element.currentStyle[style];
    }
	
    return computedStyle;
};

GPAnimation.prototype.findLeft = function(obj) {
    if (typeof (obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (obj == null) {
        return;
    }

    var currentLeft = 0;

    if (obj.offsetParent) {
        while (true) {
            currentLeft += obj.offsetLeft;

            if (!obj.offsetParent) {
                break;
            }

            obj = obj.offsetParent;
        }
    } else if (obj.x) {
        currentLeft += obj.x;
    }

    return currentLeft;
}

GPAnimation.prototype.findTop = function(obj) {
    if (typeof (obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (obj == null) {
        return;
    }

    var currentTop = 0;

    if (obj.offsetParent) {
        while (true) {
            if (obj.offsetTop) {
                currentTop += obj.offsetTop;
            }

            if (!obj.offsetParent) {
                break;
            }

            obj = obj.offsetParent;
        }
    } else if (obj.y) {
        currentTop += obj.y;
    }

    return currentTop;
}       

GPAnimation.prototype.slideTop = function(obj, endHeight, animationLength, callback) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (obj.slideTopTimer) {
        window.clearInterval(obj.slideTopTimer);
    }

    var startTime = (new Date()).getTime();
    var startHeight = parseInt(this.getStyleValue(obj, "height"));
    var heightDelta = endHeight - startHeight;
    var startTop = this.findTop(obj) + endHeight;

    var animationObject = this;

    obj.slideTopTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.slideTopTimer);

                obj.style.height = endHeight + "px";
                obj.style.top = startTop - endHeight + "px";

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(animationObject.easeOut(timeDelta, animationLength, heightDelta));

                obj.style.height = (startHeight + newValue) + "px";
                obj.style.top = (startTop - newValue) + "px";
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.slideBottom = function(obj, endHeight, animationLength, callback) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (obj.slideBottomTimer) {
        window.clearInterval(obj.slideBottomTimer);
    }

    var startTime = (new Date()).getTime();
    var startHeight = this.getStyleValue(obj, "height");
    
    if (startHeight == "auto") {
        startHeight = obj.offsetHeight;
    }
    
    startHeight = parseInt(startHeight);
    var heightDelta = endHeight - startHeight;
    
    var animationObject = this;

    obj.slideBottomTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.slideBottomTimer);

                obj.style.height = endHeight + "px";
                obj.scrollTop = 0;

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(animationObject.easeOut(timeDelta, animationLength, heightDelta));

                obj.style.height = (startHeight + newValue) + "px";
                obj.scrollTop = obj.scrollHeight;
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.slideLeft = function(obj, endWidth, animationLength, callback) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (obj.slideLeftTimer) {
        window.clearInterval(obj.slideLeftTimer);
    }

    var startTime = (new Date()).getTime();
    var startWidth = parseInt(this.getStyleValue(obj, "width"));
    var widthDelta = endWidth - startWidth;
    var startLeft = this.findLeft(obj) + endWidth;

    var animationObject = this;

    obj.slideLeftTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.slideLeftTimer);

                obj.style.width = endWidth + "px";
                obj.style.left = (startLeft - endWidth) + "px";

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(animationObject.easeOut(timeDelta, animationLength, widthDelta));

                obj.style.width = (startWidth + newValue) + "px";
                obj.style.left = (startLeft - newValue) + "px";
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.slideRight = function(obj, endWidth, animationLength, callback) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (obj.slideRightTimer) {
        window.clearInterval(obj.slideRightTimer);
    }

    var startTime = (new Date()).getTime();
    var startWidth = parseInt(this.getStyleValue(obj, "width"));
    var widthDelta = endWidth - startWidth;

    var animationObject = this;

    obj.slideRightTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.slideRightTimer);

                obj.style.width = endWidth + "px";

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(animationObject.easeOut(timeDelta, animationLength, widthDelta));

                obj.style.width = (startWidth + newValue) + "px";
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.scrollToTop = function(obj, callback, animationLength) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    this.scrollToPosition(obj, 0, callback, animationLength);
};

GPAnimation.prototype.scrollToBottom = function(obj, callback, animationLength) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    this.scrollToPosition(obj, obj.scrollHeight, callback, animationLength);
};

GPAnimation.prototype.scrollToPosition = function(obj, scrollPosition, callback, animationLength) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (obj.scrollToPositionTimer) {
        window.clearInterval(obj.scrollToPositionTimer);
    }

    var startTime = (new Date()).getTime();
    var startTop = parseInt(obj.scrollTop);
    var topDelta = scrollPosition - startTop;

    var animationObject = this;

    obj.scrollToPositionTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.scrollToPositionTimer);

                obj.scrollTop = scrollPosition;

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(animationObject.easeOut(timeDelta, animationLength, topDelta));

                obj.scrollTop = startTop + newValue;
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.easeOut = function(currentTime, endTime, valueDelta) {
    return -valueDelta * ((currentTime = currentTime / endTime - 1) * currentTime * currentTime * currentTime - 1);
};

GPAnimation.prototype.easeInOut = function(currentTime, endTime, valueDelta) {
    if ((currentTime /= endTime / 2) < 1) {
        return valueDelta / 2 * currentTime * currentTime * currentTime * currentTime;
    } else {
        return -valueDelta / 2 * ((currentTime -= 2) * currentTime * currentTime * currentTime - 2);
    }
}

GPAnimation.prototype.fadeBackgroundToColor = function(obj, targetColor, callback, animationLength) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (obj.fadeBackgroundToColorTimer) {
        window.clearInterval(obj.fadeBackgroundToColorTimer);
    }

    var startTime = (new Date()).getTime(),
        sourceColor,
        sourceR,
        sourceG,
        sourceB,
        targetR,
        targetG,
        targetB,
        deltaR,
        deltaG,
        deltaB;

    sourceColor = this.rgbToHex(this.getStyleValue(obj, "background-color"));
    sourceR = this.convertFromHex(sourceColor.substring(1, 3));
    sourceG = this.convertFromHex(sourceColor.substring(3, 5));
    sourceB = this.convertFromHex(sourceColor.substring(5, 7));
    targetR = this.convertFromHex(targetColor.substring(1, 3));
    targetG = this.convertFromHex(targetColor.substring(3, 5));
    targetB = this.convertFromHex(targetColor.substring(5, 7));
    deltaR = targetR - sourceR;
    deltaG = targetG - sourceG;
    deltaB = targetB - sourceB;

    var animationObject = this;

    obj.fadeBackgroundToColorTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime(),
                timeDelta = time - startTime,
                r,
                g,
                b;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.fadeBackgroundToColorTimer);

                obj.style.backgroundColor = targetColor;

                if (callback) {
                    callback();
                }
            } else {
                r = sourceR + parseInt(animationObject.easeOut(timeDelta, animationLength, deltaR));
                g = sourceG + parseInt(animationObject.easeOut(timeDelta, animationLength, deltaG));
                b = sourceB + parseInt(animationObject.easeOut(timeDelta, animationLength, deltaB));

                obj.style.backgroundColor = "#" + animationObject.convertToHex(r) + animationObject.convertToHex(g) + animationObject.convertToHex(b);
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.iterator = function(method, startValue, endValue, callback, animationLength) {
    if (!animationLength) {
        animationLength = this.defaultAnimationLength;
    }

    if (document.body.iteratorTimer) {
        window.clearInterval(document.body.iteratorTimer);
    }

    var startTime = (new Date()).getTime();
    var valueDelta = endValue - startValue;

    var animationObject = this;

    document.body.iteratorTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime();
            var timeDelta = time - startTime;

            if (timeDelta >= animationLength) {
                window.clearInterval(document.body.iteratorTimer);

                method(endValue);

                if (callback) {
                    callback();
                }
            } else {
                var newValue = parseInt(animationObject.easeOut(timeDelta, animationLength, valueDelta));

                method(startValue + newValue);
            }
        },
        this.defaultInterval
    );
};

GPAnimation.prototype.flash = function(obj, color, callback, animationLength) {
    if (typeof(obj) == "string") {
        obj = document.getElementById(obj);
    }

    if (!animationLength) {
        this.defaultAnimationLength;
    }

    if (obj.flashTimer) {
        window.clearInterval(obj.flashTimer);
    }

    var startTime = (new Date()).getTime(),
        originalColor,
        sourceR,
        sourceG,
        sourceB,
        targetR,
        targetG,
        targetB,
        deltaR,
        deltaG,
        deltaB;

    color = this.normalizeColor(color);
    originalColor = this.normalizeColor(this.rgbToHex(this.getStyleValue(obj, "color")));
    sourceR = this.convertFromHex(color.substring(1, 3));
    sourceG = this.convertFromHex(color.substring(3, 5));
    sourceB = this.convertFromHex(color.substring(5, 7));
    targetR = this.convertFromHex(originalColor.substring(1, 3));
    targetG = this.convertFromHex(originalColor.substring(3, 5));
    targetB = this.convertFromHex(originalColor.substring(5, 7));
    deltaR = targetR - sourceR;
    deltaG = targetG - sourceG;
    deltaB = targetB - sourceB;

    var animationObject = this;

    obj.flashTimer = window.setInterval(
        function() {
            var time = (new Date()).getTime(),
                timeDelta = time - startTime,
                r,
                g,
                b;

            if (timeDelta >= animationLength) {
                window.clearInterval(obj.flashTimer);

                obj.style.color = originalColor;

                if (callback) {
                    callback();
                }
            } else {
                r = sourceR + parseInt(animationObject.easeOut(timeDelta, animationLength, deltaR));
                g = sourceG + parseInt(animationObject.easeOut(timeDelta, animationLength, deltaG));
                b = sourceB + parseInt(animationObject.easeOut(timeDelta, animationLength, deltaB));

                obj.style.color = "#" + animationObject.convertToHex(r) + animationObject.convertToHex(g) + animationObject.convertToHex(b);
            }
        },
        this.defaultInterval
    );
};

var gpAnimation = new GPAnimation();