/* === TIGER MESSAGE MODULE === */

/** 
 * @method message
 * @description (See below)
 * @author K. Beau Beauchamp
 * @public
 * @static
 * @param {str} the message string
 * @param {str || elm} accepts an input element or string reference
 * @param {str} (optional) a constant class used to determine the type
 * of message and to apply or remove from the form element, default: ALERT
 * @return nothing
 */

TIGER.message = {

	/* Description:
	 * The message() method handles the setting and clearing of form messages 
	 * within our forms and pages. This method can be used as either a static 
	 * method or as a callback for another method, such as our validator(). Note
	 * also in TIGER, clicking on a message will dismiss the message from the
	 * page.
	 * 
	 * Header Messages: HEAD (default)
	 * Page messages generally appear at the top of a page or containter as 
	 * colored message bars. To use MSG_HEAD, simply pass in the sMessage, a 
	 * container elm and a sElmClass of MSG_HEAD. 
	 * Example: TIGER.message(sMessages,eContainer,'MSG_HEAD');
	 * 
	 * Alert Messages: ALERT
	 * As much as we despise alerts, they are sometimes useful for communicating
	 * information. TIGER provides a simple alert popup that is formatted using
	 * the Web 2.0 style that is inherent within the applicaton. Simply pass in a
	 * sMessage and TIGER will display an alert popup. If you would like an alert
	 * formatted with HTML styled message, pass in an HTML element root with your
	 * message and the sClass MSG_ALERT.
	 * 
	 * Forms: FORM
	 * TIGER supports inline form messages. The sMessage var essentially
	 * becomes our valid (false or null) or invalid (true or string) flag. If 
	 * a message is sent into the method, then we trigger the element's message 
	 * handling features, apply the default or sClass, or make other form 
	 * settings, like enabling or disabling the submit button.
	 * 
	 * Forms Configuration:
	 * Within the TIGER form pages, we ubiquitously use the following form field
	 * setup:
	 * 
	 * <div><label></label><input /> ... <span></span></div>
	 * 
	 * The INPUT element becomes our anchor element, so to speak, to affect changes
	 * of text and classes in the sibling and even parent elements. The lastChild
	 * <span> element is where our form messages go. */

	show : function(oMessage)
	{

		/* Message Object:
		 * {
		 * 		message		: {string},
		 * 		sourceElm	: {el || string} (usually null except for form messages),
		 * 		targetElm	: {el || string} (defaults to system_messages),
		 * 		sclass		: {string} (optional, defaults to 'alert')
		 * }
		 */
		
		if (typeof(oMessage) !== 'object')
		{
			oMessage = {
				 message	: oMessage,
				 sourceElm	: null,		// used for form messages
				 targetElm	: 'system_messages',
				 sclass		: 'alert'
			};
		}
	
		/* Moving out of the switch, we want all string element references to be 
		 * converted to actual element references. */
		switch(oMessage.targetElm){
			case 'form':
				if(!TIGER.util.isNull(oMessage.message))
				{
					oMessage.targetElm = Dom.getLastChild(oMessage.sourceElm.parentNode);
					TIGER.message.form(oMessage);
				}
				break;
			
			case 'system_messages':
			default:
				if(!TIGER.util.isNull(oMessage.message))
				{
					oMessage.targetElm = Dom.get(oMessage.targetElm);
					TIGER.message.head(oMessage);
				}
				break;
		}

	},

	/* TIGER.message.containers is an array that hold our animation objects and
	 * helps us keep track of animations that have already been assigned to 
	 * page elements. It keeps our page more efficient. */
	containers : [],

	head : function(oMessage)
	{
		/* Description:
		 * TIGER.message.head is the default message display helper. It displays
		 * one or more delimited messages as list items within an unordered list
		 * parent element. 
		 * 
		 * sClass:
		 * Message types are defined by their respective CSS class: info, success, 
		 * alert and error. */
		
		/* Message Object:
		 * {
		 * 		message		: {string},
		 * 		sourceElm	: {el || string} (usually null except for form messages),
		 * 		targetElm	: {el || string} (defaults to system_messages),
		 * 		sclass		: {string} (optional, defaults to 'alert')
		 * }
		 */

		TIGER.message.element(oMessage);

	},


	/** 
	 * @method message.form
	 * @description (See below)
	 * @author K. Beau Beauchamp
	 * @public
	 * @static
	 * @param {str} the message string
	 * @param {str || elm} accepts an input element or string reference
	 * @return nothing
	 */
	
	form : function(oMessage)
	{
	
		/* Description:
		 * Originally, this function was intended to be used strictly with inline
		 * forms messages. However, it's pretty useful also for displaying all kinds
		 * of messages. */

		/* Message Object:
		 * {
		 * 		message		: {string || false},
		 * 		sourceElm	: {el || string} (usually null except for form messages),
		 * 		targetElm	: {el || string} (defaults to system_messages),
		 * 		sclass		: {string} (optional, defaults to 'alert')
		 * }
		 */

		/* Store these for now so our changeMessage function has refrences. */
		TIGER.message.form.message 	= oMessage.message;
		TIGER.message.form.element 	= oMessage.sourceElm;
		TIGER.message.form.target 	= oMessage.targetElm;

		// the target el for a message should always be a span element. if the target is not a span element
		// the next bit of code searches up the dom tree to locate the first available span within the div.form-element
		// container. you can comment out this code if you don't need it.
		
		// first check to see if we're dealing with an inline-element'
		if(Dom.getAncestorByClassName(oMessage.sourceElm, 'inline-element')){

			TIGER.message.form.target = (oMessage.targetElm.nodeName.toString().toLowerCase() !== 'span')
			? Dom.getElementBy(function(el){return (true);},'span', Dom.getAncestorByClassName(oMessage.sourceElm, 'inline-element'))
			: oMessage.targetElm;

		} else {

			TIGER.message.form.target = (oMessage.targetElm.nodeName.toString().toLowerCase() !== 'span')
			? Dom.getElementBy(function(el){return (true);},'span', Dom.getAncestorByClassName(oMessage.sourceElm, 'form-element'))
			: oMessage.targetElm;

		}


		/* Setup two YUI animations that target the span container holding the 
		 * message text. The message containter is the last child span of the 
		 * div containing the input element. */
		var elm = TIGER.message.form.element;
		var eTarget = TIGER.message.form.target;
		
		if (!TIGER.message.containers[elm.id]){
	
			TIGER.message.containers[elm.id] = [];
	
			TIGER.message.containers[elm.id].FadeOut = new Anim( eTarget );
			TIGER.message.containers[elm.id].FadeOut.duration = 0.3;
			TIGER.message.containers[elm.id].FadeOut.attributes.opacity = {to: 0};
		
			TIGER.message.containers[elm.id].FadeIn = new Anim( eTarget );
			TIGER.message.containers[elm.id].FadeIn.duration = 0.3;
			TIGER.message.containers[elm.id].FadeIn.attributes.opacity = {to: 1};
	
			TIGER.message.containers[elm.id].ColorIn = new ColorAnim(elm);
			TIGER.message.containers[elm.id].ColorIn.duration = 0.3;
			TIGER.message.containers[elm.id].ColorIn.attributes.backgroundColor = {to: '#fdf2ba'};
	
			TIGER.message.containers[elm.id].ColorOut = new ColorAnim(elm);
			TIGER.message.containers[elm.id].ColorOut.duration = 0.3;
			TIGER.message.containers[elm.id].ColorOut.attributes.backgroundColor = {to: '#ffffff'};
	
		}
	
		/* Automatically slam the target to 0 opacity if it's empty */
		if (eTarget.innerHTML === ''){Dom.setStyle(eTarget,'opacity',0);}
	
		/* This is a function we can call to set the target's message. It just tidy's
		 * up our code a bit ... */
		var changeMessage = function()
		{
			var vMessage 	= TIGER.message.form.message;
			var elm 		= TIGER.message.form.element;
			var eTarget 	= TIGER.message.form.target;

			/* Clear the target's current contents. */
			eTarget.innerHTML = '';
			
			/* Okay, here's the deal, an element will usually return an array of
			 * booleans (false = passed test) and strings (message = failed test) and 
			 * we don't want to display all of the messages in the limited amount of space 
			 * on the form's message span. We need to find just the first string and display
			 * it, otherwise, we can just display the vMessage. */
			if (TIGER.util.isArray(vMessage))
			{
				for(i in vMessage)
				{
					// get rid of any false array elements
					if (!vMessage[i]){vMessage.splice(i,1);}
				}
				vMessage = (vMessage.length > 0) ? vMessage[0] : false;
			}
			
			/* If the sMessage came back false, don't do anything more because
			 * we've cleared the error condition that generated the message in
			 * the first place. */
			if(vMessage)
			{
				
				/* Sometimes the vMessage can be an object that we want to stuff
				 * into the target element. */
				if (typeof(vMessage).toString().toLowerCase() === 'string')
				{
				
					/* Populate the target. */
					var img = TIGER.html.createElement(
						'img', 
						{
							'id':'',
							'src': TIGER.imagepath + 'error.png'
						}, 
						eTarget,
						'child'
					);
					
					vMessage = document.createTextNode(vMessage);
	
				}
	
				eTarget.appendChild(vMessage);
		
				TIGER.message.containers[elm.id].FadeIn.animate();
				TIGER.message.containers[elm.id].ColorIn.animate();
			}
		};
	
		/* Fade the target's opacity to 0 and then change the message. */
		TIGER.message.containers[elm.id].FadeOut.onComplete.subscribe( changeMessage );
		TIGER.message.containers[elm.id].FadeOut.animate();
		TIGER.message.containers[elm.id].ColorOut.animate();

	},


	/** 
	 * @method message.form
	 * @description (See below)
	 * @author K. Beau Beauchamp
	 * @public
	 * @static
	 * @param {str} the message string
	 * @param {str || elm} accepts an input element or string reference
	 * @return nothing
	 */
	
	element : function(oMessage)
	{
	
		/* Description:
		 * Originally, this function was intended to be used strictly with inline
		 * forms messages. However, it's pretty useful also for displaying all kinds
		 * of messages. 
		 * 
		 * For now, the only elment that should be used for messages is stuffing an
		 * li into an ol element. */

		/* Message Object:
		 * {
		 * 		message		: {string || false},
		 * 		sourceElm	: {el || string} (usually null except for form messages),
		 * 		targetElm	: {el || string} (defaults to system_messages),
		 * 		sclass		: {string} (optional, defaults to 'alert')
		 * }
		 */

		/* Store the message object for now so our changeMessage function has a refrence. */
		TIGER.message.element.oMessage = oMessage;
		
		/* Update the animation container memory with the target element. */
		TIGER.message.setContainers(oMessage.targetElm);

		/* A function to build our li messages. */
		var buildMessage = function()
		{
			var oMessage = TIGER.message.element.oMessage;
			oMessage.targetElm = Dom.get(oMessage.targetElm);
	
			if(oMessage.message)
			{
				
				/* If the message is not already an object we need to create a
				 * li node to stuff into the ul target element. */
				if (typeof(oMessage.message) === 'string')
				{
				
					/* Populate the target. */
					var li = TIGER.html.createElement(
						'li', 
						{
							'class' : oMessage.sclass + ' hide'
						}
					);
					var message = document.createTextNode(TIGER.i18n(oMessage.message));
					li.appendChild(message);
					Dom.generateId(li,oMessage.targetElm.id);
					oMessage.message = li;
				}
				
			}
		};

		var addMessage = function()
		{
			/* Note that the message at this point is always an li element and the 
			 * targetElm is always a ul element with the class "messages". */
			
			// Prep Element for animations
			oMessage.targetElm.appendChild(oMessage.message);
			TIGER.message.setContainers(oMessage.message);
			Event.addListener(oMessage.message, 'click', function(){TIGER.message.removeMessage(this);} );

			oMessage.height = oMessage.message.offsetHeight;
			Dom.setStyle(oMessage.message, 'opacity', 0);
			Dom.removeClass(oMessage.message, 'hide');
		};
		
		var fadeInMessage = function()
		{
			var oMessage = TIGER.message.element.oMessage;
			TIGER.message.containers[oMessage.message.id].FadeIn.animate();
		};

		buildMessage();
		addMessage();

		// Expand
		TIGER.message.containers[oMessage.targetElm.id].Height.onComplete.subscribe( fadeInMessage );
		TIGER.message.containers[oMessage.targetElm.id].Height.attributes.height = {by: oMessage.height};
		TIGER.message.containers[oMessage.targetElm.id].Height.animate();
		
	},

	removeMessage : function(elm)
	{
		
		function deleteElement(elm)
		{
			var height = elm.parentNode.offsetHeight - elm.offsetHeight;
			var parent = elm.parentNode;
			
			elm.parentNode.removeChild(elm);

			TIGER.message.containers[parent.id].Height.attributes.height = {to: height};
			TIGER.message.containers[parent.id].Height.animate();

		}
		
		TIGER.message.containers[elm.id].FadeOut.onComplete.subscribe( function(){deleteElement(elm);} );
		TIGER.message.containers[elm.id].FadeOut.animate();
	},
	
	init : function()
	{
		if (Dom.getChildren(Dom.get('system_messages')).length == 0) {Dom.get('system_messages').style.height = 0;}
	},

	setContainers : function(targetElm)
	{

		if (!TIGER.message.containers[targetElm.id]){
			
			TIGER.message.containers[targetElm.id] = [];

			TIGER.message.containers[targetElm.id].Height = new Anim( targetElm );
			TIGER.message.containers[targetElm.id].Height.duration = 0.3;
		
			TIGER.message.containers[targetElm.id].FadeOut = new Anim( targetElm );
			TIGER.message.containers[targetElm.id].FadeOut.duration = 0.3;
			TIGER.message.containers[targetElm.id].FadeOut.attributes.opacity = {to: 0};
		
			TIGER.message.containers[targetElm.id].FadeIn = new Anim( targetElm );
			TIGER.message.containers[targetElm.id].FadeIn.duration = 0.3;
			TIGER.message.containers[targetElm.id].FadeIn.attributes.opacity = {to: 1};

		}

	}
	
};

