/* Create a name space for all Artline specific JavaScript functions. */

var ARTLINE = {
	mouse : {},
	event : {},
	dom : {},
	menu : {},
	category : {},
	item : {},
	searchForm : {
		placeholderText : "Enter style, theme, or card #"
	},
	orderForm : {}
};

/*** Category - Overlay *******************************************************/

ARTLINE.category.bindOverlay = function(selector, id)
{
	STORE.yui.load(["container", "animation", "connection", "selector"],
			function()
	{
		var overlay = {
			
			/**
			 * Source. Image element for which the overlay is currently
			 * displaying.
			 */ 
			_source : null,
			
			/**
			 * YUI overlay widget.
			 */
			_overlay : new YAHOO.widget.Overlay(id,
					{
						constrainToViewport : true,
						effect : {
							"effect" : YAHOO.widget.ContainerEffect.FADE,
							"duration" : 0.2
						}
					}),
			
			/**
			 * Text displayed if an error occurs when trying to retrieve the
			 * card details.
			 */
			FAILURE_TEXT : "No details available.",
			
			/**
			 * Offset the overlay from the cursor position.
			 */
			OFFSET : { X : 15, Y : 15 },
			
			/**
			 * Content cache index by URL.
			 */
			_cache : {},
			
			/**
			 * Event handler for a mouseover event. Displays the overlay for the
			 * event's target element.
			 */
			over : function (event)
			{
				// Determine the source. IE8 and under use srcElement. Perform
				// all operations on the local variable to avoid race
				// conditions. 
				
				var source  = event.target || event.srcElement;
				
				this._source = source;
				
				// Determine the URL.
				
				var url = source.getAttribute("artline-overlay-url");
				
				var coordinates = this._coordinates(event);
				
				// Check to see if we've already retrieved this item's content.
				// If so, we can bypass the HTTP request and just pull the
				// content out of the cache.
				
				if (this._cache[url])
				{
					var content = this._cache[url];
					
					this._show(coordinates, content);
					
					return;
				}
				
				// Encapsulate the relevant event information in a context
				// object.
				
				var context = this._createContext(source, url, coordinates);
				
				this._fetch(context);
			},
			
			/**
			 * Context object used to store state for the duration of a fetch
			 * and render cycle.
			 * 
			 * @param string source Source element
			 * @param string url URL from which to retrieve the content.
			 * @param object coordinates Hash table with x and y keys
			 *                           corresponding to the mouse
			 *                           coordinates. 
			 */
			_createContext : function(source, url, coordinates)
			{
				return {
					source : source,
					url : url,
					coordinates : coordinates,
					content : ""
				}
			},
			
			/**
			 * Helper method for retrieving the mouse coordinates from a mouse
			 * event.
			 */
			_coordinates : function(event)
			{
				// Use YUI to determine the mouse coordinates. Most browsers
				// expose the coordinates as pageX and pageY. In IE8 and under,
				// it takes some math. Note that the getXY method returns an
				// array in the form [x, y].
				
				var xy = YAHOO.util.Event.getXY(event);
				
				return { x : xy[0], y : xy[1] };
			},
			
			/**
			 * Fetches the overlay content from the server and renders the
			 * overlay when the content has been retrieved. Content is fetch
			 * asynchronously and cached for the duration of the page's
			 * lifetime.
			 */
			_fetch : function(context)
			{
				var self = this;
				
				YAHOO.util.Connect.asyncRequest(
					"GET",
					context.url,
					{
						success : function(response)
						{
							context.content = response.responseText;
							self._callback(context);
						},
						failure : function(response)
						{
							context.content = self.FAILURE_TEXT;
							self._callback(context);
						}
					}
				);
			},
			
			/**
			 * Fetch async callback handler. Caches the results by URL.
			 * Positions and renders the overlay.
			 */
			_callback : function(context)
			{
				// First, cache the result so that we don't have to fetch it
				// twice in a single page's lifetime.
				
				this._cache[context.url] = context.content;
				
				// Check to make sure the source didn't change. The user may
				// have moved their mouse over a different thumbnail.
				
				if (context.source !== this._source)
				{
					return;
				}
				
				// The focus hasn't changed. Position and render the overlay.
				
				this._show(context.coordinates, context.content);
			},
			
			/**
			 * Helper method for displaying an overlay. Renders the overlay with
			 * the specified content based on the supplied coordinates.
			 */
			_show : function(coordinates, content)
			{
				// NOTE: Render prior to positioning. This ensures that the
				//       overlay will not be positioned off screen.
				
				this._render(content);
				
				this._position(coordinates);
			},
			
			/**
			 * Positions the overlay using the given mouse coordinates. 
			 */
			_position : function(coordinates)
			{
				// Move the overlay by the given amount
				
				var left = coordinates.x + this.OFFSET.X;
				var top = coordinates.y + this.OFFSET.Y;
				
				this._overlay.cfg.setProperty("xy", [left, top]);
			},
			
			/**
			 * This method is called when the XMLHTTPRequest returns from its
			 * round-trip with the server. Updates the overlay's content and
			 * shows it.
			 */
			_render : function(content)
			{
				this._overlay.body.innerHTML = content;
				
				this._overlay.render();
				
				this._overlay.show();
			},
			
			/**
			 * This method hides the current card hover element.
			 */
			_hide : function()
			{
				this._source = null;
				this._overlay.hide();
			},
			
			/**
			 * Handles the mousemove event. Checks to see if the overlay needs
			 * to be hidden (because the user's mouse is no longer hovered over
			 * the source image).
			 */
			check : function(event)
			{
				// Check to see if an overlay is currently being displayed.
				
				if (this._source == null)
				{
					return;
				}
				
				// Check to see if the cursor appears within the region of the
				// source image.
				
				var coordinates = this._coordinates(event);
				
				var region = YAHOO.util.Region.getRegion(this._source);
				var point = new YAHOO.util.Point(coordinates.x, coordinates.y);
				
				if (region.contains(point))
				{
					return;
				}
				
				this._hide();
			}
		};
		
		var S = YAHOO.util.Selector,
			E = YAHOO.util.Event;
		
		var elements = S.query(selector);
		
		E.addListener(elements, "mouseover", function(e) { overlay.over(e); });
		
		E.addListener(document, "mousemove", function(e) { overlay.check(e); });
	});
};

ARTLINE.item.swapImage = function(url)
{
	var image = document.getElementById("cardImage");
	image.src = url;
};

ARTLINE.searchForm.handleSubmit = function(form)
{
	// Normalize the keyword field. By default, it will have some help text in
	// it.
	
	if (form.keywords.value == ARTLINE.searchForm.placeholderText)
	{
		form.keywords.value = "";
	}
	
	// If the keyword field is empty, give the user a warning rather than trying
	// to run a search.
	
	if (form.keywords.value == "")
	{
		alert("Please provide a keyword, style or card number.");
		
		return false;
	}
	
	// Log the keywords to the IndexTools stats script.
	
	if (typeof(captureClickout) != "undefined")
	{
		try
		{
			captureClickout("05", form.keywords.value);
		}
		catch(e)
		{
			// Do nothing.
		}
	}
	
	return true;
};

ARTLINE.searchForm.handleClick = function(formName)
{
	var form = document.getElementById(formName);
	
	if (ARTLINE.searchForm.handleSubmit(form))
	{
		form.submit();
	}
};

ARTLINE.searchForm.handleKeywordFocus = function(field)
{
	// Hide the help text when the user selects the field.
	
	if (field.value == ARTLINE.searchForm.placeholderText)
	{
		field.value = "";
		
		field.className = "";
	}
};

ARTLINE.searchForm.handleKeywordBlur = function(field)
{
	// If the user has moved away from the field and it is empty, re-insert the
	// help text.
	
	if (field.value == "")
	{
		field.value = ARTLINE.searchForm.placeholderText;
		
		field.className = "hint";
	}
};

/*** Order Form ***************************************************************/

ARTLINE.orderForm.panels = {};

ARTLINE.orderForm.updateSwatch = function(name)
{
	var select = document.getElementById(name + "Select");
	
	// NOTE: In what circumstances does this return undefined/null?
	
	if (!select)
	{
		return;
	}
	
	var swatch = document.getElementById(name + "Swatch");
	var color = select.options[select.selectedIndex].value;
	
	try
	{
		swatch.style.backgroundColor = "#" + color;
	}
	catch (ex)
	{
		// FIXME: In what circumstances will this throw an error?
	}
	
	var colorName = document.getElementById(name + "Name");
	
	colorName.value = select.options[select.selectedIndex].text;
};

ARTLINE.orderForm.getForm = function()
{
	return document.forms.orderForm;
};

ARTLINE.orderForm.getIsCustomVerse = function()
{
	var form = ARTLINE.orderForm.getForm();
	
	return form.isCustomVerse;
};

ARTLINE.orderForm.getIsCustomVerseOption = function(value)
{
	var input = ARTLINE.orderForm.getIsCustomVerse();
	
	// NOTE: We have to check for the existence of the radio button because
	//       it will not exist if the card does not have a verse option set.
	
	if (input)
	{
		for (var i = 0; i < input.length; i++)
		{
			var option = input[i];
			
			if (option.value == value)
			{
				return option;
			}
		}
	}
	
	return null;
};

ARTLINE.orderForm.getVerseSelect = function()
{
	return document.getElementById("versesSelect");
};

ARTLINE.orderForm.getCustomVerse = function()
{
	return document.getElementById("customVerse");
};

ARTLINE.orderForm.setIsCustomVerse = function(isCustomVerse)
{
	var verseSelectInput;
	var customVerseInput;
	var customVerseOption;
	var notCustomVerseOption;
	var enabledInput;
	var disabledInput;
	var checkedRadio;
	var uncheckedRadio;
	
	// Fetch the form elements that we'll be toggling.
	
	verseSelectInput = ARTLINE.orderForm.getVerseSelect();
	customVerseInput = ARTLINE.orderForm.getCustomVerse();
	customVerseOption = ARTLINE.orderForm.getIsCustomVerseOption(1);
	notCustomVerseOption = ARTLINE.orderForm.getIsCustomVerseOption(0);
	
	// Determine which elements get toggled in which direction.
	
	if (isCustomVerse)
	{
		enabledInput = customVerseInput;
		disabledInput = verseSelectInput;
		checkedRadio = customVerseOption;
		uncheckedRadio = notCustomVerseOption;
	}
	else
	{
		enabledInput = verseSelectInput;
		disabledInput = customVerseInput;		
		checkedRadio = notCustomVerseOption;
		uncheckedRadio = customVerseOption;
	}
	
	// Change the style of the disabled element. We're doing this instead of
	// actually disabling the element because the visual effect of disabling an
	// element is harsh.
	
	// NOTE: We have to check for the existence of the inputs before enabling
	//       and disabling them because the verse select input will not be
	//       available if there are no verses.
	
	// FIXME: We should refactor class manipulation into separate methods.
	
	if (enabledInput)
	{
		enabledInput.className = enabledInput.className.replace(" disabled", "");
	}
	
	if (disabledInput)
	{
		if (disabledInput.className.indexOf(" disabled") == -1)
		{
			disabledInput.className += " disabled";
		}
	}
	
	// NOTE: The checkbox itself will not exist if the card does not even have
	//       a verse option set.
	
	if (checkedRadio)
	{
		checkedRadio.checked = true;
	}
};

ARTLINE.orderForm.selectPanelOption = function(panelName, selectName,
		selectIndex)
{
	
	var selectElement = document.getElementById(selectName);
	
	selectElement.selectedIndex = selectIndex;
	
	if (name == "verses")
	{
		ARTLINE.orderForm.setIsCustomVerse(false);
	}
	
	if (selectElement.onchange)
	{
		selectElement.onchange();
	}
		
	ARTLINE.orderForm.panels[panelName].hide();
};


ARTLINE.orderForm.panelCallBack = function(response)
{
	if (response.status != 0)
	{	
		var id = response.argument.id;
		
		var panelBody = document.getElementById(id);
		
		panelBody.innerHTML = response.responseText;
		
	}
};

ARTLINE.orderForm.registerPanel = function(name, fetchBody, printable,
		clickable, url)
{
	STORE.yui.load(["store-panel"], function()
	{
		var linkName = name + "Link";
		
		var options = {
			"width" : "600px",
			"height" : "400px",
			"close" : true,
			"context" : ["orderForm", "tl", "tl"],
			"visible" : false,
			"fixedcenter" : true,
			"draggable" : false,
			"modal" : false,
			"constraintoviewport" : true,
			"effect" : {
				"effect" : YAHOO.widget.ContainerEffect.FADE,
				"duration" : 0.25
			}
		};
		
		var panel = new YAHOO.widget.Panel(name, options);
		
		if (printable == null)
		{
			printable = true;
		}
			
		if (clickable == null)
		{
			clickable = true;
		}
		
		ARTLINE.orderForm.panels[name] = panel;
		
		// NOTE: If the panels are not located directly under the body tag,
		//       errors may occur in IE when calling this during the onload or
		//       domready events. In which case, render should be called
		//       immediately before show().
		
		panel.render();
		
		var E = YAHOO.util.Event;
		
		var link = document.getElementById(linkName);
		
		if (fetchBody)
		{
			var bodyName = name + "Body";
			
			// NOTE: Adding a timestamp to prevent caching in IE.
			
			url = url + "&printable=" + printable + "&clickable=" + clickable +
					"&id=" + name;
			
			E.addListener(link, "click", function(e)
			{
				YAHOO.util.Connect.asyncRequest("GET", url,
					{
						"success" : ARTLINE.orderForm.panelCallBack,
						"failure" : ARTLINE.orderForm.panelCallBack,
						"argument": { "id" : bodyName }
					}
				);
			});
		}
		
		E.addListener(link, "click", function(e)
		{
			panel.show(panel, true);
			// The panel is hidden by default to avoid scroll bars in IE. We
			// want to wait until the panel has been positioned before
			// displaying it.
			document.getElementById(name).style.display = "block";
			e.cancelBubble = true;
		});
	});
};
		
/**
 * Helper method for printing the content of a panel.
 */
ARTLINE.orderForm.printPanel = function(id)
{
	var iframe = document.getElementById("printFrame");
	
	// From:
	//   
	//   http://xkr.us/articles/dom/iframe-document/
	//   
	// In short:
	//   
	//   contentWindow returns the window object in IE and Gecko.
	//   contentDocument returns the document in Safari.
	//   contentDocument returns the window in Opera.
	
	var iframeDoc = iframe.contentWindow || iframe.contentDocument;
	
	// We may have a window or document. We want a document.
	
	if (iframeDoc.document)
	{
		iframeDoc = iframeDoc.document;
	}
	
	iframeDoc.open();
	
	var panel = document.getElementById(id);
	
	iframeDoc.write(panel.innerHTML);
	
	// NOTE: window.print() does not work in the Safari 3 beta for Windows. For
	//       the moment, we're going to ignore it in the hopes that it will be
	//       fixed before the final release.
	
	// The window.focus() command is for IE.
	
	var printCommand = "setTimeout(\"window.focus(); window.print();\", 1000);";
	
	var script = "<s" + "cript type=\"text/javascript\">" + printCommand + "</s" + "cript>";
	
	iframeDoc.write(script);
	
	iframeDoc.close();
};
		

ARTLINE.orderForm.onTextFocus = function(text, defaultString)
{
	if (text.value == defaultString)
	{
		text.value = "";
		text.setAttribute("class", "text");
		text.setAttribute("className", "text");
	}
}

ARTLINE.orderForm.onTextBlur = function(text, defaultString)
{
	if (text.value == "")
	{
		text.value = defaultString;
		text.setAttribute("class", "text disabled");
		text.setAttribute("className", "text disabled");
	}
}

ARTLINE.orderForm.enableInputs = function(inputs, enabled)
{
	for (var i = 0; i < inputs.length; i++)
	{
		input = document.getElementById(inputs[i]);
		
		if (!input) return;
		
		if (enabled)
		{
			input.removeAttribute("disabled");
			
			if (input.getAttribute("class"))
			{
				input.setAttribute("class", input.getAttribute("class").replace(/disabled/g, ""));
				input.setAttribute("className", input.getAttribute("className").replace(/disabled/g, ""));
			}	
		}
		else
		{
			input.setAttribute("disabled", "disabled");
			
			if (input.getAttribute("class") || input.getAttribute("className"))
			{
				input.setAttribute("class", input.getAttribute("class") + " disabled");
				input.setAttribute("className", input.getAttribute("className") + " disabled");
			}
			else
			{
				input.setAttribute("class", "disabled");
				input.setAttribute("className", "disabled");
			}
		}
	}
}

