﻿var imageRotator = Class.create();

imageRotator.prototype = {
    options: undefined,
    divLoading: undefined,
    divLoadingThumbNail: undefined,
    divBigPicture: undefined,
    imgBigPicture: undefined,
    imgBigPictureEffect: undefined,
    thumbNailPicturesContainer: undefined,
    bigPictureUrls: [],
    opacityEffects: [],
    slideInterval: undefined,

    initialize: function(options)
    {
        this.options = Object.extend({
            divBigPicture: undefined,
            imgBigPicture: undefined,
            thumbNailPicturesContainer: undefined,
            isLoading: false,
            loadingImageURL: undefined,
            isLoadingThumbNail: false,
            loadingImageURLThumbNail: undefined,
            activeIndex: 0,
            isSlideShow: false,
            slideFrequency: 10,
            thumbNailStartOpacityValue: 0.5,
            minOpacityValueBigPicture: 0.1,
            opacityUpDurationBigPicture: 0.4,
            opacityDownDurationBigPicture: 0.4,
            opacityUpDurationThumbNail: 0.2,
            opacityDownDurationThumbNail: 0.4
        }, options || {});

        this.divBigPicture = $(this.options.divBigPicture);
        this.imgBigPicture = $(this.options.imgBigPicture);

        if (this.options.isLoading)
            this.prepareDivLoading();

        if (this.options.isLoadingThumbNail)
            this.prepareDivLoadingThumbNail();

        this.thumbNailPicturesContainer = $(this.options.thumbNailPicturesContainer);
        this.prepareThumbNailPicturesContainer();
        try
        {
            this.showFirstPicture();
        }
        catch (err)
        {
            Element.show(this.imgBigPicture);
        }
    },

    prepareDivLoading: function()
    {
        var imgLoading = new Image();
        var marginLeft, marginTop;

        imgLoading.src = this.options.loadingImageURL;
        marginLeft = Math.round((Element.getWidth(this.divBigPicture) - imgLoading.width) / 2);
        marginTop = Math.round((Element.getHeight(this.divBigPicture) - imgLoading.height) / 2);

        this.divLoading = Builder.node(
                                        'div',
                                        {
                                            style: 'display: none; position: absolute;'
                                        },
                                        [Builder.node('img', { src: imgLoading.src })]
                                      );
        Element.setStyle(
                            this.divLoading,
                            {
                                left: Element.cumulativeOffset(this.divBigPicture).left + marginLeft + 'px',
                                top: Element.cumulativeOffset(this.divBigPicture).top + marginTop + 'px'
                            }
                        );

        this.divBigPicture.appendChild(this.divLoading);
    },
    hideDivLoading: function()
    {
        Element.setStyle(this.divLoading, { display: 'none' });
    },
    showDivLoading: function()
    {
        Element.setStyle(this.divLoading, { display: 'block' });
    },

    prepareDivLoadingThumbNail: function()
    {
        var imgLoading = new Image();
        var marginLeft, marginTop;

        imgLoading.src = this.options.loadingImageURLThumbNail;
        this.divLoadingThumbNail = Builder.node(
                                                    'div',
                                                    {
                                                        style: 'display: none; position: absolute;'
                                                    },
                                                    [Builder.node('img', { src: imgLoading.src })]
                                                  );

        document.observe('dom:loaded', function() { document.body.appendChild(this.divLoadingThumbNail); } .bind(this)); // to prevent IE failure on unload 
    },
    hideDivLoadingThumbNail: function()
    {
        Element.setStyle(this.divLoadingThumbNail, { display: 'none' });
    },
    showDivLoadingThumbNail: function(leftPosition, topPosition)
    {
        Element.setStyle(
                            this.divLoadingThumbNail,
                            {
                                left: leftPosition + 'px',
                                top: topPosition + 'px'
                            }
                        );

        Element.setStyle(this.divLoadingThumbNail, { display: 'block' });
    },

    prepareThumbNailPicturesContainer: function()
    {
        var containerRef, imgRef;
        Element.cleanWhitespace(this.thumbNailPicturesContainer);
        for (var i = 0; i < this.thumbNailPicturesContainer.childNodes.length; i++)
        {
            containerRef = this.thumbNailPicturesContainer.childNodes[i];
            imgRef = containerRef.getElementsByTagName('img')[0];

            this.bigPictureUrls[i] = containerRef.title;
            containerRef.removeAttribute('title');

            Element.setOpacity(imgRef, this.options.thumbNailStartOpacityValue);
            Event.observe(containerRef, 'mouseover', this.mouseOverFunction.bindAsEventListener(this, imgRef, i));
            Event.observe(containerRef, 'mouseout', this.mouseOutFunction.bindAsEventListener(this, imgRef, i));
            Event.observe(containerRef, 'click', this.mouseClickFunction.bindAsEventListener(this, containerRef, imgRef, i));
        }
    },

    showFirstPicture: function()
    {
        Element.hide(this.imgBigPicture);
        var containerRef = this.thumbNailPicturesContainer.childNodes[this.options.activeIndex];
        var imgRef = containerRef.getElementsByTagName('img')[0];
        this.mouseClickFunction(this, containerRef, imgRef, this.options.activeIndex);
    },

    mouseOverFunction: function(event, imgElement, index)
    {
        if (this.opacityEffects[index])
            this.opacityEffects[index].cancel();

        this.opacityEffects[index] = new Effect.Opacity(imgElement, { to: 1, duration: this.options.opacityUpDurationThumbNail });
    },

    mouseOutFunction: function(event, imgElement, index)
    {
        if (this.opacityEffects[index])
            this.opacityEffects[index].cancel();

        this.opacityEffects[index] = new Effect.Opacity(imgElement, { to: this.options.thumbNailStartOpacityValue, duration: this.options.opacityDownDurationThumbNail });
    },

    mouseClickFunction: function(event, container, imgElement, index)
    {
        var imgPreLoader = new Image();

        if (this.options.isLoading)
        {
            this.showDivLoading();
            Event.observe(imgPreLoader, 'load', this.hideDivLoading.bind(this));
        }

        if (this.options.isLoadingThumbNail)
        {
            this.showDivLoadingThumbNail(
                                            Element.cumulativeOffset(container).left + Math.round((Element.getWidth(container) - Element.getWidth(this.divLoadingThumbNail)) / 2),
                                            Element.cumulativeOffset(container).top + Math.round((Element.getHeight(container) - Element.getHeight(this.divLoadingThumbNail)) / 2)
                                        );
            Event.observe(imgPreLoader, 'load', this.hideDivLoadingThumbNail.bind(this));
        }

        if (this.options.isSlideShow)
        {
            this.stopSlideShow();
            Event.observe(imgPreLoader, 'load', this.startSlideShow.bindAsEventListener(this));
        }

        Event.observe(imgPreLoader, 'load', this.changeImageEffect.bindAsEventListener(this, imgPreLoader));
        Event.observe(imgPreLoader, 'load', this.setThumbNails.bindAsEventListener(this, container, imgElement, index));
        Event.observe(imgPreLoader, 'load', this.updateThumbNails.bindAsEventListener(this, index));
        imgPreLoader.src = this.bigPictureUrls[index];
    },

    changeImageEffect: function(event, imgPreLoader)
    {
        if (this.imgBigPictureEffect)
            this.imgBigPictureEffect.cancel();

        this.imgBigPictureEffect = new Effect.Opacity(
                                                        this.imgBigPicture,
                                                        {
                                                            to: this.options.minOpacityValueBigPicture,
                                                            duration: this.options.opacityDownDurationBigPicture,
                                                            afterFinish: function(event)
                                                            {
                                                                this.imgBigPicture.src = imgPreLoader.src;
                                                                if (!Element.visible(this.imgBigPicture))
                                                                    Element.show(this.imgBigPicture);
                                                                this.imgBigPictureEffect = new Effect.Opacity(this.imgBigPicture, { to: 1, duration: this.options.opacityUpDurationBigPicture });
                                                            } .bind(this)
                                                        }
                                                    );
    },

    setThumbNails: function(event, container, imgElement, index)
    {
        var activeIndex = this.options.activeIndex;
        var activeContainer = this.thumbNailPicturesContainer.childNodes[activeIndex];
        var activeImg = activeContainer.getElementsByTagName('img')[0];

        this.mouseOutFunction(this, activeImg, activeIndex);
        Event.observe(activeContainer, 'mouseover', this.mouseOverFunction.bindAsEventListener(this, activeImg, activeIndex));
        Event.observe(activeContainer, 'mouseout', this.mouseOutFunction.bindAsEventListener(this, activeImg, activeIndex));
        Event.observe(activeContainer, 'click', this.mouseClickFunction.bindAsEventListener(this, activeContainer, activeImg, activeIndex));

        Event.stopObserving(container, 'mouseover');
        Event.stopObserving(container, 'mouseout');
        Event.stopObserving(container, 'click');

        this.options.activeIndex = index;
    },

    updateThumbNails: function(event, index)
    {
        if (this.opacityEffects[index])
            this.opacityEffects[index].cancel();

        Element.setOpacity(this.thumbNailPicturesContainer.childNodes[index].getElementsByTagName('img')[0], 1);
    },

    startSlideShow: function()
    {
        this.loadNextImage();
        this.slideInterval = new PeriodicalExecuter(this.showNextImage.bind(this), this.options.slideFrequency);
    },
    stopSlideShow: function()
    {
        if (this.slideInterval)
            this.slideInterval.stop();
    },
    loadNextImage: function()
    {
        var imgPreLoader = new Image();
        imgPreLoader.src = this.bigPictureUrls[(this.options.activeIndex + 1) % this.thumbNailPicturesContainer.childNodes.length];
    },
    showNextImage: function(event)
    {
        var index = (this.options.activeIndex + 1) % this.thumbNailPicturesContainer.childNodes.length;
        var containerRef = this.thumbNailPicturesContainer.childNodes[index];
        var imgRef = containerRef.getElementsByTagName('img')[0];
        this.mouseClickFunction(this, containerRef, imgRef, index);
        this.loadNextImage();
    }
}
