d = new Debug( 'off' );   // TODO: change for release!

/**
 * Singleton object to hold data and functionality for this page
 */
function DennisWise( options ) {
  
  // Setup default values
  options = $.extend({
    cameFromSplash: false,
    isHome: false,
    numToShow: 20,
    numRows: 4,
    numCols: 5
  }, options || {} );
  
  if( 'undefined' == typeof options.imageList ) {
    alert( "Invalid imageList specified." );
    return;
  }

  // Number of images to show at a time.  -1 means show as many as there are spots available
  this.numToShow = options.numToShow;
  
  // List of all images that can be displayed on this page (note: this can be >20 images for the home
  // page as those images will rotate).  Otherwise, it should be no larger than 20 images for a given
  // page.
  this.imageList = imageList;

  // True if we're on the home page
  this.isHome = options.isHome;
  
  // True if we came from the splash.html page
  this.cameFromSplash = options.cameFromSplash;
  
  // Size of the image grid
  this.numRows = options.numRows;
  this.numCols = options.numCols;
  
  // Max number of images on a page
  this.imagesPerPage = this.numRows * this.numCols;

  // Image transistion duration base number (some transitions are in fractions of this number, in ms)
  this.delay = 500;
  
  // Time (in ms) for images to fade in or out
  this.fadeDelay = 500;
  
  // Array of images that have been displayed
  this.picked = new Array();
  
  // Array of table cells with images in them, initially all are empty
  this.alreadyFilled = new Array();
  for( i = 0; i < ( this.imagesPerPage ); i++ ) {
    this.alreadyFilled[i] = false;
  }
  
  // Where we are in the list of images to be displayed
  this.imageListIndex = 0;
  
  // Trails imageListIndex, points to the first image in the last batch of displayed images.
  // Used to fade out images as we fade in new ones
  this.displayedImageIndex = 0;
  
  // How often to cycle images on the home page
  this.homeRefreshInterval = 8000;
//  this.homeRefreshInterval = 3000;
  
  if( -1 == this.numToShow ) {
    // -1 means show as many as will fit from imageList, but not more than what we have room for
    this.numToShow = ( this.imageList.length > ( this.numCols * this.numRows )) ? ( this.numCols * this.numRows ) : this.imageList.length;
  } else if( this.imageList.length < this.numToShow ) {
    this.numToShow = this.imageList.length;
  }
  
  // Reduce fadeIn time if we've got a lot of images to show.  Note: this.delay must be > 0.
  if ( this.numToShow > 10 ) {
    this.delay = this.delay / 2;
  } 

  d.print( "Created dw object: %o", this );
}

DennisWise.prototype.markAsFilled = function( gridId ) {
  var row, col;
  if( 'object' == typeof gridId ) {
    this.alreadyFilled[( gridId.row * this.numCols ) + gridId.col] = true;
  } else {
    this.alreadyFilled[gridId] = true;
  }
}

DennisWise.prototype.markAsEmpty = function( gridId ) {
  if( 'object' == typeof gridId ) {
    this.alreadyFilled[( gridId.row * this.numCols ) + gridId.col] = false;
  } else if ( 'number' == typeof gridId ) {
    this.alreadyFilled[gridId] = false;
  }
}

DennisWise.prototype.isFull = function( gridId ) {
  if( 'object' == typeof gridId ) {
    return this.alreadyFilled[( gridId.row * this.numCols ) + gridId.col];
  } else if ( 'number' == typeof gridId ) {
    return this.alreadyFilled[gridId];
  }
}

DennisWise.prototype.isEmpty = function( gridId ) {
  if( 'object' == typeof gridId ) {
    return !this.alreadyFilled[( gridId.row * this.numCols ) + gridId.col];
  } else if ( 'number' == typeof gridId ) {
    return !this.alreadyFilled[gridId];
  }
}

/**
 * Onload code
 */
DennisWise.prototype.init = function() {
	
	// Hide thumbnails at first
	if( $.browser.safari ) {
	  $( ".thumbCell img, #noJS" ).css( 'display', 'none' );
	} else {
	  // Basically the same thing, but since we use fadeIn to display, we protect ourselves from
	  // future changes to how they implement by using hide().  Alas, Safari does hide on hide(),
	  // for whatever reason...
	 $( ".thumbCell img, #noJS" ).hide();
	}
	
	// Disable links until we've setup Lightbox
	$( ".thumbCell a" ).bind( 'click', disableLink );
	
	if( this.cameFromSplash ) {
		$( "#menu" )
			.hide();
	}

	// Start the show...
	$( "#everything" ).fadeIn( this.fadeDelay );

	if( '' != errStr ) {
		alert( errStr );
		return;	
	}

  // Set up Contact link
  var me = this;
  $( "#contact" ).click( function() {
    $( "#everything" ).css({ opacity: .1 });
    var div = $( "#contactInfo div" );
    if( "0px" == div.css( "top" )) {
      div.css( "top", ( $( window ).height() - div.height()) / 2 );
    }
    $( "#contactInfo" )
      .css({ left: 0, display: "none" })
      .fadeIn( me.fadeDelay )
      .click( function() {
        $( "#everything" ).css({ opacity: 1.0 });
        $( this ).fadeOut( me.fadeDelay );
      });
    return false;
  });

  // Set up client list link
  $( "#clients" ).click( function() {
    $( "#everything" ).css({ opacity: .1 });
    var div = $( "#clientList div" );
    if( "0px" == div.css( "top" )) {
      div.css( "top", ( $( window ).height() - div.height()) / 2 );
    }
    $( "#clientList" )
      .css({ left: 0, display: "none" })
      .fadeIn( me.fadeDelay )
      .click( function() {
        $( "#everything" ).css({ opacity: 1.0 });
        $( this ).fadeOut( me.fadeDelay );
      });
    return false;
  });

	// Set up Links link
	// Links section removed for now...
//	$( "#links" ).hover( function() {
//		// Mouse over
//		$( this ).find( "ul" )
//	    .stop()
//	    .css({ opacity: 1.0 })
//	    .show();
//	}, function() {
//		// Mouse out
//		$( this ).find( "ul" )
//		  .stop()
//		  .fadeOut( this.delay );
//	});

	if( !this.imageList.length ) {
		// Error condition -- something went wrong!
		return;
	}

  this.showImages();
};

DennisWise.prototype.showImages = function() {

  // Set interval loop to display images in table
  var me = this;
  var si = setInterval( function() {
    if( 'undefined' == typeof me.imageList[me.imageListIndex].getGridId() ) {
      me.imageList[me.imageListIndex].setGridId( me.findOpenSpot() );
    } else {
      me.markAsFilled( me.imageList[me.imageListIndex].getGridId() );
    }
    me.imageList[me.imageListIndex].showImage({
      duration: me.fadeDelay
    });
    me.imageListIndex++;

    // Loop around to the beginning
    if( me.imageListIndex == me.imageList.length ) {
      me.imageListIndex = 0;
    }

    if(( me.imageListIndex % me.numToShow ) == 0 ) {
      clearInterval( si );
      if( me.isHome ) {
        $( "#menu" ).fadeIn( me.delay );
      }
      $( ".lightbox-enabled" ).lightbox();
      $( ".thumbCell a" ).unbind( 'click', disableLink );
    }
  }, me.delay / 3 );
  
  // Set up loop to refresh home page display every so often
  if( me.isHome ) {
    me.cycleCount = 0;
    var refreshInterval = setInterval( function() {
      d.print( "Starting new cycle" );
      
      // Disable clicks while we're cycling
      $( '#thumbs a' ).bind( 'click', disableLink );
      
      // Setup an interval of the numToShow images to transition
      var trans = setInterval( function() {
        var oldGridId = me.imageList[me.displayedImageIndex].getGridId();
        me.imageList[me.displayedImageIndex].hideImage( me.fadeDelay, function( thumb ) {
          me.markAsEmpty( oldGridId );
        });
        me.imageList[me.imageListIndex].showImage({
          gridId: me.findOpenSpot(),
          duration: me.fadeDelay
        }); 

        // Loop around when we hit the end of the list
        if( ++me.imageListIndex == me.imageList.length ) {
          me.imageListIndex = 0;
        }
        if( ++me.displayedImageIndex == me.imageList.length ) {
          me.displayedImageIndex = 0;
        }

        // Cycle numToShow images each time
        if( ++me.cycleCount >= me.numToShow ) {
          clearInterval( trans );
          $( ".lightbox-enabled" ).lightbox();
          $( '#thumbs a' ).unbind( 'click', disableLink );
          me.cycleCount = 0;
        }
      }, me.delay / 3 );
    }, me.homeRefreshInterval );
  }
}

/**
 * Returns the index of a random available (empty) spot in the image grid.  NOTE this routine
 * assumes the calling routine isn't stupid enough to ask for an open spot when none would exist!
 */
DennisWise.prototype.findOpenSpot = function() {
  if( -1 == $.inArray( false, this.alreadyFilled )) {
    // I'm an idiot...
    alert( "ERROR: No open spots in findOpenSpot!" );
    return;
  }
  var gridId = Math.floor( Math.random() * ( this.imagesPerPage ));   // Zero-based
  while( this.isFull( gridId )) {
    gridId = Math.floor( Math.random() * ( this.imagesPerPage ));
  }
  this.markAsFilled( gridId );
  d.print( "Found open spot: %d in %o", gridId, this.alreadyFilled );
  return( gridId );
}

/*******************************************/	
/*******************************************/	


/**
 * Photo object
 */
function Thumbnail( options ) {
  options = $.extend({
    index: -1,       // Position in the overall image list for this category
    src: '',         // Image filename (no path) 
    width: -1,       // Width and height in pixels
    height: -1,
    gridId: null,
    subdir: '',      // In case the image is in a subdirectory of the /portfolio directory (eg: large upload of private images)
    duration: 500    // Default duration of transition events, in ms.
  }, options || {} );
  d.print( "Creating thumbnail: %o", options );
  
  // Required params
  if(( -1 == options.index ) || ( '' == options.src ) || ( -1 == options.width ) || ( -1 == options.height )) {
    throw new Error( "Missing required parameter in contructor" );
  } else {
    this.index = options.index;
    this.src = options.src;
    this.width = options.width;
    this.height = options.height;
  }
  
  // Optional params
  this.subdir = options.subdir;
  this.duration = options.duration;
  this.visible = false;
  this.gridId = options.gridId;
  
  if( '' == this.subdir ) {
    this.thumbSrc = "portfolio/thumbs/"+this.src;
    this.fullSrc = "portfolio/full/"+this.src;
  } else {
    this.thumbSrc = "portfolio/" +this.subdir+ "/thumbs/"+this.src;
    this.fullSrc  = "portfolio/" +this.subdir+ "/full/"+this.src;
  }
  prefetchImage( this.thumbSrc );
}
Thumbnail.prototype.isVisible = function() {
  return this.visible;
};
/**
 *
 */
Thumbnail.prototype.showImage = function( options ) {
  var me = this;
  options = $.extend({
    cellWidth: 171,
    cellHeight: 171,
    gridId: me.gridId,
    duration: 500
  }, options || {} );

  if(( 'undefined' == typeof options.gridId ) || ( -1 == options.gridId )) {
    throw new Error( "Must set gridId before calling showImage()" );
    return false;
  }
  d.print( "showing image: this: %o, gridId: %d", this, options.gridId );

  this.gridId = options.gridId;   // Used when hiding image
  $( '#thumbCell' +options.gridId+ ' img' )
    .attr({
      src: this.thumbSrc,
      height: this.height,
      width: this.width
    })
    .css({ marginTop: (( options.cellHeight - this.height ) / 2 ) +'px' })
    .fadeIn( options.duration, function() { me.visible = true; })
    .parent()   // Also change the surrounding link destination
      .attr( 'href', this.fullSrc )
      .addClass( 'lightbox-enabled' );

  return true;
};
Thumbnail.prototype.hideImage = function( duration, callback ) {
  if( 'undefined' == typeof duration ) {
    duration = this.duration;
  }
  if( 'undefined' == typeof callback ) {
    callback = function() {};
  }
  d.print( "hiding image: this: %o, gridId: %d, callback: %o", this, this.gridId, callback );

  var me = this;
  $( '#thumbCell' +this.gridId+ ' img' )
    .parent().removeClass( 'lightbox-enabled' )
    .end().fadeOut( duration, function() {
      me.visible = false;
      callback( me );
    });
};
Thumbnail.prototype.getGridId = function () {
  return this.gridId;
}
Thumbnail.prototype.setGridId = function( gridId ) {
  d.print( "Setting %o to gridId %d", this, gridId );
  this.gridId = gridId;
}


/*******************************************/	
/*******************************************/	

/**
 * Debugging object 
 */
function Debug( debugMode ) {
  if( 'undefined' == typeof debugMode ) {
    debugMode = 'off';
  }
  if( !window.console ) {
    debugMode = 'off';
  }

  this.mode = debugMode;
  this.print = function(){};
  
  if( 'on' == this.mode ) {
    if( console.debug ) {
      this.print = console.debug;
    } else if( console.log ) {
      this.print = function() {
        if( arguments.length ) {
          console.log( arguments[0] );
        }
      }
    }
  }
}
/*************************************/
/*************************************/
function prefetchImage( url ) {
	var i = new Image();
	i.onload = function() {
		// Release memory after image has been cached
		i.onload = null;
		i = null;
	};
	i.src = url;
}

// image is required, isThumb is optional, defaults to true
function getImageUrl( image, isThumb ) {
	if(( undefined === isThumb ) || isThumb ) {
	  return "portfolio/700/" +image;
	} else {
	  return "portfolio/160/" +image;
	}
}

function disableLink() {
  return false;
}
;
