


/// <reference name="MicrosoftAjax.debug.js" />
/// <reference path="../ExtenderBase/BaseScripts.js" />
/// <reference path="../Common/Common.js" />
/// <reference path="../Compat/Timer/Timer.js" />

(function () {
    var scriptName = "ExtendedSlideShow";

    function execute() {

        Type.registerNamespace('Sys.Extended.UI');
        Sys.Extended.UI.SlideShowBehavior = function (element) {
            /// <summary>
            /// creates a new slide show behavior
            /// </summary>
            /// <param name="element" type="Sys.UI.DomElement" DomElement="true" mayBeNull="false" />
            /// <returns />
            Sys.Extended.UI.SlideShowBehavior.initializeBase(this, [element]);
            // Properties
            this._nextButtonID = null;
            this._previousButtonID = null;
            this._imageDescriptionLabelID = null;
            this._imageTitleLabelID = null;
            this._playButtonID = null;
            this._playButtonValue = '||>';
            this._stopButtonValue = '[]';
            this._slideShowServicePath = location.pathname;
            this._slideShowServiceMethod = null;
            this._contextKey = null;
            this._useContextKey = false;
            this._playInterval = 3000;
            this._tickHandler = null;
            this._loop = false;
            this._autoPlay = false;

            // Variables
            this._inPlayMode = false;
            this._elementImage = null;
            this._bNext = null;
            this._bPrevious = null;
            this._currentIndex = -1;
            this._currentValue = null;
            this._imageDescriptionLabel = null;
            this._imageTitleLabel = null;
            this._bPlay = null;
            this._slides = null;
            this._timer = null;
            this._currentImageElement = null;
            this._images = null;
            this._cachedImageIndex = -1;

            // Delegates
            this._clickNextHandler = null;
            this._clickPreviousHandler = null;
            this._clickPlayHandler = null;
            this._tickHandler = null;
            this._imageLoadedHandler = null;

        }
        Sys.Extended.UI.SlideShowBehavior.prototype = {
            initialize: function () {
                ///<summary>
                /// Initialize the slide show.
                /// </summary>
                /// <returns />      

                Sys.Extended.UI.SlideShowBehavior.callBaseMethod(this, 'initialize');
                var e = this.get_element();
                this._elementImage = e;

                // create an invisible img element
                this._currentImageElement = document.createElement('IMG');
                this._currentImageElement.style.display = 'none';
                document.body.appendChild(this._currentImageElement);

                //Create a new parent for Image
                var _divContent = document.createElement('DIV');
                e.parentNode.insertBefore(_divContent, e);
                e.parentNode.removeChild(e);
                _divContent.appendChild(e);
                _divContent.align = 'center';

                this.controlsSetup();
                // Create handlers for slide show buttons clicks events and for image loaded events.
                if (this._bNext) {
                    this._clickNextHandler = Function.createDelegate(this, this._onClickNext);
                    $addHandler(this._bNext, 'click', this._clickNextHandler);
                }
                if (this._bPrevious) {
                    this._clickPreviousHandler = Function.createDelegate(this, this._onClickPrevious);
                    $addHandler(this._bPrevious, 'click', this._clickPreviousHandler);
                }
                if (this._bPlay) {
                    this._clickPlayHandler = Function.createDelegate(this, this._onClickPlay);
                    $addHandler(this._bPlay, 'click', this._clickPlayHandler);
                }

                this._imageLoadedHandler = Function.createDelegate(this, this._onImageLoaded);
                $addHandler(this._currentImageElement, 'load', this._imageLoadedHandler);

                // init slide show
                this._slideShowInit();
            },

            dispose: function () {
                ///<summary>
                /// Dispose the handlers and perform other slide show cleanup.
                /// </summary>
                /// <returns />      

                if (this._clickNextHandler) {
                    $removeHandler(this._bNext, 'click', this._clickNextHandler);
                    this._clickNextHandler = null;
                }
                if (this._clickPreviousHandler) {
                    $removeHandler(this._bPrevious, 'click', this._clickPreviousHandler);
                    this._clickPreviousHandler = null;
                }
                if (this._clickPlayHandler) {
                    $removeHandler(this._bPlay, 'click', this._clickPlayHandler);
                    this._clickPlayHandler = null;
                }
                if (this._imageLoadedHandler) {
                    $removeHandler(this._currentImageElement, 'load', this._imageLoadedHandler);
                    this._imageLoadedHandler = null;
                }
                if (this._timer) {
                    this._timer.dispose();
                    this._timer = null;
                }
                Sys.Extended.UI.SlideShowBehavior.callBaseMethod(this, 'dispose');
            },

            add_slideChanged: function (handler) {
                ///<summary>
                /// Add handler for the <code>slideChanged</code> Event.
                /// </summary>
                /// <param name="handler" type="Function" mayBeNull="false" />   
                /// <returns />       
                this.get_events().addHandler('slideChanged', handler);
            },
            remove_slideChanged: function (handler) {
                ///<summary>
                /// Remove handler for the <code>slideChanged</code> Event.
                /// </summary>
                /// <param name="handler" type="Function" mayBeNull="false"/>   
                /// <returns />     
                this.get_events().removeHandler('slideChanged', handler);
            },
            raiseSlideChanged: function (eventArgs) {
                ///<summary>
                /// Raise the <code>slideChanged</code> Event.
                /// </summary>
                /// <param name="eventArgs" type="Sys.EventArgs" mayBeNull="true"/>   
                /// <returns />      
                var handler = this.get_events().getHandler('slideChanged');
                if (handler) {
                    if (!eventArgs) {
                        eventArgs = Sys.EventArgs.Empty;
                    }
                    handler(this, eventArgs);
                }
            },

            add_slideChanging: function (handler) {
                ///<summary>
                /// Add handler for the <code>slideChanging</code> Event.
                /// </summary>
                /// <param name="handler" type="Function" mayBeNull="false" />   
                /// <returns />      
                this.get_events().addHandler('slideChanging', handler);
            },
            remove_slideChanging: function (handler) {
                ///<summary>
                /// Remove handler for the <code>slideChanging</code> Event.
                /// </summary>
                /// <param name="handler" type="Function" mayBeNull="false"/>   
                /// <returns />       
                this.get_events().removeHandler('slideChanging', handler);
            },
            raiseSlideChanging: function (previousSlide, newSlide) {
                ///<summary>
                /// Raise the <code>slideChanging</code> Event.
                /// </summary>
                /// <param name="previousSlide" type="Object" mayBeNull="true"/>   
                /// <param name="nextSlide" type="Object" mayBeNull="true"/>           
                /// <returns type="Boolean" />       
                var handler = this.get_events().getHandler('slideChanging');
                if (handler) {
                    var eventArgs = new Sys.Extended.UI.SlideShowEventArgs(previousSlide, newSlide, this._currentIndex);
                    handler(this, eventArgs);
                    return eventArgs.get_cancel();
                }
                return false;
            },

            get_contextKey: function () {
                /// <value type="String" mayBeNull="true">
                /// User/page specific context provided to an optional overload of the
                /// web method described by ServiceMethod/ServicePath.  If the context
                /// key is used, it should have the same signature with an additional
                /// parameter named contextKey of type string.
                /// </value>
                return this._contextKey;
            },
            set_contextKey: function (value) {
                if (this._contextKey != value) {
                    this._contextKey = value;
                    this.set_useContextKey(true);
                    // if initialize has not been called
                    // then do not reset the slideshow.
                    if (this._elementImage) {
                        this._slideShowInit();
                    }
                    this.raisePropertyChanged('contextKey');
                }
            },

            get_useContextKey: function () {
                /// <value type="Boolean">
                /// Whether or not the ContextKey property should be used.  This will be
                /// automatically enabled if the ContextKey property is ever set
                /// (on either the client or the server).  If the context key is used,
                /// it should have the same signature with an additional parameter
                /// named contextKey of type string.
                /// </value>
                return this._useContextKey;
            },
            set_useContextKey: function (value) {
                if (this._useContextKey != value) {
                    this._useContextKey = value;
                    this.raisePropertyChanged('useContextKey');
                }
            },


            controlsSetup: function () {
                /// <summary>
                /// Get handles to various slide show controls if specified.
                /// </summary>      
                /// <returns />
                if (this._previousButtonID) {
                    this._bPrevious = document.getElementById(this._previousButtonID);
                }
                if (this._imageDescriptionLabelID) {
                    this._imageDescriptionLabel = document.getElementById(this._imageDescriptionLabelID);
                }
                if (this._imageTitleLabelID) {
                    this._imageTitleLabel = document.getElementById(this._imageTitleLabelID);
                }
                if (this._nextButtonID) {
                    this._bNext = document.getElementById(this._nextButtonID);
                }
                if (this._playButtonID) {
                    this._bPlay = document.getElementById(this._playButtonID);
                    this._bPlay.value = this._playButtonValue;
                }
            },

            resetButtons: function () {
                /// <summary>
                /// Maintain the various buttons states.
                /// </summary>    
                /// <returns />  

                if (!this._loop) {
                    // at the last slide
                    if (this._slides.length <= this._currentIndex + 1) {
                        if (this._bNext) this._bNext.disabled = true;
                        if (this._bPlay) this._bPlay.disabled = true;
                        if (this._bPrevious) this._bPrevious.disabled = false;
                        // turn off play mode if on
                        this._inPlayMode = false;
                        if (this._timer) {
                            this._timer.set_enabled(false);
                        }
                        if (this._bPlay) this._bPlay.value = this._playButtonValue;

                    } else {
                        if (this._bNext) this._bNext.disabled = false;
                        if (this._bPlay) this._bPlay.disabled = false;
                    }
                    // at the first slide
                    if (this._currentIndex <= 0) {
                        if (this._bPrevious) this._bPrevious.disabled = true;
                    } else {
                        if (this._bPrevious) this._bPrevious.disabled = false;
                    }
                }
                else {
                    if (this._slides.length == 0) {
                        if (this._bPrevious) this._bPrevious.disabled = true;
                        if (this._bNext) this._bNext.disabled = true;
                        if (this._bPlay) this._bPlay.disabled = true;
                    }
                }
                if (this._inPlayMode) {
                    // restart timer
                    this._timer.set_enabled(false);
                    this._timer.set_enabled(true);
                }
            },

            resetSlideShowButtonState: function () {
                /// <summary>
                /// Maintain the play button state to reflect whether the slide show is in play mode.
                /// </summary>       
                /// <returns />      

                if (this._inPlayMode) {
                    if (this._bPlay) this._bPlay.value = this._stopButtonValue;
                }
                else {
                    this.resetButtons();
                    if (this._bPlay) this._bPlay.value = this._playButtonValue;
                }
            },

            setCurrentImage: function () {
                /// <summary>
                /// Retrieve the current image.
                /// </summary>  
                /// <returns />    
                if (this._slides[this._currentIndex]) {
                    this._currentImageElement.src = this._slides[this._currentIndex].ImagePath;
                } else {
                    this._currentImageElement.src = '';
                }
                if (Sys.Browser.agent == Sys.Browser.Opera) {
                    // call the handler explicitly for opera
                    this._onImageLoaded(true);
                }
            },

            updateImage: function (value) {
                /// <summary>
                /// Set current image to be the specified Slide.
                /// </summary>  
                /// <param name="value" type="Object" mayBeNull="false" />
                /// <returns />

                if (value) {
                    if (this.raiseSlideChanging(this._currentValue, value)) {
                        return;
                    }
                    var altimg = $get(this._elementImage.id + "_alt");
                    if (altimg)
                        if (this._elementImage.src.indexOf('/blank.gif')>=0)
                            altimg.style.display = "none";
                        else {
                            //alert(this._elementImage.src);
                            altimg.src = this._elementImage.src;
                            altimg.style.width = this._elementImage.style.width;
                            altimg.style.height = this._elementImage.style.height;
                            altimg.style.left = this._elementImage.offsetLeft;
                            altimg.style.top = this._elementImage.offsetTop;
                            altimg.style.display = "inline";
                            //slideshow._elementImage.style.display="none";
                            Sys.Extended.UI.Animation.FadeOutAnimation.play(altimg, 1);
                        }

                    this._currentValue = value;
                    this._elementImage.src = value.ImagePath;
                    this._elementImage.alt = value.Name;

                    if (this._imageDescriptionLabel) {
                        this._imageDescriptionLabel.innerHTML = value.Description ? value.Description : "";
                    }
                    if (this._imageTitleLabel) {
                        this._imageTitleLabel.innerHTML = value.Name ? value.Name : "";
                    }

                    Sys.Extended.UI.Animation.FadeInAnimation.play(this._elementImage, 1);

                    this.raiseSlideChanged(value);
                    this.resetButtons();
                }
            },

            get_imageDescriptionLabelID: function () {
                /// <value type="String" mayBeNull="true">    
                /// ID of the label that describes the current slide.
                /// </value>
                return this._imageDescriptionLabelID;
            },
            set_imageDescriptionLabelID: function (value) {
                if (this._imageDescriptionLabelID != value) {
                    this._imageDescriptionLabelID = value;
                    this.raisePropertyChanged('imageDescriptionLabelID');
                }
            },

            get_imageTitleLabelID: function () {
                /// <value type="String" mayBeNull="true">    
                /// ID of the label that shows the title of the current slide.
                /// </value>
                return this._imageTitleLabelID;
            },
            set_imageTitleLabelID: function (value) {
                if (this._imageTitleLabelID != value) {
                    this._imageTitleLabelID = value;
                    this.raisePropertyChanged('imageTitleLabelID');
                }
            },

            get_nextButtonID: function () {
                /// <value type="String" mayBeNull="true">    
                /// ID on the next button.
                /// </value>        
                return this._nextButtonID;
            },
            set_nextButtonID: function (value) {
                if (this._nextButtonID != value) {
                    this._nextButtonID = value;
                    this.raisePropertyChanged('nextButtonID');
                }
            },

            get_playButtonID: function () {
                /// <value type="String" mayBeNull="true">    
                /// ID on the play button.    
                /// </value>        
                return this._playButtonID;
            },
            set_playButtonID: function (value) {
                if (this._playButtonID != value) {
                    this._playButtonID = value;
                    this.raisePropertyChanged('playButtonID');
                }
            },

            get_playButtonText: function () {
                /// <value type="String" mayBeNull="true">    
                /// Text in play button to play the slide show when it is not playing.    
                /// </value>        
                return this._playButtonValue;
            },
            set_playButtonText: function (value) {
                if (this._playButtonValue != value) {
                    this._playButtonValue = value;
                    this.raisePropertyChanged('playButtonText');
                }
            },

            get_stopButtonText: function () {
                /// <value type="String" mayBeNull="true">    
                /// Text in play button to stop the slide show when it is playing.
                /// </value>        
                return this._stopButtonValue;
            },
            set_stopButtonText: function (value) {
                if (this._stopButtonValue != value) {
                    this._stopButtonValue = value;
                    this.raisePropertyChanged('stopButtonText');
                }
            },

            get_playInterval: function () {
                /// <value type="Number" integer="true" mayBeNull="true">    
                /// Interval in milliseconds between slide switches.
                /// </value>        
                return this._playInterval;
            },
            set_playInterval: function (value) {
                if (this._playInterval != value) {
                    this._playInterval = value;
                    this.raisePropertyChanged('playInterval');
                }
            },

            get_previousButtonID: function () {
                /// <value type="String" mayBeNull="true">
                /// ID of the previous button.
                /// </value>
                return this._previousButtonID;
            },
            set_previousButtonID: function (value) {
                if (this._previousButtonID != value) {
                    this._previousButtonID = value;
                    this.raisePropertyChanged('previousButtonID');
                }
            },

            get_slideShowServicePath: function () {
                /// <value type="String" mayBeNull="true">
                /// Slide show webservice path to pull the images.
                /// </value>        
                return this._slideShowServicePath;
            },

            set_slideShowServicePath: function (value) {
                if (this._slideShowServicePath != value) {
                    this._slideShowServicePath = value;
                    this.raisePropertyChanged('slideShowServicePath');
                }
            },

            get_slideShowServiceMethod: function () {
                /// <value type="String" mayBeNull="false">
                /// Slide show webservice methods that will return the slide images.
                /// </value>        
                return this._slideShowServiceMethod;
            },
            set_slideShowServiceMethod: function (value) {
                if (this._slideShowServiceMethod != value) {
                    this._slideShowServiceMethod = value;
                    this.raisePropertyChanged('slideShowServiceMethod');
                }
            },

            get_loop: function () {
                /// <value type="Boolean" mayBeNull="true">
                /// boolean to detect if slideshow should wrap around on hitting the first/last slides.
                /// </value>
                return this._loop;
            },
            set_loop: function (value) {
                if (this._loop != value) {
                    this._loop = value;
                    this.raisePropertyChanged('loop');
                }
            },

            get_autoPlay: function () {
                /// <value type="Boolean" mayBeNull="true">
                /// boolean to detect if slide show should start playing on render.
                /// </value>
                return this._autoPlay;
            },
            set_autoPlay: function (value) {
                if (this._autoPlay != value) {
                    this._autoPlay = value;
                    this.raisePropertyChanged('autoPlay');
                }
            },

            _onClickNext: function (e) {
                /// <summary>
                /// Next button click handler.
                /// </summary>      
                /// <param name="e" type="Sys.UI.DomEvent" mayBeNull="false" />   
                /// <returns />  

                // prevent server post-back for asp.net buttons.
                e.preventDefault();
                e.stopPropagation();
                this._clickNext();
            },

            _onImageLoaded: function (e) {
                /// <summary>
                /// Image loaded handler.
                /// </summary>
                /// <param name="e" type="Sys.UI.DomEvent" mayBeNull="false"/>   
                /// <returns />      
                this.updateImage(this._slides[this._currentIndex]);
                this.resetButtons();
                this._cacheImages();
            },

            _clickNext: function () {
                /// <summary>
                /// Switches slide show to displaying the next slide.
                /// </summary>  
                /// <returns />  

                if (this._slides) {
                    if ((this._currentIndex + 1) < this._slides.length) {
                        ++this._currentIndex;
                    } else if (this._loop) {
                        this._currentIndex = 0;
                    } else {
                        return false;
                    }
                    this.setCurrentImage();
                    return true;
                }
                return false;
            },

            _onClickPrevious: function (e) {
                /// <summary>
                /// Previous button click handler.
                /// </summary>
                /// <param name="e" type="Sys.UI.DomEvent" mayBeNull="false"/>   
                /// <returns />  

                // prevent server post-back for asp.net buttons.
                e.preventDefault();
                e.stopPropagation();
                this._clickPrevious();

            },

            _clickPrevious: function () {
                /// <summary>
                /// Switches slide show to displaying the previous slide.
                /// </summary>    
                /// <returns />          

                if (this._slides) {
                    if ((this._currentIndex - 1) >= 0) {
                        --this._currentIndex;
                    }
                    else if (this._loop) {
                        this._currentIndex = this._slides.length - 1;
                    } else {
                        return false;
                    }
                    this.setCurrentImage();
                    return true;
                }
                return false;
            },

            _onClickPlay: function (e) {
                /// <summary>
                /// Play button click handler.
                /// </summary>
                /// <param name="e" type="Sys.UI.DomEvent" mayBeNull="false"/>   
                /// <returns />

                // prevent server post-back for asp.net buttons.
                e.preventDefault();
                e.stopPropagation();
                this._play();
            },

            _play: function () {
                /// <summary>
                /// Maintains timer state/slide show buttons state and creates handler to switch images in play mode
                /// if not already in play mode.
                /// </summary>   
                /// <returns />
                if (this._inPlayMode) {
                    this._inPlayMode = false;
                    this._timer.set_enabled(false);
                    this.resetSlideShowButtonState();
                } else {
                    // play the side show
                    this._inPlayMode = true;
                    if (!this._timer) {
                        this._timer = new Sys.Timer();
                        this._timer.set_interval(this._playInterval);
                        this._tickHandler = Function.createDelegate(this, this._onPlay);
                        this._timer.add_tick(this._tickHandler);
                    }
                    this.resetSlideShowButtonState();
                    this._timer.set_enabled(true);
                }
            },

            _onPlay: function (e) {
                /// <summary>
                /// Sets the slide show to the current image in play mode and maintains button state.
                /// </summary>   
                /// <param name="e" type="Sys.UI.DomEvent" mayBeNull="false"/>
                /// <returns type="Boolean" />
                if (this._slides) {
                    if ((this._currentIndex + 1) < this._slides.length) {
                        ++this._currentIndex;
                        this.setCurrentImage();
                        return true;
                    } else if (this._loop) {
                        this._currentIndex = 0;
                        this.setCurrentImage();
                        return true;
                    } else {
                        this._inPlayMode = false;
                        this.resetSlideShowButtonState();
                    }
                }
                return false;
            },

            _slideShowInit: function () {
                /// <summary>
                /// Initializes the slide show by invoking the webservice to retrieve the slides
                /// and sets the first slide.
                /// </summary>
                /// <returns />
                // clear the state of the slideshow
                this._currentIndex = -1;
                this._cachedImageIndex = -1;
                this._inPlayMode = false;
                this._currentValue = null;
                // clear the cache
                this._images = null;
                // Create the service parameters and optionally add the context parameter
                // (thereby determining which method signature we're expecting...)
                var params = null;
                if (this._useContextKey) {
                    params = { contextKey: this._contextKey };
                }

                Sys.Net.WebServiceProxy.invoke(
                this._slideShowServicePath,
                this._slideShowServiceMethod,
                false,
                params,
                Function.createDelegate(this, this._initSlides),
                null,
                null);
            },

            _initSlides: function (sender, eventArgs) {
                /// <summary>
                /// Initializes the slide show with the first image and configures the specified play settings.
                /// </summary>
                /// <param name="sender" type="Object" mayBeNull="true"/>
                /// <param name="eventArgs" type="Sys.EventArgs" mayBeNull="true" />
                /// <returns />

                this._slides = sender;
                if (this._slides) {
                    this._images = new Array();
                    this._clickNext();
                    if (this._autoPlay) {
                        this._play();
                    }
                }
            },

            _cacheImages: function () {
                /// <summary>
                /// Caches 4 more slides periodically.
                /// </summary>
                /// <returns />

                // cache if current index is divisible by 3
                if ((this._currentIndex) % 3 == 0) {
                    var oldCachedImageIndex = this._cachedImageIndex;
                    for (var i = this._cachedImageIndex + 1; i < this._slides.length; i++) {
                        if (this._slides[i]) {
                            this._images[i] = new Image();
                            this._images[i].src = this._slides[i].ImagePath;
                            this._cachedImageIndex = i;
                            if ((oldCachedImageIndex + 4) <= i) {
                                // cached 4 slides
                                break;
                            }
                        }
                    }
                }
            }

        }
        Sys.Extended.UI.SlideShowBehavior.registerClass('Sys.Extended.UI.SlideShowBehavior', Sys.Extended.UI.BehaviorBase);
        Sys.registerComponent(Sys.Extended.UI.SlideShowBehavior, { name: "slideShow" });

        Sys.Extended.UI.SlideShowEventArgs = function (previousSlide, nextSlide, slideIndex) {
            /// <summary>
            /// Event arguments for the SlideShowBehavior's slideChanging event
            /// </summary>
            /// <param name="previousSlide" type="Object" mayBeNull="true" />
            /// <param name="nextSlide" type="Object" mayBeNull="true" />
            /// <param name="slideIndex" type="Integer" mayBeNull="true" />
            /// <returns />
            Sys.Extended.UI.SlideShowEventArgs.initializeBase(this);

            this._previousSlide = previousSlide;
            this._nextSlide = nextSlide;
            this._slideIndex = slideIndex;
        }
        Sys.Extended.UI.SlideShowEventArgs.prototype = {
            get_previousSlide: function () {
                /// <value type="Object">
                /// PreviousSlide
                /// </value>
                return this._previousSlide;
            },

            get_nextSlide: function () {
                /// <value type="Object">
                /// NextSlide
                /// </value>
                return this._nextSlide;
            },

            get_slideIndex: function () {
                /// <value type="Number" integer="true">    
                /// SlideIndex
                /// </value>
                return this._slideIndex;
            }
        }
        Sys.Extended.UI.SlideShowEventArgs.registerClass('Sys.Extended.UI.SlideShowEventArgs', Sys.CancelEventArgs);

    } // execute

    if (window.Sys && Sys.loader) {
        Sys.loader.registerScript(scriptName, ["ExtendedBase", "ExtendedCommon", "ExtendedTimer", "Network"], execute);
    }
    else {
        execute();
    }

})();

