﻿Tegud.ImageAnimations = function () {
    var _cascadeSegments = 41;

    var _randomNumber = function (limit) {
        return Math.floor(limit * Math.random())
    };

    var _animations = [
    // Fade
        {
        Name: "Fade",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);
            var animationTimeout = 500;

            existingImage.fadeOut(animationTimeout, function () { existingImage.remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    },
    // Slide up
        {
        Name: "Slide Up",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);
            var animationTimeout = 650;

            existingImage.animate({ top: -existingImage.height() }, animationTimeout, "easeInOutQuad", function () { existingImage.remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    },
    // Slide left
        {
        Name: "Slide Right",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);

            var animationTimeout = 1000;

            existingImage.animate({ left: existingImage.width() }, animationTimeout, "easeInOutQuad", function () { existingImage.remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    },
    // Split vertical
        {
        Name: "Split Vertical",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);

            var animationTimeout = 650;
            var imageWidth = existingImage.width();
            var imageHeight = existingImage.height();

            var segments = _splitImage(existingImage, 2);

            segments.eq(0).animate({ top: imageHeight }, animationTimeout, "easeInOutQuad", function () { segments.eq(0).remove(); });
            segments.eq(1).animate({ top: -imageHeight }, animationTimeout, "easeInOutQuad", function () { segments.eq(1).remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    },
    // Split horizontal
        {
        Name: "Split Horizontal",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);

            var containerWidth = existingImage.parent().width();
            var imageWidth = existingImage.width();
            var imageHeight = existingImage.height();
            var animationTimeout = 650;

            var segments = _splitImage(existingImage, 2);

            segments.eq(0).animate({ left: -Math.floor((containerWidth / 2)) }, animationTimeout, "easeInOutQuad", function () { segments.eq(0).remove(); });
            segments.eq(1).animate({ left: containerWidth }, animationTimeout, "easeInOutQuad", function () { segments.eq(1).remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    },
    // tri split Vertical
        {
        Name: "Tri Split Vertical",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);

            var imageWidth = existingImage.width();
            var imageHeight = existingImage.height();
            var animationTimeout = 650;

            var segments = _splitImage(existingImage, 3);

            segments.filter(":not(:eq(1))").animate({ top: imageHeight }, animationTimeout, "easeInOutQuad", function () { segments.eq(0).remove(); });
            segments.eq(1).animate({ top: -imageHeight }, animationTimeout, "easeInOutQuad", function () { segments.eq(1).remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    },
    // Square Down
        {
        Name: "Square Down",
        Animation: function (existingImage, nextImage, callback) {
            nextImage.insertBefore(existingImage);

            var imageWidth = existingImage.width();
            var imageHeight = existingImage.height();
            var animationTimeout = 650;

            existingImage.animate({
                top: Math.floor(imageHeight / 2),
                left: Math.floor(imageWidth / 2),
                width: 0,
                height: 0,
                opacity: 0.6
            }, animationTimeout, "easeInOutQuad", function () { existingImage.remove(); });

            _executeCallbackOnTimeout(callback, animationTimeout);
        }
    }];
    
    // Disable certain animations for IE (its sloooow).
    if(!$.browser.msie || $.browser.version > 8) {
        // Grid - Slide Out
        _animations[_animations.length] = {
            Name: "Grid - Slide Out",
            Animation: function (existingImage, nextImage, callback) {
                nextImage.insertBefore(existingImage);

                var imageWidth = existingImage.width();
                var imageHeight = existingImage.height();
                var animationTimeout = 650;

                _imageToGrid(existingImage, 2).each(function (i) {
                    var current = $(this);

                    current.animate({
                        top: i > 1 ? imageHeight : -imageHeight,
                        left: i == 0 || i == 2 ? -imageWidth : imageWidth
                    }, animationTimeout, "easeInOutQuad", function () { current.remove(); });
                });

                _executeCallbackOnTimeout(callback, animationTimeout);
            }
        };

        // Grid - Fadeout Sequential
        _animations[_animations.length] = {
            Name: "Grid - Fadeout Sequential",
            Animation: function (existingImage, nextImage, callback) {
                nextImage.insertBefore(existingImage);

                var cascadeTimeout = 45;
                var animationTimeout = 650;
                var segments = _imageToGrid(existingImage, 4);

                segments.each(function (i) {
                    var current = $(this);

                    setTimeout(function () {
                        current.animate({ opacity: 0 }, animationTimeout, "easeInOutQuad", function () { current.remove(); });
                    }, i * cascadeTimeout);
                });

                _executeCallbackOnTimeout(callback, ((segments.size() - 1) * cascadeTimeout) + animationTimeout);
            }
        };
        // Grid - Fadeout Random
        _animations[_animations.length] = {
            Name: "Grid - Fadeout Random",
            Animation: function (existingImage, nextImage, callback) {
                nextImage.insertBefore(existingImage);

                var maxTimeout;

                _imageToGrid(existingImage, [8, 4]).each(function (i) {
                    var current = $(this);
                    var timeout = (_randomNumber(500) + 250);

                    if (!timeout > (maxTimeout || 0))
                        maxTimeout = timeout;

                    setTimeout(function () {
                        current.animate({ opacity: 0 }, 650, "easeInOutQuad", function () { current.remove(); });
                    }, timeout);
                });

                _executeCallbackOnTimeout(callback, (maxTimeout || 0) + 650);
            }
        };
        // Cascade Left to Right
        _animations[_animations.length] = {
            Name: "Cascade Left to Right",
            Animation: function (existingImage, nextImage, callback) {
                nextImage.insertBefore(existingImage);
                var imageHeight = existingImage.height();

                _cascade(_splitImage(existingImage, _cascadeSegments), imageHeight, 25, 650, callback);
            }
        };
        _animations[_animations.length] = {
        // Cascade Right to Left
            Name: "Cascade Right to Left",
            Animation: function (existingImage, nextImage, callback) {
                nextImage.insertBefore(existingImage);
                var imageHeight = existingImage.height();

                _cascade(_splitImage(existingImage, _cascadeSegments).reverse(), imageHeight, 25, 650, callback);
            }
        };
    }

    var _cascade = function (segments, imageHeight, cascadeOffset, animationTimeout, callback) {
        segments.reverse().each(function (i) {
            var current = $(this);

            setTimeout(function () {
                current.animate({
                    top: -imageHeight,
                    opacity: 0.3
                }, animationTimeout, "easeInOutQuad", function () { current.remove(); });
            }, (i * cascadeOffset));
        });

        _executeCallbackOnTimeout(callback, ((segments.size() - 1) * cascadeOffset) + animationTimeout);
    };

    var _executeCallbackOnTimeout = function (callback, timeout) {
        if (callback && $.isFunction(callback)) 
            callback(timeout);
    };

    // Splits an image into a grid
    // Grid can either by specified as a square number (provide a numeric value as the grid value)
    // or by a 2 dimensional integer array, e.g. 2, 5 would produce a 2 x 5 grid.
    var _imageToGrid = function (image, grid) {
        // If the grid is a number, its that number squared for the grid.
        if (!isNaN(grid))
            grid = [grid, grid];

        // Not an array, return the image untouched.
        if (!$.isArray(grid))
            return image;

        var imageWidth = image.width();
        var imageHeight = image.height();

        var segmentWidth = Math.ceil(imageWidth / grid[0]);
        var segmentHeight = Math.ceil(imageHeight / grid[1]);

        var imageLocation = image.attr("src");
        var segmentSet = $();
        var totalHeight = 0;

        for (var x = 0; x < grid[1]; x++) {
            // Loop through the number of rows.
            var totalWidth = 0;

            for (var y = 0; y < grid[0]; y++) {
                // Loop through the number of columns.
                segmentSet = segmentSet.add($("<div />", {
                    css: {
                        position: "absolute",
                        top: totalHeight,
                        left: totalWidth,
                        width: segmentWidth,
                        height: segmentHeight,
                        "background-image": "url('" + imageLocation + "')",
                        "background-position": (-totalWidth) + "px " + (-totalHeight) + "px"
                    }
                }).insertBefore(image));


                totalWidth += segmentWidth;
            }

            totalHeight += segmentHeight;
        }

        image.remove();

        return segmentSet;
    };

    // Splits an image into the specified number of columns.
    // Returns a jQuery set of segments.
    var _splitImage = function (image, segments) {
        // Get the image's width.
        var imageWidth = image.width();
        var imageHeight = image.height();
        var segmentWidth = Math.ceil(imageWidth / segments);
        var segmentSet = $();
        var imageLocation = image.attr("src");
        var totalWidth = 0;

        for (var x = 0; x < segments; x++) {
            segmentSet = segmentSet.add($("<div />", {
                css: {
                    position: "absolute",
                    top: 0,
                    left: totalWidth,
                    width: segmentWidth,
                    height: imageHeight,
                    "background-image": "url('" + imageLocation + "')",
                    "background-position": -totalWidth + "px 0px"
                }
            }).insertBefore(image));

            totalWidth += segmentWidth;
        }

        // Remove the existing image.
        image.remove();

        // Return the jQuery object that contains the segments.
        return segmentSet;
    };

    return {
        getAnimation: function (name) {
            if (!name)
                return _animations[_randomNumber(_animations.length)].Animation;

            name = name.toLowerCase();

            for (var x = 0; x < _animations.length; x++) {
                if (_animations[x].Name.toLowerCase() == name) {
                    return _animations[x].Animation;
                }
            }
        }
    };
} ();

Tegud.HeaderGallery = function () {
    var _shiftBounceTimeout;
    var _shiftDebounce = 700;
    var _imageIndex = 0;
    var _shiftTimeout = 15000;
    var _imageArray;
    var _rotateTimeout;

    var _headerContainer;
    var _headerContainerInner;

    var _headerControls;
    var _headerControlsMarker;

    var _headerImageBuffer;
    var _headerInformationContainer;
    var _headerInformationContent;
    var _headerInformationTitle;
    var _headerInformationText;
    var _headerLoading;

    // Private function: _setRotateTimeout
    // Sets the timeout rotation to rotate in the preset shiftTimeout value.
    var _setRotateTimeout = function () {
        _rotateTimeout = setTimeout(function () { _shift(1); }, _shiftTimeout);
    }

    var _preLoad = function () {
        var unloadedItems = _headerImageBuffer.children().filter(".UnLoaded");

        // We dont have any more items to preload.
        if (!unloadedItems.length) {
            // Hide the loading screen.
            _headerLoading.hide();
            return;
        }

        // Show the loading screen.
        _headerLoading.show();

        // Load the first unloaded image.
        _load(unloadedItems.first(), _preLoad);
    }

    // Private function: _load
    // Parameters: 
    //      image       The image to load
    //      callback    The function to execute (if any) upon completion.
    // Loads the specified image.
    var _load = function (image, callback) {
        image
            .bind("load", function () {
                $(this)
                    .removeClass("UnLoaded")
                    .removeData("imageSrc")
                    .unbind("load");

                // Check if this item's index is the same as the current index.
                // if it is, switch the images.
                if (image.index() == _imageIndex)
                    _switchImages(image);

                if (callback && $.isFunction(callback))
                    callback(image);
            })
            .attr("src", image.data("imageSrc"));
    }

    // Private function: _shift
    // Moves the gallery a number of positions relative to its current position.
    var _shift = function (shiftBy) {
        if (_shiftBounceTimeout)
            return;
        else
            _shiftBounceTimeout = setTimeout(function () { _shiftBounceTimeout = undefined; }, _shiftDebounce);

        _goto(_imageIndex + shiftBy);
    };

    // Private function: _shift
    // Moves the gallery to the specified index.
    var _goto = function (index) {
        if (_rotateTimeout != undefined)
            clearTimeout(_rotateTimeout);

        var imageBufferItems = _headerImageBuffer.children();
        var imageBufferSize = imageBufferItems.size();

        if (index < 0)
            index = (imageBufferSize - 1);
        else if (index > (imageBufferSize - 1))
            index = 0;

        if (_imageIndex == index)
            return;

        _imageIndex = index;

        _headerControlsMarker.animate({ "left": 28 * _imageIndex }, 500, "easeInOutQuad");

        var nextImage = imageBufferItems.eq(_imageIndex);

        if (!nextImage.hasClass("UnLoaded"))
            _switchImages(nextImage);
    };

    var _setInfoText = function (animationTime) {
        if (!_imageArray[_imageIndex].Title && !_imageArray[_imageIndex].Description) {
            // No name or title, hide the info container
            _headerInformationContainer.addClass("Hidden");
            return;
        }

        // Show the info container, set the title/description text.
        _headerInformationContainer.removeClass("Hidden");

        if (_imageArray[_imageIndex].AlwaysShowInfo)
            _headerInformationContainer.addClass("AlwaysShow");
        else
            _headerInformationContainer.removeClass("AlwaysShow");


        var currentTitle = _headerInformationTitle.text();
        var currentDescription = _headerInformationText.text();

        _headerContainer.css("cursor", _imageArray[_imageIndex].TargetURL ? "pointer" : "default");

        if (currentTitle === (_imageArray[_imageIndex].Title || "") && currentDescription === (_imageArray[_imageIndex].Description || ""))
            return;

        var setText = function () {
            _headerInformationTitle.text(_imageArray[_imageIndex].Title || "");
            _headerInformationText.text(_imageArray[_imageIndex].Description || "");
        };

        if (!animationTime) {
            setText();
            return;
        }

        var animationTime = Math.floor(animationTime / 2);

        _headerInformationContent
            .fadeOut(animationTime, setText)
            .fadeIn(animationTime);
    }

    var _switchImages = function (nextImage) {
        var currentImage = _headerContainerInner.children(":eq(0)");
        var nextImage = nextImage.clone();

        if (currentImage.attr("src") == nextImage.attr("src"))
            return;

        Tegud.ImageAnimations.getAnimation()(currentImage, nextImage, _setInfoText);

        _setRotateTimeout();
    };

    return {
        // Public function to initialise the gallery.
        init: function (images) {
            _imageArray = images || [];
            _setRotateTimeout();

            // Set up the information div.
            _headerContainer = $("#HeaderContainer")
                .bind("click", function () {
                    var target = _imageArray[_imageIndex].TargetURL;

                    if (!target)
                        return;

                    $(window).attr("location", target);
                })
                .append(_headerInformationContainer = $("<div />", { id: "HeaderImageInformationContainer" })
                    .append($("<div />", { id: "HeaderImageInformation", css: { opacity: 0.7} }))
                    .append(_headerInformationContent = $("<div />", { id: "HeaderImageInformationContent" })
                        .append($("<div />", { id: "HeaderImageInformationContentContainer" })
                            .append((_headerInformationText = $("<span />")))
                            .append((_headerInformationTitle = $("<h2 />"))))));

            _headerControls = $("#HeaderControls");
            _headerContainerInner = $("#HeaderContainerInner");
            _headerImageBuffer = $("#HeaderImageBuffer");
            _headerLoading = $("#HeaderLoading").css("opacity", 0.7);

            // Create and add the header control items.
            var headerHtml = new Array();
            for (var x = 0; x < _imageArray.length; x++) {
                headerHtml[headerHtml.length] = "<li style=\"left: " + (x * 28) + "px\"/>";
            }

            _headerControls
                .append((_headerControlsMarker = $("<li />", { "class": "Marker" })))
                .append(headerHtml.join(""));

            for (var x = 0; x < _imageArray.length; x++) {
                _headerImageBuffer.append(x > 0
                                ? $("<img src=\"\" class=\"UnLoaded\" />").data("imageSrc", "/Content/" + _imageArray[x].Image)
                                : $("<img src=\"" + "/Content/" + _imageArray[x].Image + "\" />"));
            }

            var centralAreaMouseoutTimer;

            // Bind Button Events
            var centralArea = $("#CentralArea")
                .bind("mouseover", function () {
                    if (centralAreaMouseoutTimer) {
                        clearTimeout(centralAreaMouseoutTimer);
                        centralAreaMouseoutTimer = undefined;
                    }

                    _headerContainer.addClass("Hover");
                })
                .bind("mouseout", function () {
                    if (!centralAreaMouseoutTimer) {
                        centralAreaMouseoutTimer = setTimeout(function () {
                            _headerContainer.removeClass("Hover");
                        }, 100);
                    }
                })
                .delegate("#GalleryLeft, #GalleryRight", "click", function (e) { _shift(e.target.id == "GalleryLeft" ? -1 : 1); })
                .delegate("#HeaderControls > :not(.Marker)", "click", function () { _goto($(this).index() - 1); });

            // if no support for transitions.
            if (!$.support.transition)
                centralArea;

            // Bind the key events for left and right to direct the gallery left or right
            $(document).keydown(function (e) {
                if (e.keyCode != 37 && e.keyCode != 39)
                    return;

                // keyCode 37 is left.
                if (e.keyCode == 37)
                    _shift(-1);
                else
                    _shift(1);
            });

            // Set the info text.
            _setInfoText();

            // Start the loading of the images in the background.
            setTimeout(function () {
                _preLoad();
            }, 1000);
        },
        shift: _shift
    };
} ();

