/**
 * Object productMenu
 * Creates a menu of products that scroll horizontally or vertically and changes between them when clicked
 * 
 * @param _menu_elem_id the ID of the "product menu" element, whatever will contain the whole menu monstrosity.
 * @param _clip_width total width available to the image menu's contents
 * @param _clip_height total height available to the image menu's contents
 * @param _between_images amount in pixels that will appear between the menu items
 * @param _img_base_dir the directory in which to find the menu's arrows and such...note that the images added
 * 		as menu items need full paths.
 * @param [vertical] if present and true then the menu is positioned vertically, otherwise horizontal.
 * @param [id_prefix] if present, this prefix is added to all XHTML element id's that are used by the menu
 * 
 * TODO: Check to see if the max-width max-height works on ie6 to scale the thumbs/medium res images.
 */
function jacProductMenu(_menu_elem_id, _clip_width, _clip_height, _between_images, _img_base_dir)
{
	//array of image properties displayed in our menu, as well as their information
	var menu_imgs = new Array();
	
	var menu_items = new Array();

	//the elements that hold the information box and the image
	var menu_elem = $(_menu_elem_id);

	//the base directory where images are stored
	var img_base_dir = _VOES(_img_base_dir);
	
	//whether the next and previous controls are enabled
	var control_enabled = new Hash({prev: false, next: false});
	var control_hidden = new Hash({prev: false, next: false});

	//clipping box properties
	var between_images = _between_images != null ? _between_images : 0;
	var vertical = arguments.length >= 6 ? arguments[5] : false;
	var clip_width = _clip_width != null ? _clip_width : (vertical ? 110 : 600);
	var clip_height = _clip_height != null ? _clip_height : (vertical ? 375 : 77);

	//current scrolling position
	var begin_index = 0;
	var end_index = 0;
	var scroll_position = 0;

	var cur_partition = null;
	var item_partitions = new Array();

	var id_prefix = arguments.length >= 7 ? (arguments[6] + '-') : '';

	//to avoid calculating this with a for loop
	var total_img_and_margin_width = 0;
	
	var observing = false;
	var click_menu_bound = null;
	var click_prev_bound = null;
	var click_next_bound = null;

	/* Private Functions */
	function show_partition(_partition)
	{
		if(_partition < 0)
			return;
		
		if(_partition >= item_partitions.length)
		{
			if(_partition - 1 >= item_partitions.length)
				return;

			//set beginning to the end of the last partition, which won't be included in last partition, if
			//the 0th partition, use 0 to start
			var begin_part = _partition == 0 ? 0 : item_partitions[_partition-1].get('last');
			var end_part = begin_part;
			if(begin_part >= menu_items.length)
				return;
//			alert('creating partition');

			var clip_used = 0;
			var dim = vertical ? 1 : 0;
			var temp_between = 0;
			for(end_part = begin_part; end_part < menu_items.length; end_part++)
			{
				var thumb_size = menu_items[end_part].get_thumb_size();
				if((clip_used += thumb_size[dim] + temp_between) > (vertical ? clip_height : clip_width))
				{
					//take off one extra "between_images" amount, avoid fencepost error
					clip_used -= (thumb_size[dim] + temp_between);
					break;
				}

				//if we are on first image, change the between to the regular
				if(end_part == begin_part)
					temp_between = between_images;
			}
//			alert('clip_used: ' + clip_used + ', clip_width: ' + clip_width);
			//end_part will be one past the last thumb that fit (or one past the end of menu items);
			//the interval is [begin_part, end_part) like c++ STL
			item_partitions.push(new Hash({first: begin_part, last: end_part, clip_used: clip_used}));
		}

		var h = item_partitions[_partition];
		cur_partition = _partition;
//		alert(h.get('first') + ', ' + h.get('last') + ', ' + h.get('clip_used'));
		show_items.call(this, item_partitions[_partition]);
	}

	function show_items(_partition)
	{
		var first = _partition.get('first');
		var last = _partition.get('last');
		if(first < 0 || last > menu_items.length)
			return;

		//make sure the old begin_index has a margin again
		var new_style = vertical ? {margin: between_images + 'px 0 0 0'} : {margin: '0 0 0 ' + between_images + 'px'};
//		$('product-menu-' + begin_index).setStyle(new_style);
		begin_index = first;
		end_index = last;
		for(var i = 0; i < menu_items.length; i++)
		{
			if(i >= begin_index && i < end_index)
			{
				$(id_prefix + 'product-menu-' + i).show();
				$(id_prefix + 'product-menu-' + i).setStyle(new_style);
			}
			else
				$(id_prefix + 'product-menu-' + i).hide();
		}
		//and the new one doesn't
		$(id_prefix + 'product-menu-' + begin_index).setStyle({margin: 0});

		//center the menu images within the available area
		scroll_position = ((vertical ? clip_height : clip_width) - _partition.get('clip_used'))/2;
		new_style = vertical ? {paddingTop: scroll_position + 'px'} : {left:  scroll_position + 'px'};
		$(id_prefix + 'product-menu').setStyle(new_style);

		this.disable_controls(begin_index == 0, end_index == menu_items.length);
	}

	function click_menu_item(e)
	{
		//get the menu item corresponding to the index of all characters after product-menu-img-
		var index = parseInt(e.element().id.substring(17 + id_prefix.length));
		
		var cur_item = menu_items[index];
		cur_item.item_click();
	}

	/**********************************************
	 * click_next
	 * event observer for the control-next click event
	 * @param e - event object passed
	 * @return none
	 */
	function click_next(e)
	{
		if(control_enabled.get('next'))
			show_partition.call(this, cur_partition + 1);
//			show_items_from_index.call(this, end_index + 1);
	}

	/**********************************************
	 * click_prev
	 * Event handler for prev-control click event.
	 * @param e - event object
	 * @return none
	 */
	function click_prev(e)
	{
		if(control_enabled.get('prev'))
			show_partition.call(this, cur_partition - 1);
//			show_items_to_index.call(this, begin_index - 1);
	}

	//
	//"public" functions

	//call to redisplay the menu after items have been added (or removed)
	this.update = function()
	{
		if(observing)
			this.stop_observing();

		//maximum clip height
		if(!vertical && clip_height > 120)
			clip_height = 100;
		else if(vertical && clip_width > 115)
			clip_width = 115;

		cache_image(img_base_dir + '/product-menu-scroll-prev.png');
		cache_image(img_base_dir + '/product-menu-scroll-next.png');
		cache_image(img_base_dir + '/product-menu-scroll-prev-disabled.png');
		cache_image(img_base_dir + '/product-menu-scroll-next-disabled.png');
		cache_image(img_base_dir + '/progress-indicator.gif');

		var prev_control_html = 
			'<div id="' + id_prefix + 'scroll-prev" class="scroll-button prev disabled"></div>'; // + 
		var scroll_bckgnd_html =
			'<div id="' + id_prefix + 'scroller-background"></div>';
		var next_control_html = 
			'<div id="' + id_prefix + 'scroll-next" class="scroll-button next disabled"></div>';// +

		var product_menu_items = menu_items.inject('',
			function(acc, n, index)
			{
				return acc +
					'<li id="' + id_prefix + 'product-menu-' + index + '">' +
						n.get_menu_xhtml(id_prefix + 'product-menu-img-' + index) +
					'</li>\n';
			});

		var product_menu_html = 
			'<div id="' + id_prefix + 'product-menu-cropper">' +
				'<ul id="' + id_prefix + 'product-menu" class="product-menu">' +
					product_menu_items +
				'</ul>' +
			'</div>';

		//FIXME: change it so we dont' hav eto do the control html for either one
		if(vertical)
			prev_control_html = next_control_html = '';
		menu_elem.update(prev_control_html + product_menu_html + next_control_html);

		click_menu_bound = click_menu_item.bindAsEventListener(this);
		menu_items.each(
			function(elem, index)
			{
				$(id_prefix + 'product-menu-img-' + index).observe('click', click_menu_bound);
			});

		click_prev_bound = click_prev.bindAsEventListener(this);
		click_next_bound = click_next.bindAsEventListener(this);
		$(id_prefix + 'scroll-prev').observe('click', click_prev_bound);
		$(id_prefix + 'scroll-next').observe('click', click_next_bound);

		observing = true;

		//change the width, the container needs to be 70px bigger than the cropper, 35px margin with control in
		//it on either side
//		var menu_width = vertical ? clip_width + 10 : clip_width + 70;
//		menu_elem.setStyle({position: 'relative', top: '0', left: '0', width: menu_width + 'px',
//			height: clip_height + 'px'});

		$(id_prefix + 'product-menu-cropper').setStyle({position: 'absolute', top: '0', left: vertical ? '0' : '35px',
			overflow: 'hidden',	width: clip_width + 'px', height: clip_height + 'px'});

		$(id_prefix + 'product-menu').setStyle({display: 'block', position: 'absolute', top: '0', left: '0',
			bottom: '0', /* width: 210*menu_items.length + 'px', */ lineHeight: '0'});

		//moved from top
//		show_items_from_index.call(this, 0);
		show_partition.call(this, 0);
	};

	this.stop_observing = function()
	{
		if(click_menu_bound != null)
			menu_imgs.each(
				function(elem, index)
				{
					$(id_prefix + 'product-menu-img-' + index).stopObserving('click', click_menu_bound);
				});

		if(click_prev_bound != null)
			$(id_prefix + 'scroll-prev').stopObserving('click', click_prev_bound);
		if(click_next_bound != null)
			$(id_prefix + 'scroll-next').stopObserving('click', click_next_bound);
		
		observing = false;
	};

	this.add_menu_item = function(menu_item)
	{
		var thumb_size = menu_item.get_thumb_size();
		if(thumb_size[1] > clip_height)
			clip_height = thumb_size[1];
		menu_items.push(menu_item);
	};
	this.remove_menu_item = function(index)
	{
		menu_items.splice(index, 1);
	};

	this.add_image = function(_thumb_uri, _med_uri, _large_uri, _thumb_width, _thumb_height, _alt, _info)
	{
		var uri_match = _med_uri.match(/^([a-zA-Z0-9\-_~\/%]*)\.?([a-zA-Z]*)?$/);

		var _base_uri = uri_match[1];
		var _ext = uri_match[2];

		cache_image(_thumb_uri);

		if(vertical)
		{
			if(_thumb_width > clip_width)
				clip_width = _thumb_width;
		}
		else
		{
			if(_thumb_height > clip_height)
				clip_height = _thumb_height;
		}

		menu_imgs.push(new Hash({uri: _med_uri, base_uri: _base_uri, thumb_uri: _thumb_uri, med_uri: _med_uri,
			large_uri: _large_uri, ext: _ext, alt: _alt, width: _thumb_width, height: _thumb_height,
			info: _info}));
		total_img_and_margin_width += _thumb_width;
	};

	//removes every item with uri == _uri, if you added more than one, this is what will go down
	this.remove_image = function(_uri)
	{
		//TODO: remove observation
		menu_imgs.reject(function(n)
					{
						if(n.get('uri') == _uri)
						{
							total_img_and_margin_width -= n.get('width') + between_images;
							return true;
						}
						else
							return false;
					});
//		show_items_from_index.call(this, 0);
		show_partition.call(this, 0);
	};

	//control: either 'prev-control' or 'next-control'
	this.enable_control = function(control)
	{
		var which = control.substring(7 + id_prefix.length);
		var vert_str = vertical ? 'vert-' : '';
//		if(!control_enabled.get(which))
//		{
			//make sure it stays hidden
			if(!control_hidden.get(which))
			{
				$(control).setStyle({backgroundImage: "url('" + img_base_dir + '/product-menu-' + vert_str
					+ control.substring(id_prefix.length) + ".png')"});
				$(control).removeClassName('disabled');
			}

			control_enabled.set(which, true);
//		}
	};

	//control: either 'prev-control' or 'next-control'
	this.disable_control = function(control)
	{
		var which = control.substring(7 + id_prefix.length);
		var vert_str = vertical ? 'vert-' : '';
//		if(control_enabled.get(which))
//		{
			//make sure it stays hidden
			if(!control_hidden.get(which))
			{
				$(control).setStyle({backgroundImage: "url('" + img_base_dir + '/product-menu-' + vert_str
					+ control.substring(id_prefix.length) + "-disabled.png')"});
				$(control).addClassName('disabled');
			}

			control_enabled.set(which, false);
//		}
	};

	//pass true for whichever control should be disabled, if both are disabled they will be hidden
	this.disable_controls = function(disable_prev, disable_next)
	{
		//if they are to be both disabled, hide them.
		if(disable_prev && disable_next)
		{
			this.hide_control(id_prefix + 'scroll-prev');
			this.hide_control(id_prefix + 'scroll-next');
			var scroller_bkgnd = $(id_prefix + 'scroller-background');
			if(scroller_bkgnd != null)
				scroller_bkgnd.hide();
		}
		else
		{
			if(scroller_bkgnd != null)
				scroller_bkgnd.show();
			if(disable_prev)
				this.disable_control(id_prefix + 'scroll-prev');
			else
				this.enable_control(id_prefix + 'scroll-prev');
			if(disable_next)
				this.disable_control(id_prefix + 'scroll-next');
			else
				this.enable_control(id_prefix + 'scroll-next');
		}
	};

	this.display_control = function(control)
	{
		if(!control_hidden.get(which))
			return;

		var which = control.substring(id_prefix.length, 4);

		var observe_func = null;
		if(which == 'prev')
			observe_func = click_prev_bound = click_prev.bindAsEventListener(this);
		else
			observe_func = click_next_bound = click_next.bindAsEventListener(this);

		$(control).observe('click', observe_func);

		var disabled_str = control_enabled.get(which) ? '' : '-disabled';
		var vert_str = vertical ? 'vert-' : '';
		$(control).setStyle({backgroundImage: "url('" + img_base_dir + '/product-menu-' + vert_str
			+ control.substring(id_prefix.length) + disabled_str + ".png')"});
		$(control).removeClassName('disabled');
		control_hidden.set(which, false);
	};

	this.hide_control = function(control)
	{
		if(control_hidden.get(which))
			return;

		$(control).setStyle({backgroundImage: 'none'});
		$(control).addClassName('disabled');
		var which = control.substring(id_prefix.length, 4); 
		$(control).stopObserving('click', which == 'prev' ? click_prev_bound : click_next_bound);

		control_hidden.set(which, true);
	};
}

function jacImageMenuItem(thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt)
{
	this._thumb_uri = thumb_uri;
	this._thumb_width = thumb_width;
	this._thumb_height = thumb_height;
	this._medium_uri = medium_uri;
	this._large_uri = large_uri;
	this._alt = alt == null ? '' : alt;

	this._custom_pre_click = arguments.length >= 7 ? arguments[6] : null;
	this._custom_post_click = arguments.length >= 8 ? arguments[7] : null;
//	alert('Pre click: ' + this._custom_pre_click + ' Post click: ' + this._custom_post_click);
}
jacImageMenuItem.prototype = new Object();
jacImageMenuItem.prototype.constructor = jacImageMenuItem;
jacImageMenuItem.prototype._thumb_uri;
jacImageMenuItem.prototype._thumb_width;
jacImageMenuItem.prototype._thumb_height;
jacImageMenuItem.prototype._medium_uri;
jacImageMenuItem.prototype._large_uri;
jacImageMenuItem.prototype._alt;
jacImageMenuItem.prototype._custom_pre_click;
jacImageMenuItem.prototype._custom_post_click;

jacImageMenuItem.img_base_dir = '/res/images';

jacImageMenuItem.prototype.get_thumb_size =
	function()
	{
		return [this._thumb_width, this._thumb_height];
	};
jacImageMenuItem.prototype.get_alt =
	function()
	{
		return this._alt;
	};

jacImageMenuItem.prototype.get_thumb_uri =
	function()
	{
		return this._thumb_uri;
	};
jacImageMenuItem.prototype.get_medium_uri =
	function()
	{
		return this._medium_uri;
	};
jacImageMenuItem.prototype.get_large_uri =
	function()
	{
		return this._large_uri;
	};

jacImageMenuItem.prototype.get_alt =
	function()
	{
		return this._alt;
	};
jacImageMenuItem.prototype.set_alt =
	function(new_alt)
	{
		this._alt = new_alt;
	};

jacImageMenuItem.prototype.item_click =
	function()
	{
		if(this._custom_pre_click != null)
			this._custom_pre_click.call(this);
		
		if(this._custom_post_click != null)
			this._custom_post_click.call(this);
	};

jacImageMenuItem.prototype.get_menu_xhtml =
	function(id)
	{
		return '<img id="' + id + '" class="menu-image" src="' + this._thumb_uri + '" alt="' + this._alt
			+ '" style="width: ' + this._thumb_width + 'px; height: ' + this._thumb_height + 'px;" />';
	};

function jacImageMenuItemJS(thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt, click_func)
{
	jacImageMenuItem.call(this, thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt);

	this._click_func = click_func;
}
jacImageMenuItemJS.prototype = new jacImageMenuItem;
jacImageMenuItemJS.prototype._click_func;

jacImageMenuItemJS.prototype.item_click =
	function()
	{
		if(this._custom_pre_click != null)
			this._custom_pre_click.call(this);
	
		if(this._click_func != null)
			this._click_func.call(this);

		if(this._custom_post_click != null)
			this._custom_post_click.call(this);
	};

function jacImageMenuItemImgInfo(thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt, info, lb_title)
{
	jacImageMenuItem.call(this, thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt,
		arguments.length >= 9 ? arguments[8] : null, arguments.length >= 10 ? arguments[9] : null);
	this._info = info == null ? '' : info;
	this._lb_title = lb_title == null ? '' : lb_title;
}
jacImageMenuItemImgInfo.prototype = new jacImageMenuItem;
jacImageMenuItemImgInfo.prototype._info;
jacImageMenuItemImgInfo.prototype._lb_title;

jacImageMenuItemImgInfo.prototype.get_info =
	function()
	{
		return this._info;
	};
jacImageMenuItemImgInfo.prototype.set_info =
	function(new_info)
	{
		this._info = new_info;
	};
jacImageMenuItemImgInfo.prototype.get_lb_title =
	function()
	{
		return this._lb_title;
	};
jacImageMenuItemImgInfo.prototype.set_lb_title =
	function(new_lb_title)
	{
		this._lb_title = new_lb_title;
	};

jacImageMenuItemImgInfo.prototype.item_click =
	function()
	{
		if(this._custom_pre_click != null)
			this._custom_pre_click.call(this);

		var info_elem = $(jacImageMenuItemImgInfo.info_elem_id);
		if(info_elem != null)
			info_elem.update(this._info);

		var img_elem = $(jacImageMenuItemImgInfo.img_elem_id);
		if(img_elem != null)
		{
			var img_wrapper_elem = $(jacImageMenuItemImgInfo.img_wrapper_elem_id);
			var bkgnd_switch = false;
			if(img_wrapper_elem != null && jacImageMenuItemImgInfo.show_progress)
			{
				var wrapper_size = img_wrapper_elem.getDimensions();
				img_elem.hide();
				img_wrapper_elem.setStyle({background: 'white 50% 50% url("' + jacImageMenuItem.img_base_dir
					+ '/progress-indicator.gif") no-repeat', width: wrapper_size.width + 'px',
					height: wrapper_size.height + 'px'});
				bkgnd_switch = true;
			}

			//hide the image, swap it out, showing the progress if that is set
			img_elem.hide();

			var that = this;
			var custom_post_click = this._custom_post_click;
			function img_elem_load(e)
			{
				if(custom_post_click != null)
					custom_post_click.call(that);
				img_elem.show();
				if(bkgnd_switch)
					img_wrapper_elem.setStyle({backgroundImage: 'none', width: wrapper_size.width + 'px',
						height: 'auto'});
				img_elem.stopObserving('load', img_elem_load);
			}

			img_elem.observe('load', img_elem_load);
//			img_elem.src = this._medium_uri;
			img_elem.writeAttribute({alt: this._alt, src: this._medium_uri});
		}

		var img_link_elem = $(jacImageMenuItemImgInfo.img_link_elem_id);
		if(img_link_elem != null)
		{
			img_link_elem.writeAttribute({href: this._large_uri, title: this._lb_title});
		}
		
		var more_info_link_elem = $(jacImageMenuItemImgInfo.more_info_link_elem_id);
		if(more_info_link_elem != null)
		{
			more_info_link_elem.writeAttribute({href: this._large_uri, title: this._lb_title});
		}

//		if(this._custom_post_click != null)
//			this._custom_post_click();
	};

jacImageMenuItemImgInfo.show_progress = true;
jacImageMenuItemImgInfo.info_elem_id = null;
jacImageMenuItemImgInfo.img_elem_id = null;
jacImageMenuItemImgInfo.img_link_elem_id = null;
jacImageMenuItemImgInfo.img_wrapper_elem_id = null;
jacImageMenuItemImgInfo.more_info_link_elem_id = null;

/**
 * 
 * @param thumb_uri
 * @param thumb_width
 * @param thumb_height
 * @param medium_uri
 * @param large_uri
 * @param alt - ESCAPED of html entities please
 * @param caption - ESCAPED of html entities please
 * @return new object
 */
function jacImageMenuItemLightbox(thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt, caption)
{
	jacImageMenuItem.call(this, thumb_uri, thumb_width, thumb_height, medium_uri, large_uri, alt);
	this._caption = caption;
}
jacImageMenuItemLightbox.prototype = new jacImageMenuItem;
jacImageMenuItemLightbox.prototype._caption;

//"virtual" function overrides
jacImageMenuItemLightbox.prototype.get_menu_xhtml =
	function(id)
	{
		return '<a href="' + this._large_uri + '" rel="lightbox" title="' + this._caption + '">'
			+ jacImageMenuItem.prototype.get_menu_xhtml.call(this, id)
			+ '</a>';
	};
jacImageMenuItemLightbox.prototype.item_click =
	function()
	{
		if(this._custom_pre_click != null)
			this._custom_pre_click.call(this);

		if(this._custom_post_click != null)
			this._custom_post_click.call(this);
	};

