/**
 * Byng.ui.response
 *
 * Provides methods to read responses from the framework and use
 * standard UI widgets in the basecode
 * 
 * @copyright Byng Systems LLP
 * 
 * @author Ollie Maitland
 *
 */
Byng.register('byng.ui.response',
{
	/**
	 * Represents a request failed
	 * 
	 * @param Int
	 */
	REQ_FAILED : 0,
	
	/**
	 * Represents a request passed
	 * 
	 * @param Int
	 */
	REQ_PASSED : 1,
			
	/**
	 * Represents a prompt for information
	 */
	REQ_PROMPT : 2,
	
	/**
	 * Holds the internal DOM elements for the popup
	 * 
	 * @param DomElement
	 */
	internals : null,
	
	/**
	 * Holds the stack of listeners
	 * 
	 * @param Array
	 */
	listeners : [],
	
	/**
	 * Start the response handler
	 * 
	 * 
	 */
	initialize : function ()
	{
		// local access to the dom wrapper object
		
	},
	
	/**
	 * Build the prompt dialogue box
	 * 
	 * @param DomElement promptTree
	 */
	buildPrompt : function (promptTree) 
	{
		var xmlTag = new ByngXml ( promptTree );
		
		// get content from title and question tags
		var title = xmlTag.getChildContent ( "title" );
		var question = xmlTag.getChildContent ( "question" );	
		
		// clear internals if necessary
		if (this.internals == null && this.promptContainer != null) {
			this.promptContainer.empty();
		} 
		
		// new internals wrapper
		this.internals = new Element("div");
		
		// create cancel button
		var cancel = new Element("a", {'href' : 'javascript:Byng.ui.dom.cancelPopup();'});
			cancel.addClass("close");
		
		// add to the prompt tree
		this.internals.appendChild (cancel);
		
		// title element
		var h3 = new Element("h3", {'title' : title});
			h3.set('html',title);
		
		// add to the DOM
		this.internals.appendChild (h3);

		// question element
		var p = new Element("p");
			p.set('html',question);
			
		// add to the DOM
		this.internals.appendChild (p);

		// accept/cancel buttons
		var options = xmlTag.getChildTag("options");
		var optionList = options.getElementsByTagName("option");
		
		// create wrapping <div>
		var wrap = new Element("div");
		for (var i = 0, n = optionList.length; i < n; i++) {
			this.addOption (optionList[i], wrap);
		}
		
		// append the wrapper
		this.internals.appendChild (wrap);
		// append the internal wrapper
		this.promptContainer.appendChild (this.internals);			
		// display the popup
		this.promptContainer.setStyle('display',"block");
		
		// initialise the environ,ent
		this.promptInit ();
	},
	
	/**
	 * Add an option to the prompt
	 * 
	 */
	addOption : function (opt, wrap) 
	{
		var opt = new ByngXml ( opt );
		var icon = new Element("a");
		var value = opt.getAttribute ("value");
		var className = opt.getAttribute ("class");			
		var title = opt.getContent ();
		
		// set the button properties
		icon.href = "javascript:Byng.ui.response.callBack('" + value + "');";
		icon.className = className;
		icon.title  = title;
		wrap.appendChild (icon);
	},
	
	/**
	 * Handle callback from the pop-up
	 * 
	 */
	callBack : function ( value ) 
	{		
		if (value == true) {
			this.promptAccept();
		} else {
			this.promptCancel();
		}
	},
		
	/**
	 * Set the accept event
	 * 
	 */
	setPromptAccept : function (fn) 
	{
		this.promptAccept = fn;
	},
	
	/**
	 * Set the cancel pop-up event
	 * 
	 */
	setPromptCancel : function (fn) 
	{
		this.promptCancel = fn;
	},
	
	/**
	 * Set the poup-up container and init() action
	 * 
	 */
	setPromptContainer : function	(div, init) 
	{
		this.promptContainer = div;
		this.promptInit = init;
	},
	
	/**
	 * Set the listener
	 * 
	 * @param String handle
	 * @return Object
	 */
	setListener : function (handle, fn) 
	{
		this.listeners[handle] = fn;	
	},
	
	/**
	 * Get a listener method
	 * 
	 * @param String handle
	 */
	getListener : function (handle) 
	{
		if (this.listeners[handle] == null) {
			return this.emptyListener(handle);
		} else {
			return this.listeners[handle];
		}
	},
		
	/**
	 * Empty listener handler
	 * 
	 * @param String h
	 */
	emptyListener : function (h) 
	{
		alert ("Requested non-existent listener ("+h+")");
	},
	
	/**
	 * Set the onAlert handling function
	 * 
	 * @param Function onAlert
	 */
	setOnAlert : function (onAlert, raiseFromDom)
	{
		Byng.app.addEvent('alert', onAlert);
		if (raiseFromDom) window.addEvent('domready', this.raiseAlertsFromDom.bind(this));
	},
	
	/**
	 * Raise the alerts from the DOM
	 * 
	 */
	raiseAlertsFromDom : function ()
	{
		[ELEM_FEEDBACK,ELEM_ERRORS].each(function(msgType) {
			$(msgType).getElements('li span').each(function(msg) {
				Byng.app.fireEvent('alert', [msg.get('text'), msgType]);
			}.bind(this));
		}.bind(this));
	},
	
	/**
	 * Read a response
	 * 
	 * @param DomElement xml
	 */
	read : function (xml, ajax)
	{
		try {
			var resp = new ByngXml(xml);
			var event = (resp.getCode() == true ? 'success' : 'error');
			
			// write messages
			Byng.ui.response.writeMessages(resp);
						
			// run any post condition events
			if (typeOf(ajax) == 'object') {
				ajax.fireEvent( event, [resp, ajax]);
			}
			
			// condition: code response indicated a prompt answer is required
			if (resp.getCode() == Byng.ui.response.REQ_PROMPT) {
				// build the prompt dialogue
				Byng.ui.response.buildPrompt(resp.getChildTag("prompt"));
			}
			
			// act upon any workflow directives
			var workflow = resp.getWorkflow( event );
			if ( workflow != null ) {
				Byng.ui.response.runWorkflow( workflow );
			}
			return resp;
		} catch (e) {
			Byng.log(e);
		}
	},
	
	/**
	 * Run a workflow
	 * 
	 * @param Object workflow
	 */
	runWorkflow : function ( workflow )
	{
		var params = workflow.get('params');
		switch (workflow.get('action')) {
			case "navigate":
				switch(params.navigateTo){
					case 'self': 	Byng.ui.reload(2000); break;
					case 'login':	Byng.ui.gotoLocation('/login'); break;
					case 'logout':	Byng.ui.gotoLocation('/logout'); break;
					case 'url':		Byng.ui.gotoLocation(params.url); break;
				}
			break;
		}
	},
	
	/**
	 * Write messages
	 * 
	 * @param Mixed messages
	 * @param String msgType
	 */
	writeMessages : function (messages, msgType)
	{
		// condition: passed raw XML
		if(typeOf(messages) == 'element') {
			messages = new ByngXml(messages);
		}
	
		// condition: passed something other than a hash
		if (typeOf(messages) != 'hash') {
			if (messages.name != 'byngxml') {
				messages = new ByngXml(messages);
			}
			messages = new Hash ({'errors' : messages.getErrors(), 'feedback' : messages.getFeedback()});
		}
		
		messages.each(function (msgs,msgType) {
		msgs.each(function(msg) {
			Byng.app.fireEvent('alert', [msg, msgType]);
		})});
	}
		
});

