var Slideshow = new function()
{
    // Private Members
    var caption = null;
    var closeButton = null;
    var closeButtonImage = null;
    var currentSource = null;
    var imageDetails = null;
    var initialized = false;
    var navigation = null;
    var navigationCaption = null;
    var navigationSeparator = null;
    var nextButton = null;
    var overlayOpacity = 0.5;
    var overlay = null;
    var previousButton = null;
    var self = this;
    var slide = null;
    var slideshowContainer = null;
    var slideshowLoadingIcon = null;
    var slideshowSets = new Object();

    // Private Methods
    function CreateAndAddSource(_element)
    {
        var setName = _element.readAttribute('rel');

        if (!slideshowSets[setName])
        {
            slideshowSets[setName] = new Array();
        }

        slideshowSets[setName].push(new Source(_element));
    }

    function Dispose()
    {
        // Stop the slideshow if we're in one
        self.StopSlideshow();

        // Dispose of all the sources
        for (var setIndex in slideshowSets)
        {
            var mySet = slideshowSets[setIndex];
            
            for (var i = 0, length = mySet.length; i < length; ++i)
            {
                mySet[i].Dispose();
            }
            mySet.clear();
        }

        slideshowSets = new Object();
    }

    function LoadImage()
    {
        // Hide the slideshow container
        slideshowContainer.setStyle({display: 'none'});

        // Reset the caption width
        //caption.setStyle({ width: 'auto' });

        // Show the loading image
        slideshowLoadingIcon.setStyle({display: 'inline'});

        // Set the caption or hide the caption element
        caption.setStyle({display: (currentSource.Caption.length > 0 ? 'inline' : 'none')}).update(currentSource.Caption);

        // Set the navigation caption
        if (slideshowSets[currentSource.SetName] && slideshowSets[currentSource.SetName].length > 1)
        {
            navigationCaption.update('Image ' + (currentSource.SetPosition + 1) + ' of ' + slideshowSets[currentSource.SetName].length);
        }

        // Show or hide the navigation buttons
        nextButton.setStyle({display: (slideshowSets[currentSource.SetName] && slideshowSets[currentSource.SetName].length > 1) ? 'inline' : 'none'});
        previousButton.setStyle({display: (slideshowSets[currentSource.SetName] && slideshowSets[currentSource.SetName].length > 1) ? 'inline' : 'none'});
        navigationSeparator.setStyle({display: (slideshowSets[currentSource.SetName] && slideshowSets[currentSource.SetName].length > 1) ? 'inline' : 'none'});
        navigation.setStyle({display: (slideshowSets[currentSource.SetName] && slideshowSets[currentSource.SetName].length > 1) ? 'block' : 'none'})

        // Set the url of the image
        slide.src = currentSource.ImageUrl;
    }

    function ShowOverlayAndLoadImage()
    {
        // Set the opacity to 0 and display to block
        overlay.setStyle({opacity: 0.0, display: 'block'});

        // Now fade in the overlay
        new Effect.Opacity(overlay, {from: 0.0, to: overlayOpacity, duration: 0.3, afterFinish: LoadImage});
    }


    // Priviledged Methods
    this.AddSource = function(_source)
    {
        var setName = _source.SetName;
        
        if (!slideshowSets[setName])
        {
            slideshowSets[setName] = new Array();
        }

        _source.SetPosition = slideshowSets[setName].length;
        slideshowSets[setName].push(_source);
    }
    
    this.Initialize = function()
    {
        if (!initialized)
        {
            overlay = new Element('div', {'class': 'Slideshow_Overlay'});
            slideshowContainer = new Element('div', {'class': 'Slideshow_Container'});
            slideshowLoadingIcon = new Element('img', {'class': 'Slideshow_LoadingIcon', 'src': '/images/icons/loading.gif'});
            slide = new Element('img', {'class': 'Slideshow_Slide'});
            imageDetails = new Element('div', {'class': 'Slideshow_ImageDetails'});
            navigation = new Element('div', {'class': 'Slideshow_Navigation'});
            navigationCaption = new Element('span', {'class': 'Slideshow_NavigationCaption'});
            previousButton = new Element('a', {'class': 'Slideshow_PreviousButton', 'href': '#'}).update('Previous');
            navigationSeparator = new Element('span', {'class': 'Slideshow_NavigationSeparator'}).update('|');
            nextButton = new Element('a', {'class': 'Slideshow_NextButton', 'href': '#'}).update('Next');
            closeButton = new Element('a', {'class': 'Slideshow_CloseButton', 'href': '#'});
            closeButtonImage = new Element('img', {'src': '/images/icons/close-button.png'});
            caption = new Element('span', {'class': 'Slideshow_Caption'});

            // Build the overlay and slideshow markup
            $(document.body).insert(overlay);
            $(document.body).insert(slideshowLoadingIcon);
            $(document.body).insert(slideshowContainer);
            slideshowContainer.insert(navigation);
            slideshowContainer.insert(closeButton);
            slideshowContainer.insert(slide);
            slideshowContainer.insert(imageDetails);
            imageDetails.insert(caption);
            navigation.insert(navigationCaption);
            navigation.insert(previousButton);
            navigation.insert(navigationSeparator);
            navigation.insert(nextButton);
            closeButton.insert(closeButtonImage);

            /* sample html */
            /*
            <div class="Slideshow">
            <img />
            <div class="ImageDetails">
            <div class="Navigation"><span class="NavigationCaption">Image 1 of 5</span><a class="PreviousButton">Previous</a><span class="NavigationSeparator">|</span><a class="NextButton">Next</a><a class="CloseButton">close</a></div>
            <div class="Caption">Caption</div>                
            </div>            
            </div>
            */

            // Attach all the event handlers
            previousButton.observe('click', PreviousButton_Click);
            nextButton.observe('click', NextButton_Click);
            closeButton.observe('click', CloseButton_Click);
            overlay.observe('click', Overlay_Click);
            slide.observe('load', Slide_Loaded);
        }
        else
        {
            // We need to dispose of current sources and re-parse the dom
            try
            {
                Dispose();
            }
            catch (e)
            {
                console.log(e);
            }
        }

        // Find all the slideshow links
        var anchors = $$('a');

        // loop through all anchor tags
        for (var i = 0, length = anchors.length; i < length; ++i)
        {
            var anchor = anchors[i];
            var relAttribute = String(anchor.readAttribute('rel'));

            // use the string.match() method to catch 'slideshow' references in the rel attribute
            if (anchor.readAttribute('href') && (relAttribute.toLowerCase().match('slideshow')))
            {
                CreateAndAddSource(anchor);
            }
        }

        initialized = true;
    }

    this.ShowImage = function(source)
    {
        if (source)
        {
            currentSource = source;

            // Show the overlay if it's not already shown
            if (overlay.getStyle('display') != 'block')
            {
                ShowOverlayAndLoadImage();
            }
            else
            {
                LoadImage();
            }
        }
    }

    this.StopSlideshow = function()
    {
        currentSource = null;

        // Hide the slideshow container
        new Effect.Opacity(slideshowContainer, {from: 1.0, to: 0.0, duration: 0.3, afterFinish: function(event){
        
            //Hide the container
            slideshowContainer.setStyle({display: 'none'});
            
            // Clear the source of the image slide
            slide.src = '';

            // Hide the loading image
            slideshowLoadingIcon.setStyle({display: 'none'});

            // Fade out the overlay
            new Effect.Opacity(overlay, {from: overlayOpacity, to: 0.0, duration: 0.3, afterFinish: function() {overlay.setStyle({display: 'none'});}});
        
        }});
    }


    // Event Handlers
    function CloseButton_Click(e)
    {
        Slideshow.StopSlideshow();
        e.stop();
    }

    function NextButton_Click(e)
    {
        // Hide the slideshow container
        new Effect.Opacity(slideshowContainer, {from: 1.0, to: 0.0, duration: 0.3, afterFinish: function() {Slideshow.ShowImage(slideshowSets[currentSource.SetName][(currentSource.SetPosition + 1 + slideshowSets[currentSource.SetName].length) % slideshowSets[currentSource.SetName].length]);}});

        e.stop();
    }

    function PreviousButton_Click(e)
    {
        // Hide the slideshow container
        new Effect.Opacity(slideshowContainer, {from: 1.0, to: 0.0, duration: 0.3, afterFinish: function() {Slideshow.ShowImage(slideshowSets[currentSource.SetName][(currentSource.SetPosition - 1 + slideshowSets[currentSource.SetName].length) % slideshowSets[currentSource.SetName].length]);}});

        e.stop();
    }

    function Overlay_Click(e)
    {
        Slideshow.StopSlideshow();
        e.stop();
    }

    function Slide_Loaded(e)
    {
        window.setTimeout(function()
        {
            // Set the visibility and display of the container
            slideshowContainer.setStyle({visibility: 'hidden', display: 'block'});
            var slideshowContainerOffset = slideshowContainer.viewportOffset();
            
            if(!slideshowContainerOffset || slideshowContainerOffset.top < 0 || slideshowContainerOffset.left < 0)
            {
                // Scroll the window to the slideshows location
                new Effect.ScrollTo('MainMenu', {duration:0.5, afterFinish:function()
                {
                    // Get the dimensions of the container
                    var dimensions = slideshowContainer.getDimensions();
                    var _marginLeft = '-' + Math.ceil(dimensions.width / 2) + 'px';

                    // Hide the loading image
                    slideshowLoadingIcon.setStyle({display: 'none'});

                    // Set the position based on the container size
                    slideshowContainer.setStyle({marginLeft: _marginLeft, opacity: 0.0, visibility: 'visible'});
                    new Effect.Opacity(slideshowContainer, {from: 0.0, to: 1.0, duration: 0.3});
                }});
            }
            else
            {
                // Get the dimensions of the container
                var dimensions = slideshowContainer.getDimensions();
                var _marginLeft = '-' + Math.ceil(dimensions.width / 2) + 'px';

                // Hide the loading image
                slideshowLoadingIcon.setStyle({display: 'none'});

                // Set the position based on the container size
                slideshowContainer.setStyle({marginLeft: _marginLeft, opacity: 0.0, visibility: 'visible'});
                new Effect.Opacity(slideshowContainer, {from: 0.0, to: 1.0, duration: 0.3});
            }
        }, 100);
    }

    // Private Classes
    Source = function(_element)
    {
        // Private Members
        var element = _element;
        var self = this;

        // Public Properties
        this.Caption = element.readAttribute('title') || '';
        this.SetName = element.readAttribute('rel');
        this.SetPosition = slideshowSets[self.SetName].length;
        this.ImageUrl = element.readAttribute('href');

        // Event Handlers
        function OnClick(e)
        {
            Slideshow.ShowImage(self);
            e.stop();
            return false;
        }

        // Priviledged Methods
        this.Dispose = function()
        {
            element.stopObserving('click', OnClick);
        }

        element.observe('click', OnClick);
        element.setAttribute('title', '');
    }
}

Event.observe(window, 'load', function() {Slideshow.Initialize();});
