
var GalleryImage = Class.create(
{
  CLASS_NAME     : 'GalleryImage',

  initialize: function(imageArray)
  {
    imageArray  = this.checkImageAvailability(imageArray);
    this.image  = imageArray;
    this.active = false;
  },

  checkImageAvailability: function(imageArray)
  {
    //alert('Check availability:\r\n' + imageArray[0] + "\r\n" + imageArray[1] + "\r\n" + imageArray[2]);

    try{ new Ajax.Request(imageArray[0], { method:'get', asynchronous: false, onFailure: function(){imageArray[0] = null;} }); } catch(err){}
    try{ new Ajax.Request(imageArray[1], { method:'get', asynchronous: false, onFailure: function(){imageArray[1] = null;} }); } catch(err){}
    try{ new Ajax.Request(imageArray[2], { method:'get', asynchronous: false, onFailure: function(){imageArray[2] = null;} }); } catch(err){}
    
    if ( !imageArray[0] && !imageArray[1] && !imageArray[2] )
    {
      imageArray[1] = "/LIBRARIES/javascript/gallery/image-unavailable.gif";
    }

    return imageArray;

  },

  setVisibility: function(visibility)
  {
    this.visibility=visibility;
  },

  getVisibility: function()
  {
    return this.visibility;
  },

  setActive: function(active)
  {
    this.active=active;
  },

  isActive: function()
  {
    return this.active;
  },

  setIndex: function(index)
  {
    this.index=index;
  },

  getIndex: function()
  {
    return this.index;
  },
  
  setContainer: function(container)
  {
    this.container=container;
  },

  getContainer: function()
  {
    return this.container;
  },

  setImageClone: function(image)
  {
    this.imageClone=image;
  },

  setImageSmall: function(image)
  {
    this.imageSmall=image;
  },

  setImageMedium: function(image)
  {
    this.imageMedium=image;
  },

  setImageLarge: function(image)
  {
    this.imageLarge=image;
  },

  getImageClone: function()
  {
    return this.imageClone;
  },

  getImageSmall: function()
  {
    return this.imageSmall;
  },

  getImageMedium: function()
  {
    return this.imageMedium;
  },

  getImageLarge: function()
  {
    return this.imageLarge;
  },

  getSourceSmall: function()
  {
    return this.image[0] || this.image[1] || this.image[2];
  },

  getSourceMedium: function()
  {
    return this.image[1] || this.image[2] || this.image[0];
  },

  getSourceLarge: function()
  {
    return this.image[2] || this.image[1] || this.image[0];
  }
});


var Enum = Class.create(
{
    CLASS_NAME     : 'Enum',

    initialize: function(list)
    {
      for ( n = 0; n < list.length; n++ )
      {
          eval('this.'+list[n]+"="+n+";");
      }
    }
});

var TimedEvent = Class.create(
{
    CLASS_NAME     : 'TimedEvent',

    initialize: function(callback, callbackparameter, baseinterval, interval, condition)
    {
       this.callback=callback;
       this.baseinterval=baseinterval;
       this.interval=interval;
       this.framedelay=(interval/baseinterval).round();
       this.condition=condition;
       this.callbackparameter = callbackparameter;
    }
});


/**
*
* Class jGallery
*
* @Date: 09.10.2008
* @Version: 1.0.1
* @Author: Daniel Mueller
*
*/
var JGallery = Class.create(
{
  //static fields
  Version        : '1.0.1',

  CLASS_NAME     : 'JGallery',
  
  title          : null,

  PLAYDELAY      : {interval: 8000, swaptime: 3000},
  DEADZONE       : '30px', // can end on px or %
  MAX_SCROLL     : 0,
  BASE_INTERVAL :  50,
  PLAYMODES      : new Enum(['PLAY', 'PAUSE']),

  VERTICAL_GAP   : 10,
  IMAGE_PADDING  : 0,
  AUTOSCROLLSPEED: 1,

  FADE_DURATION  : 100,


  timedEvents    :[],
  autoScroll     : false,
  
  loadedSmall    : 0,
  loadedClone    : 0,
  loadedMedium   : 0,
  loadedLarge    : 0,
  loadedImages   : 0,



  initialize: function(container, imageArray, dividerPosition, galleryTitle, hideID)
  {
    $(hideID).style.display='none';
    this.container=container;
    this.divider=dividerPosition;
    this.title = galleryTitle;
    this.images=this.initImageObjects(imageArray);

    Event.observe(window, 'load', this.documentLoaded.bindAsEventListener(this));
  },

  documentLoaded: function()
  {
    this.initGallery();
  },

  initGallery: function()
  {
    this.container=$(this.container);
    this.container.update('');
    this.transitionDuration=500;
    this.combinedThumbWidth=null;
    this.dimension=this.calculateDimension();

    this.initHTMLFrame(this.container);

    //executed after all images are loaded... damn, does not work for opera...
    if (Prototype.Browser.Opera)
    {
       this.initThumbnails();
       this.initImages();
    }

    this.initMouseEvents();
    this.initTimer();

    if ( this.images.length > 1 )
    { 
      this.playMode = this.PLAYMODES.PLAY;
    }

  },

  calculateDimension: function()
  {
    bTop    = parseInt(this.container.getStyle('border-top-width').replace(/px/, ''), 10);
    bRight  = parseInt(this.container.getStyle('border-right-width').replace(/px/, ''), 10);
    bBottom = parseInt(this.container.getStyle('border-bottom-width').replace(/px/, ''), 10);
    bLeft   = parseInt(this.container.getStyle('border-left-width').replace(/px/, ''), 10);

    bTop    = isNaN(bTop) ? 0 : bTop;
    bRight  = isNaN(bRight) ? 0 : bTop;
    bBottom = isNaN(bBottom) ? 0 : bTop;
    bLeft   = isNaN(bLeft) ? 0 : bTop;

    return {width: this.container.getWidth()-bLeft-bRight, height: this.container.getHeight()-bTop-bBottom};
  },

  initTimer: function()
  {
    this.timeFireCount = 1;

    this.timedEvents.push(new TimedEvent(this.showNextImage.bindAsEventListener(this), this.PLAYDELAY.swaptime, this.BASE_INTERVAL, this.PLAYDELAY.interval, this.isAutoPlayActive.bindAsEventListener(this) ));
    this.timedEvents.push(new TimedEvent(this.scrollTrigger.bindAsEventListener(this), 0, this.BASE_INTERVAL, this.BASE_INTERVAL, function(){return true;}  ));


    this.timedEvents.push(new TimedEvent(this.scrollTrigger.bindAsEventListener(this), -this.AUTOSCROLLSPEED, this.BASE_INTERVAL, this.BASE_INTERVAL, this.isAutoScrollActive.bindAsEventListener(this) ));

    //this.periodicExecuter = new PeriodicalExecuter(this.scrollTrigger.bindAsEventListener(this), this.BASE_INTERVAL/1000);
    this.periodicExecuter = new PeriodicalExecuter(this.timerEvent.bindAsEventListener(this), this.BASE_INTERVAL/1000);
  },

  initImageObjects: function(imageArray)
  {
     images=[];

     for (var index = 0, len = imageArray.length; index < len; ++index)
     {
         images.push(new GalleryImage(imageArray[index]));
     }
     return images;
  },

  initHTMLFrame: function()
  {
     //cloneImages  = new Array();
     smallImages  = [];
     mediumImages = [];
     largeImages  = [];


     for (var index = 0, len = this.images.length; index < len; ++index)
     {
         var image = this.images[index];

         image.setIndex(index);

         image.setImageClone($(Builder.node('img', {src:image.getSourceSmall(),  id:'clone'+index, className:'cloneImage', style:'display:none;'}, [])));

         image.setImageSmall($(Builder.node('img',  {src:image.getSourceSmall(),  alt:this.title, id:'sml'+index, className:'smlImage', style:'cursor:pointer;display:none;'}, [])));
         image.setImageMedium($(Builder.node('img', {src:image.getSourceMedium(), alt:this.title, id:'med'+index, className:'medImage', style:'cursor:pointer;position:absolute;display:none;'}, [])));
         image.setImageLarge($(Builder.node('img',  {src:image.getSourceLarge(),  alt:this.title, id:'lrg'+index, className:'lrgImage', style:'display:none;'}, [])));

         Event.observe(image.getImageSmall(), 'load', this.imageLoaded.bindAsEventListener(this));
         Event.observe(image.getImageMedium(), 'load', this.imageLoaded.bindAsEventListener(this));
         Event.observe(image.getImageLarge(), 'load', this.imageLoaded.bindAsEventListener(this));
         Event.observe(image.getImageClone(), 'load', this.imageLoaded.bindAsEventListener(this));

         smallImages.push  (image.getImageClone());
         smallImages.push  (image.getImageSmall());

         mediumImages.push (image.getImageMedium());
         largeImages.push  (image.getImageLarge());

         image.getImageSmall().setStyle({ position:'absolute', top: '16px', height:(this.divider-30)+'px' });
         image.getImageClone().setStyle({ position:'absolute', top: '16px', height:(this.divider-30)+'px' });

         Event.observe(image.getImageSmall(), 'click', this.handleClickOnSmall.bindAsEventListener(this));
         Event.observe(image.getImageMedium(), 'click', this.handleClickOnMedium.bindAsEventListener(this));
     }

     this.imageContainer   = $(Builder.node('div', {id:'imageContainer', style:'position:absolute;top:0;left:0px;width:100%;height:'+(this.dimension.height-this.divider-this.VERTICAL_GAP)+'px;'}, [mediumImages]) );
     //this.imageContainer   = $(Builder.node('div', {id:'imageContainer', style:'background:blue;position:absolute;top:0;left:0;width:100%;height:300'}, [mediumImages]) );
     //this.thumbContainer   = $(Builder.node('div', {id:'thumbContainer', style:'overflow:hidden;background:red;position:absolute;top:'+this.VERTICAL_GAP+';left:0;width:100%;height:'+this.divider}, [smallImages]) );
     this.thumbContainer   = $(Builder.node('div', {id:'thumbContainer', style:'overflow:hidden;position:absolute;margin-top:10px;bottom:0;left:0px;width:100%;height:'+this.divider + 'px;'}, [smallImages]) );

     this.gallery = $(Builder.node('div', {id:'jGallery', style:'width:100%;height:100%;position:relative;border:0px solid red;'}, [this.imageContainer, this.thumbContainer]) );

     //var innerBorder = RUZEE.ShadedBorder.create({ corner:20, border:1 });
     //innerBorder.render(this.imageContainer);
     //innerBorder.render(this.thumbContainer);
     
     //TODO

     this.container.appendChild(this.gallery);
  },

  imageLoaded: function(event)
  {
    this.loadedImages++;
    //alert(this.loadedImages);
    if ( this.loadedImages == (this.images.length*4) )
    {
      this.initImages();
      this.initThumbnails();
    }
  },

  initThumbnails: function()
  {
      xPosition = 0;
      hGap      = 2;
      //gap=xPosition;
      this.images.each(function(image, index)
      {
          image.getImageSmall().setStyle({left:xPosition+'px'});
          xPosition += image.getImageSmall().getWidth()+hGap;
          image.getImageSmall().appear({ from:0.0, to: 1.0, duration: 0.5*image.getIndex() });
      });
      this.combinedThumbWidth=xPosition;
      
      // see if autoscroll shall be active
      //if ( this.combinedThumbWidth > this.dimension.width ) this.autoScroll = true;

      if ( this.images.length==1 ) this.hideThumbview();
  },
  
  hideThumbview: function()
  {
    //$('jGalleryBorder').style.height=(this.gallery.getHeight()-this.thumbContainer.getHeight())+'px';
    this.thumbContainer.style.display="none";
  },

  initImages: function()
  {

      for (var index = 0, len = this.images.length; index < len; ++index)
      {
          var image = this.images[index];
          this.scaleImage(image.getImageMedium());
          this.centerImage(image.getImageMedium());
      }

      if ( this.images.length > 0 )
      {
          this.showImage(this.images[0]);
          this.selectThumbnail(this.images[0]);
      }
  },

  initMouseEvents: function()
  {
      Event.observe(this.thumbContainer, 'mousemove', this.handleMouseOnPreview.bindAsEventListener(this));
      Event.observe(this.thumbContainer, 'mouseover', this.handleMouseEnterPreview.bindAsEventListener(this));
      Event.observe(this.thumbContainer, 'mouseout', this.handleMouseLeavePreview.bindAsEventListener(this));
  },
  
  isAutoPlayActive: function()
  {
     return this.playMode == this.PLAYMODES.PLAY;
  },
  
  isAutoScrollActive: function()
  {
     return this.autoScroll;
  },

  timerEvent: function()
  {
    for ( n=0; n<this.timedEvents.length; n++ )
    {
       if ( this.timeFireCount % this.timedEvents[n].framedelay == 0 && this.timedEvents[n].condition() )
       {
          this.timedEvents[n].callback(this.timedEvents[n].callbackparameter);
       }
    }

    this.timeFireCount++;
  },
  
  calcScrollSpeed: function()
  {
    action='still';

    //calc deadzone
    if ( this.DEADZONE.endsWith('px') )
    {
       deadzone = parseInt(this.DEADZONE.replace(/px/, ''), 10);
    }
    else if ( this.DEADZONE.endsWith('%') )
    {
       deadzone = parseInt(this.DEADZONE.replace(/%/, ''), 10);
       deadzone = this.dimension.width*(deadzone/100);
    }
    else
    {
      throw('Error: only \'%\' or \'px\' are allowed for the DEADZONE value!');
    }

    //calc scroll speed
    if (this.mouseOnPreview.X <= (this.dimension.width/2)-(deadzone/2) )
    {
        action='left';
        speed = (this.dimension.width/2)-(deadzone/2) - this.mouseOnPreview.X;
        speed = (speed/((this.dimension.width/2)-(deadzone/2)))*this.MAX_SCROLL;
    }
    else if (this.mouseOnPreview.X >= (this.dimension.width/2)+(deadzone/2) )
    {
        action='right';
        speed = (this.dimension.width/2)+(deadzone/2) - this.mouseOnPreview.X;
        speed = (speed/((this.dimension.width/2)-(deadzone/2)))*this.MAX_SCROLL;
    }
    else
    {
        action='still';
        speed=0;
    }

    // !!! must, else very strange...
    return speed.round();
  },

  scrollTrigger: function(fixedSpeed)
  {
    //return if not over thumbnail container
    if ( !fixedSpeed && !this.onPreview ) {return;}


    //move images & set visibility
    speed = fixedSpeed ? fixedSpeed : this.calcScrollSpeed();

    if ( speed == 0 ) return;
    for (var index = 0, len = this.images.length; index < len; ++index)
    {
        //set new x position
        image = this.images[index];
        newPosition = parseInt(image.getImageSmall().getStyle('left'), 10)+speed;
        image.getImageSmall().setStyle({left:newPosition+'px'});

        //set visibility
        if ( newPosition > this.dimension.width ) // out right
        {
             image.setVisibility(0.0);
             image.getImageSmall().setStyle({left:(newPosition-Math.max(this.dimension.width, this.combinedThumbWidth))+'px'});

             image.getImageSmall().setOpacity( 0.8*image.getVisibility().abs() );
             image.getImageClone().setOpacity( 0.8-(0.8*image.getVisibility().abs()) );
        }
        else if ( newPosition < -image.getImageSmall().getWidth()) // out left
        {
             image.setVisibility(0.0);
             image.getImageSmall().setStyle({left:(newPosition+Math.max(this.dimension.width, this.combinedThumbWidth))+'px'});

             image.getImageSmall().setOpacity( 0.8*image.getVisibility().abs() );
             image.getImageClone().setOpacity( 0.8-(0.8*image.getVisibility().abs()) );
        }
        else if ( newPosition >= 0 && newPosition <= this.dimension.width-image.getImageSmall().getWidth() )
        {
             image.setVisibility(1.0);

             image.getImageSmall().setOpacity( 0.8*image.getVisibility().abs() );
             image.getImageClone().setOpacity( 0.8-(0.8*image.getVisibility().abs()) );
        }
        // nice to have: percentage of visible rect
        else if ( newPosition < 0 ) //leaving left
        {
             //eg: 5(0);width:100;left:-30 --> -0.7
             image.setVisibility(-(image.getImageSmall().getWidth()+newPosition)/image.getImageSmall().getWidth());

             image.getImageClone().setStyle({display:'',left:(newPosition+Math.max(this.dimension.width, this.combinedThumbWidth))+'px'});

             image.getImageSmall().setOpacity( 0.8*image.getVisibility().abs() );
             image.getImageClone().setOpacity( 0.8-(0.8*image.getVisibility().abs()) );
             
             //try a swap
             //tempImage=image.getImageSmall();
             //image.setImageSmall(image.getImageClone());
             //image.setImageClone(tempImage);
        }
        else if (newPosition > this.dimension.width-image.getImageSmall().getWidth() ) //leaving right
        {
             //eg: dimension.width:1000;width:100;left:930 --> 0.7
             image.setVisibility((this.dimension.width-newPosition)/image.getImageSmall().getWidth() );

             image.getImageClone().setStyle({display:'',left:(newPosition-Math.max(this.dimension.width, this.combinedThumbWidth))+'px'});

             image.getImageSmall().setOpacity( 0.8*image.getVisibility().abs() );
             image.getImageClone().setOpacity( 0.8-(0.8*image.getVisibility().abs()) );

             //try a swap
             //tempImage=image.getImageSmall();
             //image.setImageSmall(image.getImageClone());
             //image.setImageClone(tempImage);
        }
        else { throw('something wrong here: id=' + image.getIndex() + '; d.w=' + this.dimension.width + '; i.w+' + image.getImageSmall().getWidth() + '; x=' + newPosition); }
    }

    /*
    $('gpio1').value= deadzone;
    $('gpio2').value=speed;
    $('gpio3').value=this.dimension.width +" - "+ this.combinedThumbWidth;
    */
  },

  handleMouseOnPreview: function(e)
  {
    this.mouseOnPreview=
    {
      X:e.pointerX() - this.thumbContainer.cumulativeOffset().left,
      Y:e.pointerY() - this.thumbContainer.cumulativeOffset().top
    };
  },

  handleMouseEnterPreview: function(e)
  {
    this.onPreview=true;
    this.autoScroll=false;
  },

  handleMouseLeavePreview: function(e)
  {
    relX = e.pointerX() - this.thumbContainer.cumulativeOffset().left;
    relY = e.pointerY() - this.thumbContainer.cumulativeOffset().top;

    if ( relX >= 0 && relY >= 0 && relX < this.thumbContainer.getWidth() && relY < this.thumbContainer.getHeight() )
    {
      return;
    }
    this.onPreview=false;
  },

  handleClickOnSmall: function(e)
  {
    newActiveImage     = this.getImageById(e.element().id);

    //image is already active
    if ( newActiveImage.isActive() ) { return; }

    currentActiveImage = this.getCurrentImage();
    this.toggleImage(currentActiveImage, newActiveImage, this.FADE_DURATION);
    
    this.playMode=this.PLAYMODES.PAUSE;
  },

  handleClickOnMedium: function(e)
  {
     this.showFullscreen();
  },
  
  getImageById: function(id)
  {
     for (var index = 0, len = this.images.length; index < len; ++index)
     {
        image = this.images[index];
        if ( image.getImageSmall().id == id || image.getImageMedium().id == id || image.getImageLarge().id == id ) { return image; }
     }
     return null;
  },

  showImage: function(image, fade_duration)
  {
      fade_duration = fade_duration ? fade_duration : this.transitionDuration;
      fade_duration = fade_duration / 1000;
      image.getImageMedium().appear({ duration: fade_duration });
      //image.getImageMedium().appear({ duration: 0 });
      image.setActive(true);
  },

  hideImage: function(image, fade_duration)
  {
      fade_duration = fade_duration ? fade_duration : this.transitionDuration;
      fade_duration = fade_duration / 1000;
      image.getImageMedium().fade({ duration: fade_duration });
      image.setActive(false);
  },

  selectThumbnail: function(image)
  {
      //image.getImageSmall().fade({ from: 0.8, to: 0.4, duration: 1.0 });
  },

  deselectThumbnail: function(image)
  {
      //image.getImageSmall().appear({ from: 0.4, to: 0.8, duration: 1.0 });
  },

  scaleImage: function(image)
  {
      //alert('scale: ' + this.dimension.width + '/' + (this.dimension.height-this.divider));
      maxWidth  = this.dimension.width-(2*this.IMAGE_PADDING);
      maxHeight = this.dimension.height-(this.divider+this.VERTICAL_GAP+(2*this.IMAGE_PADDING));

      ratio=maxWidth/maxHeight;
      imageRatio=image.getWidth()/image.getHeight();
      //imageRatio=image.width/image.height;

      diffX = maxWidth -image.getWidth();
      diffY = maxHeight-image.getHeight();

      if ( imageRatio > ratio )
      {
        //by X
        image.style.width =(image.getWidth()+diffX) + 'px';
        image.style.height=(image.getWidth()/imageRatio) + 'px';
      }
      else
      {
        //by Y
        image.style.height=(image.getHeight()+ diffY) + 'px';
        image.style.width =(imageRatio*image.getHeight()) + 'px';
      }
      imageRatio=image.getWidth()/image.getHeight();
  },

  centerImage: function(image)
  {
      if ( !image ) {return;}
      
      maxWidth  = this.dimension.width-(2*this.IMAGE_PADDING);
      //maxHeight = this.dimension.height-this.divider;
      maxHeight = this.dimension.height-(this.divider+this.VERTICAL_GAP+(2*this.IMAGE_PADDING));

      imageWidth  = image.getWidth();
      imageHeight = image.getHeight();

      diffWidth  = maxWidth - imageWidth;
      diffHeight = maxHeight - imageHeight;

      image.style.left=((diffWidth/2)+this.IMAGE_PADDING) + 'px';
      image.style.top=((diffHeight/2)+this.IMAGE_PADDING) + 'px';

      //alert(imageHeight);
      //alert(imageWidth);
  },

  toggleImage: function(imageOld, imageNew, fade_duration)
  {
      this.hideImage(imageOld, fade_duration);
      this.showImage(imageNew, fade_duration);
  },

  getCurrentImage: function()
  {
     for (var index = 0, len = this.images.length; index < len; ++index)
     {
        image = this.images[index];
        if ( image.isActive() ) { return image; }
     }
     
     //if ( this.images.length > 0 ) return this.images[0];

     return ;
  },
  
  getNextImage: function()
  {
     for (var index = 0, len = this.images.length; index < len; ++index)
     {
        image = this.images[index];
        if ( image.isActive() ) {

          if ( this.images.length > image.getIndex()+1 )
          {
            return this.images[index+1];
          }
          else return this.images[0];
        }
     }
     return;
  },
  
  getPreviousImage: function()
  {
     for (var index = 0, len = this.images.length; index < len; ++index)
     {
        image = this.images[index];
        if ( image.isActive() ) {

          if ( image.getIndex()-1 >= 0)
          {
            return this.images[index-1];
          }
          else return this.images[this.images.length-1];
        }
     }
     return;
  },

  showNextImage: function(duration)
  {
      this.toggleImage(this.getCurrentImage(), this.getNextImage(), duration);
  },

  showPreviousImage: function(duration)
  {
    this.toggleImage(this.getCurrentImage(), this.getPreviousImage(), duration);
  },
  
  setTitle: function(title)
  {
    this.title = title;
  },

  showFullscreen: function()
  {
    //if ( this.title ) alert(this.title);
    iBox.showURL(this.getCurrentImage().getSourceLarge(), this.title);
  }

});