//Needs UtilityService.js and scriptaculous and make sure to set the global variable baseURL to a valid path for ajax requests

var SliderHandler=Class.create(PanelHandler,
{
   initialize:function($super,containerId,parentHandler,imageSourceList)
   {
       /*Just for testing
       imageSourceList=$A(
         [ "/hga/gfx/slideshowImages/01.jpg",
           "/hga/gfx/slideshowImages/02.jpg",
           "/hga/gfx/slideshowImages/03.jpg",
           "/hga/gfx/slideshowImages/05.jpg",
           "/hga/gfx/slideshowImages/06.jpg",
           "/hga/gfx/slideshowImages/07.jpg",
           "/hga/gfx/slideshowImages/08.jpg"
         ]
        );
       */     
       
       $super(containerId,parentHandler);

       this.indexCurrentImage=-1;       
       //this.initEvents();
       this.myImages=null;
       this.myImages=this.getImages(imageSourceList);
       this.numberOfLoadedImages=0;
       this.vBUTTON_PREVIOUS="buttonGoToPrevious";
       this.vBUTTON_PAUSE="buttonPause";
       this.vBUTTON_NEXT="buttonGoToNext";
       this.vBUTTON_RESUME="buttonResume";
       
       this.vEFFECTS_QUEUE="slideEffect1";

       this.isPaused=false;
   },

   //Note: The navigation buttons should also be inside this container, but well that's for the next upgrade where we divide the Slideshow handler into navigation and slide section
   getEButtonGoToPreviousSlide:function()
   {return UtilityService.prototype.getFirstMatching(this.getContextDocument(),"class",this.vBUTTON_PREVIOUS);},

   getEButtonPauseSlide:function()
   {return UtilityService.prototype.getFirstMatching(this.getContextDocument(),"class",this.vBUTTON_PAUSE);},

    getEButtonResumeSlide:function()
   {return UtilityService.prototype.getFirstMatching(this.getContextDocument(),"class",this.vBUTTON_RESUME);},

   getEButtonGoToNextSlide:function()
   {return UtilityService.prototype.getFirstMatching(this.getContextDocument(),"class",this.vBUTTON_NEXT);},
   
   getImages:function(imageSourceList)
   {
       if(this.myImages!=null)
           return this.myImages;
       else
       {//create an image slide object for each given image source
           var imagesHash=new Hash();
           for(var i=0;i<imageSourceList.size();i++)
           {
               var myImage=new ImageForSliding(i,imageSourceList[i],this);
               //the image element created is hidden by default
               imagesHash.set(i,myImage);
           }
           return imagesHash;
       }
   },
    
   startSlide:function()
   {
       if(this.myImages.size()>0)
       {
           this.getEButtonPauseSlide().show();
           this.getEButtonResumeSlide().hide();
           
           var initialIndex=0;
           this.indexCurrentImage=initialIndex;           
           this.goToSlideOfIndex(this.indexCurrentImage);
       }
       else
       {
           alert("No images to be displayed?");
       }
   },
       
   getNextIndex:function(currentIndex)
   {
       var nextIndex=0;
       var max=this.myImages.keys().size()-1;
       var min=0;
       
       if(currentIndex >= max)
       {
           //Back to the beginning
           nextIndex=min;
       }
       
       else if(currentIndex<min)
       {     
           nextIndex=min;//when the input was invalid then reset to the beginning
           //alert("I should never get here!");
       }
       else
       {
           nextIndex=currentIndex+1;
       }
       return nextIndex;
   },
   
   getPreviousIndex:function(currentIndex)
   {
       var previousIndex=0;
       var max=this.myImages.keys().size()-1;
       var min=0;
       
       if(currentIndex <= min)
       {
           //Back to the beginning
           previousIndex=max;
       }
       
       else if(currentIndex > max)
       {          
           //alert("I should never get here!");
           previousIndex=max;
       }       
       else
       {
           previousIndex=currentIndex-1;
       }
       return previousIndex;
   },

   showImage:function(imageForSliding)
   {
       //after all the effects are displayed, update current index
       //effect queues are not working so for now lets make linked effects
       var imageElement=imageForSliding.getImageElement();             

      //show only if it was hidden
      if(!imageElement.visible())/*BTW: hidden by css is considered visible! See http://www.prototypejs.org/api/element/visible*/
      {
          Effect.Appear
          (
             imageElement,
             {
                 from:0.1,
                 queue:{position:"end",scope:this.vEFFECTS_QUEUE}
             }
          );
      }
          
      Effect.Fade
      (
         imageElement,
         {
           delay:2,
           //to:0.5,
           queue:{position:"end",scope:this.vEFFECTS_QUEUE}
           ,afterFinish:function()
           {
               imageElement.hide();
               imageElement.setStyle({opacity: 1});
               this.goToNextSlide();              
           }.bind(this,imageElement)}
      );

      
   },
   
   getIndexCurrentImage:function()
   {
       return this.indexCurrentImage;
   },

   setNumberOfLoadedImages:function(numberOfLoadedImages)
   {
       this.numberOfLoadedImages=numberOfLoadedImages;
   },

   getNumberOfLoadedImages:function()
   {
       return this.numberOfLoadedImages;
   },

   initEvents:function()
   {
       this.getEButtonGoToNextSlide().observe('click',
         function()
         {
             this.goToNextSlide();
         }.bind(this)
       );
       this.getEButtonGoToPreviousSlide().observe('click',
         function()
         {
             this.goToPreviousSlide();
         }.bind(this)
       );

       this.getEButtonPauseSlide().observe('click',
           function()
           {
               this.getEButtonPauseSlide().hide();
               this.getEButtonResumeSlide().show();
               this.pauseSlide();
           }.bind(this)
       );

      this.getEButtonResumeSlide().observe('click',
           function()
           {
               this.getEButtonPauseSlide().show();
               this.getEButtonResumeSlide().hide();
               this.resumeSlide();
           }.bind(this)
       );

   },
   //shorcut
   goToNextSlide:function()
   {           
       this.goToSlideOfIndex(this.getNextIndex(this.indexCurrentImage)); 
   },
   //shorcut
   goToPreviousSlide:function()
   {      
       this.goToSlideOfIndex(this.getPreviousIndex(this.indexCurrentImage));
   },
   
   goToSlideOfIndex:function(index)
   {
       if(index<0 && index>(this.myImages.keys().size()-1)) {alert('Invalid index: '+index);return}

       this.cleanEffects();
       var oldImage=this.getImages(null).get(this.indexCurrentImage);
       this.indexCurrentImage=index;
       var nextImage=this.getImages(null).get(this.indexCurrentImage);

       this.updateCurrentSlideIndicator();
       if(this.isPaused)
       {
           oldImage.getImageElement().hide();
           nextImage.getImageElement().show();
       }
       else if(!nextImage.hasAtttemptedToLoadAlready())
       {
           nextImage.startLoading();
       }
       else if(nextImage.isReady())
       {
           this.showImage(nextImage);
       }       
   },

   pauseSlide:function()
   {
       this.isPaused=true;
       this.cleanEffects();
       var currentImage=this.getImages(null).get(this.indexCurrentImage);
       currentImage.getImageElement().show();//because it was probably reset back to be hidden when cleanEffects was called
   },

   resumeSlide:function()
   {
       this.isPaused=false;
       //this is the image being currently paused, since pauseSlide was called before then all the effects were canceled and calling cleanEffects again should NOT hide this slide (cleanEffects hides all elements related to the current effects taking action)

       this.goToSlideOfIndex(this.indexCurrentImage);
   },

   cleanEffects:function()
   {//Here we should 'clean' each element related to an effect, it must go back to the way it was in the start
       Effect.Queues.get(this.vEFFECTS_QUEUE).each(
        function(effect)
        {
            var imageElement=effect.element;
            imageElement.hide();
            imageElement.setStyle({opacity: 1});
            effect.cancel();
        });
   },

   //Called when the current slide changes, override this method to update the value you want wherever you want
   updateCurrentSlideIndicator:function()
   {//dummy implementation
       var nextImage=this.getImages(null).get(this.indexCurrentImage);
       if($('currentSlideElement')!=null)
          $('currentSlideElement').update('Showing now: '+nextImage.getImageElement().identify());
   }
});

var ImageForSliding=Class.create({
   
   initialize:function(index,source,parentHandler)
   {
       this.parentSliderHandler=parentHandler;
       this.imageElement=new Element("img");
       this.imageElement.identify();
       this.imageElement.hide();
       this.mySource=source;
       this.isLoaded=false;
       this.hasAttemptedToLoad=false;
       this.parentSliderHandler.getEContainer().insert(this.imageElement);
       
       this.index=index;
       this.loadNextAfterCompleted=false;
   },
   
   isReady:function()
   {
       return this.isLoaded;
   },
   
   initEvents:function()
   {
       this.imageElement.stopObserving("load");
       this.imageElement.observe("load",
         function()
         {
            //flag to consider only real loadings and not when src=""
            if(this.hasAttemptedToLoad && !this.isReady())
            {                
                //Image is really loaded
                this.isLoaded=true;
                this.parentSliderHandler.setNumberOfLoadedImages(this.parentSliderHandler.getNumberOfLoadedImages()+1);
                
                //it is your turn to be shown!               
                if(this.index == this.parentSliderHandler.getIndexCurrentImage())
                {//this happens ONLY when the slidePanel was waiting for this image to load in order to show it
                    this.parentSliderHandler.showImage(this);
                }
                //load next
                if(this.parentSliderHandler.getNumberOfLoadedImages()<this.parentSliderHandler.getImages().keys().size())
                {   //if there are still images that need to be loaded
                    var indexTemp=this.parentSliderHandler.getIndexCurrentImage();
                    var indexNextImageToBeLoaded=indexTemp;
                    var nextImageToBeLoaded=this.parentSliderHandler.getImages().get(indexNextImageToBeLoaded);

                    while(nextImageToBeLoaded.isReady())
                    {//if the next has already been loaded, then try the next and so on
                        indexTemp=indexNextImageToBeLoaded;
                        indexNextImageToBeLoaded=this.parentSliderHandler.getNextIndex(indexTemp);
                        nextImageToBeLoaded=this.parentSliderHandler.getImages().get(indexNextImageToBeLoaded);
                    }
                    //alert("next image to be loaded is "+nextImageToBeLoaded.index);
                    //check: if there's still one that needs to be loaded
                    nextImageToBeLoaded.startLoading();
                }
            }
         }.bind(this)
       );
   },
   
   startLoading:function()
   {     
       this.initEvents();
       this.imageElement.writeAttribute("src",this.mySource);
       this.hasAttemptedToLoad=true;
   },

   getImageElement:function()
   {
       return this.imageElement;
   },

   hasAtttemptedToLoadAlready:function()
   {return this.hasAttemptedToLoad;}
   
});

