/*******************************************************************************

ImageShiftGallery, version 1.3 (07/08/2009)
(c) 2005 - 2009 Takashi Okamoto.

ImageShiftGallery is a JavaScript image viewer. It is freely distributable,
but this header must be included, and should not be modified. Donations are 
appreciated. For details, see the BuzaMoto website: http://buzamoto.com/

*******************************************************************************/

/* ----------------------------------------------------------------------------

1.3   - added ongalleryload callback.
        added autoscroll
1.2.3 - enabled 'this' object for event handlers
1.2.2 - improved image dimension calculation
1.2.1 - added onmouseover and onmouseout behaviors
1.2   - added onclick behavior for images
        changed from templates to procedurally creating gallery elements
        fixed to support IE6
1.1.1 - fixed for IE7
        Safari image loading fix (able to apply width/height) to images
        added support to add padding on the right of the image
1.1   - enabled HTML content
1.0.2 - initial support for IE7
1.0.1 - fixed image loader for firefox

---------------------------------------------------------------------------- */

// ---------------------- com.buzamoto Namespace

var com;
if (!com)
  com = {};
else if (typeof com != "object")
  throw new Error("com already exists and is not an object");

if (!com.buzamoto)
  com.buzamoto = {};
else if (typeof com.buzamoto != "object")
  throw new Error("com.buzamoto already exists and is not an object");

if (com.buzamoto.ImageShiftGallery)
  throw new Error("com.buzamoto.ImageShiftGallery already exists");

// ---------------------- com.buzamoto.ImageShiftGallery

com.buzamoto.ImageShiftGallery = {
  Version: '1.3'
}

//var numImgsToLoad = 9;
var collectionControl;
var galleryControl;
var selectionControl;
var dateControl;
var groupControl;
var setRepControl;
var selectedSetRep;
var selectedDate;

//var shiftStepSize = 4;

function nextSelectionHandler(e) 
{
    selectionControl.move('next');
    Event.stop(e);
}

function prevSelectionHandler(e) 
{
    selectionControl.move('prev');
    Event.stop(e);
}

function nextCollectionHandler(e) 
{
    collectionControl.move('next');
    Event.stop(e);
}

function prevCollectionHandler(e) 
{
    collectionControl.move('prev');
    Event.stop(e);
}

function nextGalleryHandler(e) 
{
    galleryControl.move('next');
    Event.stop(e);
}

function prevGalleryHandler(e) 
{
    galleryControl.move('prev');
    Event.stop(e);
}

function nextDateHandler(e) 
{
    dateControl.move('next');
    Event.stop(e);
}

function prevDateHandler(e) 
{
    dateControl.move('prev');
    Event.stop(e);
}

function nextGroupHandler(e) 
{
    groupControl.move('next');
    Event.stop(e);
}

function prevGroupHandler(e) 
{
    groupControl.move('prev');
    Event.stop(e);
}

function nextSetRepHandler(e) 
{
    setRepControl.move('next');
    Event.stop(e);
}

function prevSetRepHandler(e) 
{
    setRepControl.move('prev');
    Event.stop(e);
}

// ---------------------- com.buzamoto.ImageShiftGallery.Gallery

com.buzamoto.ImageShiftGallery.Gallery = Class.create({
  
  initialize: function(id, imageArray, align, numImgsToLoad, toolbar, stepSize, autoscroll, autoscrollDelay) 
  {
    this.wrapper = $(id);

    this.id = id;
    this.alignment = (align) ? align : 'top';
    this.autoscroll = (autoscroll == true);
    this.autoscrollTimer = null;
    this.autoscrollDelay = autoscrollDelay;

    //This is for making things asynchronous.
    this.loadIndex = (imageArray.length < numImgsToLoad) ? imageArray.length : numImgsToLoad;
    
    // convert imageArray to array of ISGImages
    this.imageArray = new Array();
    for (var i = 0, len = imageArray.length; i < len; ++i) {
      var obj;
      if (imageArray[i].src)
      {
        var active = i < this.loadIndex ? true : false;
        imageArray[i].active = active;
        imageArray[i].stepSize = stepSize;
        obj = new com.buzamoto.ImageShiftGallery.Image(this, imageArray[i]);
      }
      else if (imageArray[i].markup)
      {
        obj = new com.buzamoto.ImageShiftGallery.Markup(this, imageArray[i]);
      }
      this.imageArray.push(obj);
    }

    // create controller
    this.controller = new com.buzamoto.ImageShiftGallery.Controller(this, stepSize);

    var imageNodes = com.buzamoto.ImageShiftGallery.Gallery.createImageNodes(this.alignment, imageArray, this.controller, this.id);

    // create dom elements to inject
    this.container = document.createElement('div');
    Element.extend(this.container);
    this.container.id = this.id + '-container';
    this.container.addClassName('isg_container');
    
    this.container.insert({top: imageNodes});
    
    if(toolbar) 
    {   
      var toolbars = com.buzamoto.ImageShiftGallery.Gallery.createImageToolbars(this.alignment, imageArray);
      this.container.insert({top: toolbars});
    }
    
    
    this.totalWidth = this.container.childElements()[0].getWidth();
    

    // bind events to controls
    var control;
    var self = this;
      
    if(id == "gallery_sets")
    {
        collectionControl = this.controller;
        if (control = $(self.id + "_next")) 
        {
            Event.observe(control, 'click', nextCollectionHandler);
        }

        if (control = $(self.id + "_prev")) 
        {
            Event.observe(control, 'click', prevCollectionHandler);
        }
    }
    
    if(id == "gallery_dates")
    {
        dateControl = this.controller;
        if (control = $(self.id + "_next")) 
        {
            Event.observe(control, 'click', nextDateHandler);
        }

        if (control = $(self.id + "_prev")) 
        {
            Event.observe(control, 'click', prevDateHandler);
        }
    }
    
    if(id == "gallery")
    {
        galleryControl = this.controller;
        if (control = $(self.id + "_next")) 
        {
            Event.observe(control, 'click', nextGalleryHandler);
        }

        if (control = $(self.id + "_prev")) 
        {
            Event.observe(control, 'click', prevGalleryHandler);
        }
    }
    
    if(id == "gallery_groups")
    {
        groupControl = this.controller;
        if (control = $(self.id + "_next")) 
        {
            Event.observe(control, 'click', nextGroupHandler);
        }

        if (control = $(self.id + "_prev")) 
        {
            Event.observe(control, 'click', prevGroupHandler);
        }
    }
    
    if(id == "gallery_selections")
    {
        selectionControl = this.controller;
        if (control = $(self.id + "_next")) 
        {
            Event.observe(control, 'click', nextSelectionHandler);
        }

        if (control = $(self.id + "_prev")) 
        {
            Event.observe(control, 'click', prevSelectionHandler);
        }
    }
    
    if(id == "gallery_setreps")
    {
        setRepControl = this.controller;
        if (control = $(self.id + "_next")) 
        {
            Event.observe(control, 'click', nextSetRepHandler);
        }

        if (control = $(self.id + "_prev")) 
        {
            Event.observe(control, 'click', prevSetRepHandler);
        }
    }
    
    // launch load notification to check for image load
    // onload doesn't seem to have complete image objects.
    window.setTimeout(function() {
      self.loadNotifier();
    }, 200);
  },
  
  removeDates: function() 
  {
      var control;
      var self = this;

      var formElement = document.getElementById('gallery-container');
      if (formElement && formElement.parentNode && formElement.parentNode.removeChild) {
          formElement.parentNode.removeChild(formElement);
      }
      formElement = document.getElementById('gallery_dates-container');
      if (formElement && formElement.parentNode && formElement.parentNode.removeChild) {
          formElement.parentNode.removeChild(formElement);
      }
  },
  
  onGalleryLoad: function() {
    this.wrapper.insert({top: this.container});
    this.setWidth();
    if (this.autoscroll) {
      this.scheduleAutoScroll();
    }
  },

  scheduleAutoScroll: function() {
    var self = this;
    this.autoscroll = true;
    this.autoscrollTimer = window.setTimeout(function() {
      self.controller.move('next');
      self.scheduleAutoScroll();
    }, this.autoscrollDelay);
  },
  
  stopAutoScroll: function() {
    if (this.autoscrollTimer) {
      window.clearTimeout(this.autoscrollTimer);
      this.autoscrollTimer = null;
      this.autoscroll = false;
    }
  },
  
  calcWidth: function() {
    var width = 0;
    for (var i = 0; i < this.imageArray.length; i++) {
      width += this.imageArray[i].getWidth();
    }
    return width;
  },
  
  setWidth: function() {
    this.totalWidth = this.calcWidth();
  },
  
  loadNotifier: function(delay) {
    delay = (delay) ? delay : 200;
    if (!this.loadedImages()) {
      var self = this;
      window.setTimeout(function() {
        self.loadNotifier(delay);
      }, delay);
    } else {
      this.onGalleryLoad();
    }
  },
  
  loadedImages: function() {
    for (var i = 0, len = this.imageArray.length; i < len; ++i) {
      if (this.imageArray[i].image) {
        if (this.imageArray[i].image.src && this.imageArray[i].image.complete == false) return false;
        if (this.imageArray[i].width == 0) this.imageArray[i].width = this.imageArray[i].image.width;
        if (this.imageArray[i].height == 0) this.imageArray[i].height = this.imageArray[i].image.height;
      }
    }
    return true;
  }
  
});
Object.extend(com.buzamoto.ImageShiftGallery.Gallery, {
  //MOVE_COORDS: new Array(0, -1, -4, -7, -11, -17, -23, -30, -38, -47, -56, -66, -75, -84, -92, -99, -100),
  MOVE_COORDS: new Array(0, -1, -4, -7, -11, -17, -23, -30, -38, -47, -56, -66, -75, -84, -92, -96, -100, -103, -105, -102, -101, -100),


  createImageToolbars: function(align, imageArray) {
    // create table
    var imageTable = document.createElement('table');
    imageTable.id = "table_toolbar";
    Element.extend(imageTable);
    imageTable.setAttribute('cellPadding', 0);
    imageTable.setAttribute('cellSpacing', 0);
    imageTable.setAttribute('border', 0);
    imageTable.addClassName('isg_table');
    
    tr = document.createElement('tr');
    Element.extend(this.tr);

    var index = 0;
    imageArray.each(function(image) 
    {
      var td = document.createElement('td');
      Element.extend(td);
      td.setStyle({verticalAlign: align});
      
      if (image.padding)
        td.setStyle({paddingRight: image.padding + 'px'});

      var node, handler;
      if (image.src)  
      {
        favoriteLink = document.createElement('div');
        Element.extend(favoriteLink);

        //Add the read icon.
        readLink = document.createElement('a');
        
        readIcon = document.createElement('img');
        readLink.appendChild(readIcon)
        favoriteLink.appendChild(readLink);
        Element.extend(readIcon);
        readIcon.setStyle({align: 'left'});
        
        if(image.read)
        {
            readLink.setAttribute('title', 'You\'ve read this.');
            readIcon.setAttribute('src', '/arrow_full.png');
        }
        else
        {
            readLink.setAttribute('title', 'You haven\'t read this.');
            readIcon.setAttribute('src', '/arrow_empty.png');
        }
        
        readIcon.id = image._id.toString() + "_read";
        
        //Add the favorite icon.
        heartLink = document.createElement('a');
        heartIcon = document.createElement('img');
        heartLink.appendChild(heartIcon)
        favoriteLink.appendChild(heartLink);
        Element.extend(heartIcon);
        heartIcon.setStyle({align: 'left', paddingLeft: '4px'});
        
        if(!image.favorite)
        {
            heartLink.setAttribute('title', 'Mark as great.');
            heartIcon.setAttribute('src', '/heart_empty.png');
        }
        else 
        {
            heartLink.setAttribute('title', 'You like this.');
            heartIcon.setAttribute('src', '/heart_full.png');
        }
            
        
        heartIcon.id = index.toString() + "_heart";

        
        //Add the cross icon.
        crossLink = document.createElement('a');
        crossLink.setAttribute('title', 'Add this to a group.');
        crossIcon = document.createElement('img');
        crossLink.appendChild(crossIcon)
        favoriteLink.appendChild(crossLink);
        Element.extend(crossIcon);
        crossIcon.setStyle({align: 'left', paddingLeft: '4px'});
        crossIcon.setAttribute('src', '/cross_empty.png');
        
        crossIcon.id = index.toString() + "_cross";
        
        crossContainer = document.createElement('div');
        crossContainer.id = index.toString() + "_crosscontainer";
        
        crossText = document.createElement('p');
        crossText.id = index.toString() + "_infotext";

        crossText.setStyle({float: 'left', fontSize: '10px'});
        
        var groupText = "...";
        if(image.group != null)
        {
            groupText = image.group;
            crossDelete = document.createElement('img');
            crossDelete.setAttribute('src', '/deletex.png');
            crossDelete.setStyle({align: 'right', paddingLeft: '4px', paddingTop: '4px'});
            deleteLink = document.createElement('a');
            deleteLink.setAttribute('href', 'javascript:void(0)');
            deleteLink.appendChild(crossDelete);
            deleteLink.id = index.toString() + "_deletelink";
            
            
            ['click'].each(function(evt) 
            {
                var evtfn = function(indx, img) {
                  return function(event) 
                  {
                      nodNam = indx.toString() + "_infotext";
                      $(nodNam).removeChild($(nodNam).childNodes[0]);
                      newText = document.createTextNode("...");
                      $(nodNam).appendChild(newText);
                        
                      nodNam = indx.toString() + "_deletelink";
                      $(nodNam).removeChild($(nodNam).childNodes[0]);
                      
                      var updateUrl = "/group_elements/" + img._id.toString();

                      
                      new Ajax.Request(updateUrl, {
                        method: 'delete', 
                        parameters: {"name" : img.group, "rendered_object_id" : img._id},
                        onSuccess: function(transport) { },
                        onFailure: function(){ alert('Something went wrong deleting group...') }
                      });

                    Event.stop(event);
                  }
                }(index, image);

                crossDelete.observe(evt, evtfn.bindAsEventListener(image));
            });
            
            crossContainer.appendChild(deleteLink);
        }

        sometext = document.createTextNode(groupText);
        crossText.appendChild(sometext);
        crossContainer.appendChild(crossText);
        favoriteLink.appendChild(crossContainer);

        new Ajax.InPlaceEditor(crossText, '/groups/create',
        { rows:1,
          cols:10,
          callback: function(form, value) { 
              return "value="+ encodeURIComponent(value) +"&rendered_object_id=" + encodeURIComponent(image._id)
          }
        });

        if (image.click || image.mouseover || image.mouseout) 
        {

          handler = document.createElement('div');
          Element.extend(handler);
          handler.setStyle({height: 20 + 'px'});
          
          //The '12' fudge factor is to compensate for the border we
          //draw around the image objects.
          var calcWidth = image.width + 12;
          handler.setStyle({width: calcWidth + 'px'}); 
          
	      //Add the over handler.
          ['mouseover'].each(function(evt) 
          {
             var evtfn = function(indx) {
               return function(event) 
               {
                   var heart_src_str = $(indx.toString() + "_heart").src;
                   
                   var rinx = heart_src_str.lastIndexOf("/") + 1;
                   
                   heart_src_str = heart_src_str.substring(rinx, heart_src_str.length);

                   if(heart_src_str != 'heart_full.png' )
                     $(indx.toString() + "_heart").src = 'heart_half.png'
                   
                 Event.stop(event);
               }
             }(index);
            
             heartIcon.observe(evt, evtfn.bindAsEventListener(image));
          });
          
          //Add the out handler.
          ['mouseout'].each(function(evt) 
          {
              var evtfn = function(indx) {
                return function(event) 
                {
                    var heart_src_str = $(indx.toString() + "_heart").src;
                    
                    var rinx = heart_src_str.lastIndexOf("/") + 1;
                    
                    heart_src_str = heart_src_str.substring(rinx, heart_src_str.length);

                    if(heart_src_str != 'heart_full.png' )
                      $(indx.toString() + "_heart").src = 'heart_empty.png'
                    
                  Event.stop(event);
                }
              }(index);
          	
              heartIcon.observe(evt, evtfn.bindAsEventListener(image));
          });
          
          //Add the click handler. Perform an AJAX request to submit the saved item.
          ['click'].each(function(evt) 
          {
              var evtfn = function(indx) {
                return function(event) 
                {
                    
                  var heart_src_str = $(indx.toString() + "_heart").src;
                    
                  var rinx = heart_src_str.lastIndexOf("/") + 1;
                    
                  heart_src_str = heart_src_str.substring(rinx, heart_src_str.length);
                    
                  var is_favorite = true;
                  
                  if(heart_src_str != 'heart_full.png' )
                  {
                      $(indx.toString() + "_heart").src = 'heart_full.png';
                  }
                  else 
                  {
                      is_favorite = false;
                      $(indx.toString() + "_heart").src = 'heart_empty.png';     
                  }

                  if(!image.favorite)
                  {
                      //Create a new one.
                      var updateUrl = "/favorites/create";
                      new Ajax.Request(updateUrl, {
                        method: 'post', 
                        parameters: {"favorite[user_id]" : image.user_id, "favorite[rendered_object_id]" : image._id},
                        onSuccess: function(transport) {
                          var response = transport.responseText || "no response text";
                          image.favorite = !image.favorite;
                          var jso = transport.responseText.evalJSON();
                          image.favorite_id = jso["id"];
                        },
                        onFailure: function(){ alert('Something went wrong...') }
                      });
                  } else
                  {
                      //Delete it.
                      var updateUrl = "/favorites/destroy/" + image.favorite_id.toString();
                      new Ajax.Request(updateUrl, {
                        method: 'delete', 
                        parameters: {},
                        onSuccess: function(transport) {
                          var response = transport.responseText || "no response text";
                          image.favorite = !image.favorite;
                        },
                        onFailure: function(){ alert('Something went wrong deleting favorite...') }
                      });
                  }
                  Event.stop(event);
                }
              }(index);
          	
              heartIcon.observe(evt, evtfn.bindAsEventListener(image));
          });
          
          
          //CROSS.
          //Add the over handler for the cross.
          ['mouseover'].each(function(evt) 
          {
             var evtfn = function(indx) {
               return function(event) 
               {
                   $(indx.toString() + "_cross").src = '/cross_full.png';
                   
                 Event.stop(event);
               }
             }(index);
            
             crossIcon.observe(evt, evtfn.bindAsEventListener(image));
          });
          
          //Add the out handler.
          ['mouseout'].each(function(evt) 
          {
              var evtfn = function(indx) {
                return function(event) 
                {
                    nodNam = indx.toString() + "_infotext";
                    
                    if(($(nodNam).childNodes[0]).nodeValue == "...")
                    {
                        $(indx.toString() + "_cross").src = '/cross_empty.png';
                    }
                    
                  Event.stop(event);
                }
              }(index);
          	
              crossIcon.observe(evt, evtfn.bindAsEventListener(image));
          });
          
          //Add the out handler.
          ['click'].each(function(evt) 
          {
              var evtfn = function(indx) {
                return function(event) 
                {
                    nodNam = indx.toString() + "_infotext";
                    
                    if(($(nodNam).childNodes[0]).nodeValue == "...")
                    {
                        newText = document.createTextNode("Click to add to group.");
                        
                        $(nodNam).removeChild($(nodNam).childNodes[0]);
                        $(nodNam).appendChild(newText);
                    }
                    else
                    {
                        //newText = document.createTextNode("...");
                    }

                  Event.stop(event);
                }
              }(index);
          	
              crossIcon.observe(evt, evtfn.bindAsEventListener(image));
          });

          handler.insert({bottom: favoriteLink});
          node = handler;

        }

      }
      td.insert({bottom: node});
      tr.insert({bottom: td});
      index++;
    });
    
    if (navigator.userAgent.match(/MSIE/)) {
      var tbody = document.createElement('tbody');
      tbody.appendChild(tr);
      tr = tbody;
    }
    imageTable.insert({bottom: tr});
    
    return imageTable;
  },
  
  createImageNodes: function(align, imageArray, controller, id) {
    // create table
    

    var imageTable = document.createElement('table');
    imageTable.id = "tablz";
    Element.extend(imageTable);
    imageTable.setAttribute('cellPadding', 0);
    imageTable.setAttribute('cellSpacing', 0);
    imageTable.setAttribute('border', 0);
    imageTable.addClassName('isg_table');
    
    tr = document.createElement('tr');
    Element.extend(this.tr);

    if(id == 'gallery')
    {
      if($('map-container') != null)
      {
        document.body.removeChild($('map-container')); 
      }
      mapdiv = document.createElement('div');
      mapdiv.id = 'map-container';
    }
           
    var index = 0;
    imageArray.each(function(image) 
    { 
    
      var td = document.createElement('td');
      Element.extend(td);
      td.setStyle({verticalAlign: align});
      
      if (image.padding)
        td.setStyle({paddingRight: image.padding + 'px'});

      var node, handler;
      if (image.src) {
        node = document.createElement('img');
        
        img_resources = image.ires;
        vid_resources = image.vres;
        if((img_resources != undefined && img_resources.length > 0) || (vid_resources != undefined && vid_resources.length > 0))
        {
           mapname = index.toString() + "_" + id + "_map";
           node.setAttribute('usemap', '#' + mapname);
        
           mapnode = document.createElement('map');
           mapnode.setAttribute('name', mapname);
      
           if(img_resources != undefined)
           {
             for (var aidx = 0; aidx < img_resources.length; aidx++)
             {
               ires = img_resources[aidx];
               areanode = document.createElement('area');
               areanode.setAttribute('shape', "rect");
               Element.extend(areanode);
               areanode.setStyle({border: '2px solid #dfdfdf'});
               coords = ires.map_x.toString() + " " + ires.map_y.toString() + " " + (ires.map_x + ires.map_w).toString() + " " + (ires.map_y + ires.map_h).toString();
               areanode.setAttribute('coords', coords);
               areanode.setAttribute('onclick', "return hs.htmlExpand(this, { objectType: 'ajax', width :" + (ires.width + 5).toString() + " ,height: " + (ires.height + 40).toString() + "} )");
               areanode.setAttribute('href', 'image_resources/' + ires.id.toString());
               mapnode.appendChild(areanode);
             }
           }
           
           if(vid_resources != undefined)
           {
             //Handle video resources.
             for (var aidx = 0; aidx < vid_resources.length; aidx++)
             {
                vres = vid_resources[aidx];
                areanode = document.createElement('area');
                areanode.setAttribute('shape', "rect");
             
                coords = vres.map_x.toString() + " " + vres.map_y.toString() + " " + (vres.map_x + vres.map_w).toString() + " " + (vres.map_y + vres.map_h).toString();
                areanode.setAttribute('coords', coords);
                //areanode.setAttribute('onclick', "return hs.htmlExpand(this, { objectType: 'ajax', width : 420, height: 295 } )");
                areanode.setAttribute('onclick', "return hs.htmlExpand(this, { objectType: 'ajax', width :" + (vres.width + 5).toString() + " ,height: " + (vres.height + 40).toString() + "} )");
                //areanode.setAttribute('onfocus', "alert(\"hello\");");
                areanode.setAttribute('href', 'video_resources/' + vres.id.toString());
                mapnode.appendChild(areanode);
             }
           }
           mapdiv.appendChild(mapnode);
        }
        

	      node.id = index.toString() + "_" + id;
	    
        Element.extend(node);
        
        if(id == 'gallery')
        {
          node.setStyle({border: '2px solid #dfdfdf', padding: '4px'});
        }
        
        if(id == 'gallery_sets' || id == 'gallery_selections')
        {
          node.setStyle({border: '2px solid #dfdfdf', padding: '1px'});
        }
            
	    if(image.active)
          node.setAttribute('src', image.src);

        if (image.width)
          node.setStyle({width: image.width + 'px'});
        if (image.height)
          node.setStyle({height: image.height + 'px'});
        if (image.click || image.mouseover || image.mouseout) {
          //handler = document.createElement('a');
          handler = document.createElement('div');
          Element.extend(handler);
          //handler.setAttribute('href', 'javascript:void(0)');
          handler.setStyle({display: 'block', lineHeight: 0, cursor :'pointer'});
          
	      //Add the handlers, if specified.
          ['click'].each(function(evt) {
            if (image[evt]) {
              //using bindAsEventListener allows us to pass image as 'this'
              
              handler.observe(evt, image[evt].bindAsEventListener(image));
            }
          });
         
          //Add the handlers, if specified.
          ['mouseover'].each(function(evt) 
          {
              if(id == 'gallery')
              {
                var titleShiftFunc = function(img, cont, idx) {
                  return function(event) {
                    cont.setTitle(img.title);
                    cont.setCaption(img.caption);
                    $(idx.toString() + "_" + id).setStyle({border: '2px solid #696969', padding: '4px'});
                    Event.stop(event);
                  }
               } (image, controller, index);
               handler.observe(evt, titleShiftFunc.bindAsEventListener(image));
                
              }
              else if(id == 'gallery_sets'|| id == 'gallery_selections')
              {
                var titleShiftFunc = function(img, cont, idx) {
                  return function(event) {
                    cont.setTitle(img.title);
                    cont.setCaption(img.caption);
                    $(idx.toString() + "_" + id).setStyle({border: '2px solid #696969', padding: '1px'});
                    Event.stop(event);
                  }
               } (image, controller, index);
               handler.observe(evt, titleShiftFunc.bindAsEventListener(image));
              }
              
              
              
          });
          
          //Add the handlers, if specified.
          ['mouseout'].each(function(evt) 
          {
              if(id == 'gallery')
              {
                var titleShiftFunc = function(idx) {
                  return function(event) {
                    $(idx.toString() + "_" + id).setStyle({border: '2px solid #dfdfdf', padding: '4px'});
                    Event.stop(event);
                  }
                }(index);
                handler.observe(evt, titleShiftFunc.bindAsEventListener(image));
              }
              else if(id == 'gallery_sets' || id == 'gallery_selections')
              {
                var titleShiftFunc = function(idx) {
                  return function(event) {
                    $(idx.toString() + "_" + id).setStyle({border: '2px solid #dfdfdf', padding: '1px'});
                    Event.stop(event);
                  }
                }(index);
                handler.observe(evt, titleShiftFunc.bindAsEventListener(image));
              }
          });

          handler.insert({bottom: node});
          node = handler;
        }
      } else if (image.markup) 
      {

        node = document.createElement('div');
        Element.extend(node);

	      node.id = index.toString();
	      
        node.addClassName('isg_markup-wrapper');
        node.setStyle({width: image.width + 'px', height: image.height + 'px'});



        if(id == 'gallery_dates')
        {
            //Add the handlers, if specified.
            ['click'].each(function(evt) {

                var dateClickFunc = function(div_id) {
                  return function(event) {

                      if(selectedDate != undefined && selectedDate != div_id)
                      {
                          $(selectedDate).setStyle({fontWeight: 'normal'});
                      }
                      selectedDate = image.div_id;
                      
                      $(selectedDate).setStyle({'fontWeight': 'bold'});

                      if(image[evt]) image[evt]();
                      Event.stop(event);
                  }
                }(image.div_id);
        
                node.observe(evt, dateClickFunc.bindAsEventListener(image));
            });
        } else if(id == 'gallery_setreps')
        {
    	    //Add the handlers, if specified.
            ['click'].each(function(evt) {
                
                var setRepClickFunc = function(div_id) {
                  return function(event) {
                      if(selectedSetRep != undefined && selectedSetRep != div_id)
                      {
                          $(selectedSetRep).setStyle({border: '1px solid #fff', 'float': 'left', padding: '4px 0px 4px 8px', width: '260px', height: '120px'});
                      }
                      selectedSetRep = image.div_id;
                      $(image.div_id).setStyle({border: '1px solid #333', 'float': 'left', padding: '4px 0px 4px 8px', width: '260px', height: '120px'});
                      if(image[evt]) image[evt]();
                      Event.stop(event);
                  }
                }(image.div_id);
                
                node.observe(evt, setRepClickFunc.bindAsEventListener(image));
            });
            
            ['mouseover'].each(function(evt) {
                var setRepOverFunc = function(div_id) {
                  return function(event) {
                      if(selectedSetRep != image.div_id)
                      {
                          $(image.div_id).setStyle({border: '1px solid #ddd', 'float': 'left', padding: '4px 0px 4px 8px', width: '260px', height: '120px'});
                      }
                      if(image[evt]) image[evt]();
                      Event.stop(event);
                  }
                }(image.div_id);
                
                node.observe(evt, setRepOverFunc.bindAsEventListener(image));
                
                if (image[evt]) {
                  //using bindAsEventListener allows us to pass image as 'this'
                  node.observe(evt, image[evt].bindAsEventListener(image));
                }
            });
            
            ['mouseout'].each(function(evt) {
                
                var setRepOutFunc = function(div_id) {
                  return function(event) {
                      if(selectedSetRep != image.div_id)
                      {
                          $(image.div_id).setStyle({border: '1px solid #fff', 'float': 'left', padding: '4px 0px 4px 8px', width: '260px', height: '120px'});
                      }
                      if(image[evt]) image[evt]();
                      Event.stop(event);
                  }
                }(image.div_id);
                
                node.observe(evt, setRepOutFunc.bindAsEventListener(image));
                
                if (image[evt]) {
                  //using bindAsEventListener allows us to pass image as 'this'
                  node.observe(evt, image[evt].bindAsEventListener(image));
                }
            });
        } else
        {
            //Add the handlers, if specified.
            ['click', 'mouseover', 'mouseout'].each(function(evt) {
                if (image[evt]) {
                  //using bindAsEventListener allows us to pass image as 'this'
                  node.observe(evt, image[evt].bindAsEventListener(image));
                }
            });   
        }
        
        node.update(image.markup);
      }          
      td.insert({bottom: node});
      tr.insert({bottom: td});
      index++;
    });
    
    if(id == 'gallery')
    {
        document.body.appendChild(mapdiv); 
    } 
      
    if (navigator.userAgent.match(/MSIE/)) {
      var tbody = document.createElement('tbody');
      tbody.appendChild(tr);
      tr = tbody;
    }
    imageTable.insert({bottom: tr});
    return imageTable;
  }
});


// ---------------------- ImageShiftImage

com.buzamoto.ImageShiftGallery.Image = Class.create({
  
  initialize: function(gallery, imageObject) {
    this.gallery = gallery;
    this.properties = com.buzamoto.ImageShiftGallery.Image.DEFAULT.merge($H(imageObject));
    this.width = this.properties.get('width');
    this.height = this.properties.get('height');
    this.image = new Image();
    this.image.active = imageObject.active;
    this.image.stepSize = imageObject.stepSize;
    this.title = this.properties.get('title');
    this.caption = this.properties.get('caption');

  }, 
  
  getWidth: function() {
    //Plus 12 for the fudge factor.
    return this.width + this.properties.get('padding') + 12;
  },
  
  getHeight: function() {
    return this.height;
  },
  
  getTitle: function() {
    return this.properties.get('title');
  },
  
  getCaption: function() {
    return this.properties.get('caption');
  }
  
});
Object.extend(com.buzamoto.ImageShiftGallery.Image, {
  DEFAULT: $H({
    src:     '',
    caption: '...',
    title:   '...',
    active: true,
    stepSize: 1,
    width:   0, 
    height:  0,
    padding: 0
  })
});


// ---------------------- ImageShiftMarkup

com.buzamoto.ImageShiftGallery.Markup = Class.create({
  
  initialize: function(gallery, obj) {
    this.gallery = gallery;
    this.properties = com.buzamoto.ImageShiftGallery.Markup.DEFAULT.merge($H(obj));
    this.markup = obj.markup
  },
  
  getWidth: function() {
    return this.properties.get('width') + this.properties.get('padding');
  },
  
  getHeight: function() {
    return this.properties.get('height');;
  },
  
  getTitle: function() {
    return this.properties.get('title');
  },
  
  getCaption: function() {
    return this.properties.get('caption');
  }
  
});
Object.extend(com.buzamoto.ImageShiftGallery.Markup, {
  DEFAULT: $H({
    markup:     '<div style="width: 500px; height: 500px; background-color: red;"></div>',
    caption: '...',
    title:   '...',
    width:   500, 
    height:  500,
    padding: 0
  })
});


// ---------------------- ImageShiftController

com.buzamoto.ImageShiftGallery.Controller = Class.create({
  
  /* ------------- CALLBACKS ------------- */
  /* ------------- EDITABLE -------------- */
  
  onShiftStart: function() {
    this.setTitle("...");
    this.setCaption("&nbsp;");
    switch (this.dir) {
      case "next":
        //We've loaded everything. Don't continue.
        if(this.imgsArray.length == this.gallery.loadIndex)
    	{
    	  break;
    	}
    	
    	var i;
    	var lenDelta = this.imgsArray.length - this.gallery.loadIndex;
    	
    	var shiftStepSize = this.shiftStep;
    	
    	var shiftStep = (lenDelta >= shiftStepSize) ? shiftStepSize : lenDelta;
    	
    	for (i = 0; i < shiftStep; i++) {
        	//Force the next image to load.
            var img = this.imgsArray[this.gallery.loadIndex];
            if(this.gallery.id == 'gallery')
    	      //Make the image load.
              $(this.gallery.loadIndex.toString() + "_" + this.gallery.id).setAttribute('src', img.properties.get('src'));
            else
              $(this.gallery.loadIndex.toString()).setAttribute('src', img.properties.get('src'));
          
            this.imgsArray[this.gallery.loadIndex].active = true;
            this.gallery.loadIndex++;
        }
        break;
        
       case "prev":
        break;
     }

  },

  onShiftEnd: function() {
    var title = (this.imgsArray[this.unit].getTitle()) ? this.imgsArray[this.unit].getTitle() : "";
    var caption = (this.imgsArray[this.unit].getCaption()) ? this.imgsArray[this.unit].getCaption() : "";
    this.setTitle(title);
    this.setCaption(caption);
  },
  
  /* ------------- DON'T EDIT PAST HERE ------------- */
  
  initialize: function(gallery, stepSize) {
    this.gallery = gallery;
    this.posX = 0;
    this.dir = "next";
    this.moving = false;
    this.frame = 0;
    this.frameTotal = com.buzamoto.ImageShiftGallery.Gallery.MOVE_COORDS.length;
    this.MOVE_COORDS = new Array(this.frameTotal);
    this.timerID = null;
    this.imgsArray = this.gallery.imageArray;
    this.shiftStep = stepSize;
    this.unit = 0;
    this.unitTotal = this.imgsArray.length;
    if(this.unitTotal != 0)
    {
        var title = (this.imgsArray[this.unit].getTitle()) ? this.imgsArray[this.unit].getTitle() : "";
        var caption = (this.imgsArray[this.unit].getCaption()) ? this.imgsArray[this.unit].getCaption() : "";
        this.setTitle(title);
        this.setCaption(caption);
    } else
    {
        this.setTitle(" ");
        this.setCaption(" ");
    }
  },
  
  setCaption: function(caption) 
  {
    caplink = caption;
      
    if(caption.match("^"+"http") == "http")
    {
      caplink = "<a href=" + caption +">" + caption + "</a>";
    }
    
    if ($(this.gallery.wrapper.id+"_caption")) $(this.gallery.wrapper.id+"_caption").update(caplink);
  },
  
  setTitle: function(title) 
  {
    if ($(this.gallery.wrapper.id+"_title")) $(this.gallery.wrapper.id+"_title").update(title);
  },

  calcX: function(dir, currX, step) {
    var i, scale = 0;

    switch (dir) {
      case "next":
        for (i = 0; i < step; i++) {
          scale += this.imgsArray[this.unit + i].getWidth() / 100;
        }
        for (var i = 0; i < this.frameTotal; i++) {
          this.MOVE_COORDS[i] = currX + com.buzamoto.ImageShiftGallery.Gallery.MOVE_COORDS[i] * scale;
        }
        break;
      
      case "prev":
        for (i = 1; i <= step; i++) {
          scale += this.imgsArray[this.unit - i].getWidth() / 100;
        }
        for (var i = 0; i < this.frameTotal; i++) {
          this.MOVE_COORDS[i] = currX - com.buzamoto.ImageShiftGallery.Gallery.MOVE_COORDS[i] * scale;
        }
        break;

      case "start":
        for (var i = 0; i < this.frameTotal; i++) {
          this.MOVE_COORDS[i] = currX - com.buzamoto.ImageShiftGallery.Gallery.MOVE_COORDS[i] / 100 * (this.gallery.totalWidth - this.imgsArray[this.imgsArray.length-1].getWidth());
        }
        break;
      
      case "end":
        for (var i = 0; i < this.frameTotal; i++) {
          this.MOVE_COORDS[i] = currX + com.buzamoto.ImageShiftGallery.Gallery.MOVE_COORDS[i] / 100 * (this.gallery.totalWidth-this.imgsArray[this.imgsArray.length-1].getWidth());
        }
    }
  },

  moveTo: function(x) {
    $(this.gallery.container.id).style.left = x + "px";
  },

  move: function(dir) 
  {
    this.setDir(dir);
    this.run();
  },

  setDir: function(dir) {
    this.dir = dir;
  },

  run: function() {
    if (this.timerID) {
      window.clearTimeout(this.timerID);
      this.timerID = null;
    }
    
    var shiftStepSize = this.shiftStep;
    
    if (!this.moving) {
      // run on start callback
      this.onShiftStart();
      if (this.dir == "next") {
        if (this.unit < this.unitTotal-1) {
          if(this.unit + shiftStepSize >= this.unitTotal-1)
          {
              this.calcX("next", this.posX, this.unitTotal - 1 - this.unit);
              this.unit += this.unitTotal - 1 - this.unit;
              
          } else
          {
              this.calcX("next", this.posX, shiftStepSize);
              this.unit += shiftStepSize;
          }
        }
        else if (this.unit == this.unitTotal-1) {
          this.calcX("start", this.posX, shiftStepSize);
          this.unit = 0;
        }
        else return;
      }
      else if (this.dir == "prev") {
        if (this.unit > 0) {
          if(this.unit - shiftStepSize < 0)
          {
              this.calcX("prev", this.posX, 1);
              this.unit -= 1;
          } else
          {
              this.calcX("prev", this.posX, shiftStepSize);
              this.unit -= shiftStepSize;
          }
        }
        else if (this.unit <= 0) {
          //Hack to prevent movement to end by hitting prev at the beginning of the list.
          //this.calcX("end", this.posX);
          //this.unit = this.unitTotal-1;
          this.onShiftEnd();
          return;
        }
        else return;
      }
      else return;
      this.moving = true;
    }
    if (this.frame < this.frameTotal) {
      this.posX = this.MOVE_COORDS[this.frame];
      this.frame++;
      this.moveTo(this.posX);
      var self = this;
      this.timerID = window.setTimeout(function() {
        self.run();
      }, 20);
    }
    else {
      this.moving = false;
      this.frame = 0;
      window.clearTimeout(this.timerID);
      this.timerID = null;
      // run on end callback
      this.onShiftEnd();
    }
  }
});
