/*
	Source: classbehaviours.handlers.reloadfromurl.js
	ClassBehaviours is a javascript framework based on class-name parsing.
	Copyright 2011 by Maurice van Creij and published on http://www.woollymittens.nl/
	This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
*/

	// CLASSBEHAVIOURS CLASS
	// create the root classbehaviours object if it doesn't already exist
	if(typeof(classBehaviours)=='undefined') classBehaviours = {};

		// CLASSNAME BEHAVIOUR FUNCTIONS
		// create the handlers child object if it doesn't already exist
		if(typeof(classBehaviours.handlers)=='undefined') classBehaviours.handlers = {}

			// Replace a link to external content with the actual content
			classBehaviours.handlers.reloadFromUrl = {
				// properties
				name: 'reloadFromUrl',
				settings: new Array(),
				refocus: '',
				index: 0,
				respite: 50,
				// methods
				start: function(node){
					// give the node an id, if it doesn't have one yet
					node.id = (node.id) ? node.id : this.name + this.index++ ;
					this.settings[node.id] = {};
					// shortcut pointers
					var rfu = classBehaviours.handlers.reloadFromUrl;
					var cfg = rfu.settings[node.id];
					// if the node is marked to load automatically start loading
					cfg.autoTimeout = null;
					automatic = classBehaviours.utilities.getClassParameter(node, 'auto', 'no');
					if(automatic=='yes'){
						this.clicked(node);
					}else if(parseInt(automatic)>0){
						clearTimeout(cfg.autoTimeout);
						cfg.autoTimeout = setTimeout('classBehaviours.handlers.reloadFromUrl.clicked(document.getElementById("'+node.id+'"))', parseInt(automatic));
					}
					// set an onclick event
					if(node.nodeName == 'IFRAME') this.clicked(node)
					else if(node.nodeName == 'FORM') node.onsubmit = this.clicked
					else if(node.nodeName == 'BUTTON') node.onclick = this.clicked
					else if(node.nodeName == 'INPUT' && (node.type=='button' || node.type=='submit')) node.onclick = this.clicked
					else if(node.nodeName == 'INPUT' && (node.type=='radio' || node.type=='checkbox')) node.onclick = this.changed
					else if(node.nodeName == 'INPUT') node.onchange = this.changed
					else if(node.nodeName == 'SELECT') node.onchange = this.changed
					else if(node.nodeName == 'TEXTAREA') node.onchange = this.changed
					else if(node.nodeName == 'FIELDSET') null
					else node.onclick = this.clicked;
					//  Added for hijacking .NET postback event
					if(node.nodeName=='A' && node.href.indexOf('javascript:__doPostBack')>-1){
						node.href = '';
						node.onclick = this.clicked;
					}
				},
				wait: function(importProgress, referedNode, importError, requestTime){
					var rfu = classBehaviours.handlers.reloadFromUrl;
					// get the target for the indicator
					targetId = classBehaviours.utilities.getClassParameter(referedNode, 'target', '');
					if(targetId!='') targetNode = document.getElementById(targetId)
					else targetNode = referedNode;
					// if a progress meter was explicitly defined
					progressNode = classBehaviours.utilities.getClassParameter(referedNode, 'progress', '');
					if(progressNode!='') targetNode = document.getElementById(progressNode);
					// update the progress indicator
					classBehaviours.utilities.setClassParameter(targetNode, 'progress', importProgress);
					classBehaviours.utilities.setClassParameter(targetNode, 'error', importError);
					if(targetNode.nodeName=='METER'){
						targetNode.setAttribute('min', 0);
						targetNode.setAttribute('max', 100);
						targetNode.setAttribute('value', importProgress/4);
					}
					// only turn on the progress indicator after a short pause
					shownStatus = (new Date()-requestTime > rfu.respite || requestTime<0) ? 1 : 0 ;
					classBehaviours.utilities.setClassParameter(targetNode, 'show', shownStatus);
				},
				insert: function(importedObj, referedNode, importedText, requestTime){
					var rfu = classBehaviours.handlers.reloadFromUrl;
					// get the optional parameters from the refered node
					targetId = classBehaviours.utilities.getClassParameter(referedNode, 'target', null);
					sourceId = classBehaviours.utilities.getClassParameter(referedNode, 'source', null);
					//  if a form is in the response take the action and reload
					noformId = classBehaviours.utilities.getClassParameter(referedNode, 'noform', null);
					nonIntrusive = (classBehaviours.utilities.getClassParameter(referedNode, 'gently', '0')=='1');
					// for all peers of the clicked node
					if(referedNode.parentNode!=null){
						var allPeers = referedNode.parentNode.parentNode.getElementsByTagName(referedNode.nodeName);
						for(var a=0; a<allPeers.length; a++){
							// mark the clicked node as active
							if(allPeers[a]==referedNode){
								allPeers[a].className = allPeers[a].className.replace('link', 'active');
							}
							// mark the peers of the clicked node as passive
							else{
								allPeers[a].className = allPeers[a].className.replace('active', 'link');
							}
						}
					}
					// get the content from the imported node
					importedNode = (sourceId!=null) ?
						rfu.getXmlElementById(sourceId, importedObj, true) :
						importedObj ;
					// forcefully insert the content into the target node
					if(!nonIntrusive){
						// get the source HTML from the imported document
						importedHTML = rfu.serialize(importedNode, true);
						// strip any left over body tags from the content
						if(importedHTML.indexOf('<body')>-1){
							importedHTML = importedHTML.split('<body')[1].split('</body>')[0];
							importedHTML = importedHTML.substr(importedHTML.indexOf('>') + 1, importedHTML.length);
						}
						// if no id was given for the target node
						if(targetId==null){
							// replace the refered node
							newDiv = document.createElement('div');
							newDiv.id = rfu.name + rfu.index++ ;
							referedNode.parentNode.replaceChild(newDiv, referedNode);
							var targetNode = document.getElementById(newDiv.id);
						}
						// else
						else{
							// use the target id to find the node
							var targetNode = document.getElementById(targetId);
						}
						//  if a full page is loaded and the noform is set do a redirect.
						if (noformId == '1' && new String(importedHTML).toLowerCase().indexOf('<form') > -1) {
							url = new String(importedHTML).toLowerCase();
							index = url.indexOf('action') + 8;
							url = url.substr(index, url.length - index);
							//  IE removed the " from the action="".
							index = url.indexOf('"') > url.indexOf('>') ? url.indexOf('>') : url.indexOf('"');
							url = url.substr(0, index);
							location.href = url;
							return;
						}
						// insert the imported HTML
						if(targetNode!=null){
							// if the new content needs to be revealed gradually
							var revealTime = parseInt(classBehaviours.utilities.getClassParameter(referedNode, 'reveal', '0'));
							if(revealTime>0){
								// hide the old content and reveal the new content
								classBehaviours.fader.fade(targetNode, 100, 0, 5000/revealTime, 50, 0, function(){
									targetNode.innerHTML = importedHTML;
									classBehaviours.fader.fade(targetNode, 0, 100, 5000/revealTime, 50, 0, null);
								});
							}
							// else just show it immediately
							else{
								targetNode.innerHTML = importedHTML;
							}
						}
						// set the focus (if any)
						if(rfu.refocus!=null){
							if(rfu.refocus.nodeName=='INPUT' || rfu.refocus.nodeName=='SELECT' || rfu.refocus.nodeName=='TEXTAREA'){
								rfu.refocus.focus();
							}
						}
					}
					// or gently compare classnames and text
					else{
						// for all imported nodes
						importedChildNodes = importedNode.getElementsByTagName('*');
						for(var a=importedChildNodes.length-1; a>=0; a--){
							// get the target ID
							exportedChildNodeId = importedChildNodes[a].getAttribute('id');
							// if it's a node with an existing ID
							if(exportedChildNodeId!=null && exportedChildNodeId!=''){
								// get the target node
								exportedChildNode = document.getElementById(exportedChildNodeId);
								// does this node actually exist?
								if(exportedChildNode!=null){
									// sync the classname
									exportedChildNode.className = (importedChildNodes[a].className!=null) ? importedChildNodes[a].className : importedChildNodes[a].getAttribute('class') ;
									// sync the select options
									if(importedChildNodes[a].nodeName=='SELECT'){
										// every node in this select
										importedSelectOptions = importedChildNodes[a].getElementsByTagName('OPTION');
										exportedSelectOptions = exportedChildNode.getElementsByTagName('OPTION');
										// choose the longest list
										selectOptionsLength = (importedSelectOptions.length>exportedSelectOptions.length) ? importedSelectOptions.length : exportedSelectOptions.length ;
										// for every item in the list
										for(var b=selectOptionsLength-1; b>=0; b--){
											// if there is no exported option
											if(b>=exportedSelectOptions.length){
												// make a new option node
												newOptionElement = document.createElement('OPTION');
												newOptionText = document.createTextNode(importedSelectOptions[b].firstChild.nodeValue);
												newOptionElement.appendChild(newOptionText);
												newOptionElement.setAttribute('value', importedSelectOptions[b].value);
												exportedChildNode.appendChild(newOptionElement);
											}
											// if there is no imported option
											else if(b>=importedSelectOptions.length){
												// remove an option node
												exportedSelectOptions[b].parentNode.removeChild(exportedSelectOptions[b]);
											}
											// else
											else{
												// transfer the imported to the exported node
												exportedSelectOptions[b].firstChild.nodeValue = importedSelectOptions[b].firstChild.nodeValue;
												exportedSelectOptions[b].value = importedSelectOptions[b].value;
											}
										}
									}
									// sync the text
									importedHTML = rfu.serialize(importedChildNodes[a]);
									importedHTML = importedHTML.substring(importedHTML.indexOf('>') + 1, importedHTML.lastIndexOf('<'));
									isInlineMarkup = (
										exportedChildNode.innerHTML.toUpperCase().indexOf('<DIV')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<SECTION')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<ARTICLE')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<HEADER')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<FOOTER')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<NAV')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<FIELDSET')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<SELECT')<0 &&
										exportedChildNode.nodeName!='SELECT' &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<OPTION')<0 &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<TEXTAREA')<0 &&
										exportedChildNode.nodeName!='TEXTAREA' &&
										exportedChildNode.innerHTML.toUpperCase().indexOf('<INPUT')<0 &&
										exportedChildNode.nodeName!='INPUT'
									);
									if(isInlineMarkup) exportedChildNode.innerHTML = importedHTML;
								}
							}
						}
					}
					// reset the progress indicator
					classBehaviours.utilities.setClassParameter(targetNode, 'progress', 4);
					classBehaviours.utilities.setClassParameter(targetNode, 'error', 200);
					// activate any classbehaviours in there
					classBehaviours.parser.parseNode(targetNode);
					// OPTIONAL: replace the title
					replaceTitleId = classBehaviours.utilities.getClassParameter(referedNode, 'title', null);
					if(replaceTitleId!=null) document.getElementById(replaceTitleId).innerHTML = referedNode.title;
				},
				getXmlElementById : function(id, doc, echo){
					// default value
					node = null ;
					// if a valid id was given
					if(id!=null){
						// look through all nodes
						allNodes = doc.getElementsByTagName('*');
						// until you find one with the right ID
						var a = 0;
						while(node==null && a<allNodes.length){
							if(allNodes[a].getAttribute('id')==id){
								node = allNodes[a];
							}
							a += 1;
						}
					}
					// return the cleaned content
					return (echo && node==null) ? doc : node;
				},
				serialize : function(node, inner){
					// if the standard method is valid
					if(typeof(XMLSerializer)!='undefined'){
						nodeXml = (new XMLSerializer()).serializeToString(node);
					}
					// if this is MSIE and XML was given
					else if(node.xml!=null){
						nodeXml = node.xml;
					}
					// if this is MSIE and a whole document was given
					else if(node.getElementsByTagName('HTML').length>0){
						nodeXml = '<!DOCTYPE html><HTML>' + node.getElementsByTagName('HTML')[0].innerHTML + '</HTML>';
					}
					// if this is MSIE and an HTML4 fragment was given
					else if(node.innerHTML!=null && node.innerHTML!=''){
						nodeXml = '<' + node.nodeName + ' class="' + node.className + '" id="' + node.id + '">' + node.innerHTML + '</' + node.nodeName + '>';
					}
					// if this is MSIE and an HTML5 fragment was given
					else {
						// pick parent nodes until a node is found for which the innerHTML actually works
						nodeXml = '';
						nodeRoot = node;
						while(nodeRoot!=nodeRoot.parentNode && nodeXml==''){
							// try the next parent
							nodeRoot = nodeRoot.parentNode;
							// get the innerHTML of that
							nodeXml = nodeRoot.innerHTML;
						}
						// to find the tag name of the string, look for the id in the string
						idIndex = nodeXml.indexOf('id="' + node.id + '"');
						if(idIndex<0) idIndex = nodeXml.indexOf('id=' + node.id + ' ');
						if(idIndex<0) idIndex = nodeXml.indexOf('id=' + node.id + '>');
						// split the string before this position
						tagName = nodeXml.substring(0, idIndex);
						// find the last < and split it after
						openTagIndex = tagName.lastIndexOf('<');
						tagName = tagName.substring(openTagIndex+1);
						// find the first ' ' and split it before
						tagName = tagName.substring(0, tagName.lastIndexOf(' '));
						// split the string after the id position
						endTags = nodeXml.substring(idIndex);
						// while the close tag was not found and the string did not end
						charCount = openTagIndex + 1;
						tagCount = 1;
						tries = 0;
						while(tagCount>0 && tries<5){
							// look forward through the string to count similar tags
							nextStart = nodeXml.indexOf('<' + tagName, charCount);
							if(nextStart==-1) nextStart = 1000000;
							nextClose = nodeXml.indexOf('</' + tagName + '>', charCount);
							if(nextClose==-1) nextClose = 1000000;
							// if you find a similar opening tag add 1 to the count
							if(nextStart<nextClose){
								tagCount += 1;
								charCount = nextStart + 1;
							}
							// if you find a similar closing tag substract 1 from the count
							if(nextClose<nextStart){
								tagCount -= 1;
								charCount = nextClose + 1;
							}
							// if the count reaches 0 the proper closing tag was found
							tries += 1;
						}
						// cut off the rest of the string using the character counter
						closeTagIndex = nextClose + tagName.length + 3;
						// return the resulting clip
						nodeXml = nodeXml.substring(openTagIndex, closeTagIndex);
					}
					// remove the outer tag if required
					if(inner){
						// split after first > and before last <
						nodeXml = nodeXml.substring(nodeXml.indexOf('>')+1, nodeXml.lastIndexOf('<'));
					}
					// give the extracted element back
					return nodeXml;
				},
				getPostValues : function(node, nodeId){
					// use the id if needed
					if(nodeId!=null) node = document.getElementById(nodeId);
					// get all elements of this form
					formNode = classBehaviours.utilities.findParentNode(node, 'FORM');
					rootNode = classBehaviours.utilities.findParentNode(node, 'FIELDSET');
					allNodes = rootNode.getElementsByTagName('*');
					postValues = '';
					// see if we can do anything to make it easier for .NET
					// .NET replaces the last _ with a $ for eventtarget validation
					eventTarget = '';
					split = node.id.split("_");
					if (split.length > 1) {
						for (var a = 0; a < split.length; a++)
							if (split[a] != '')
							eventTarget += (a == split.length - 1 ? '$' + split[a] : '_' + split[a]);
					}
					else eventTarget = node.id;
					postValues = '__EVENTTARGET=' + eventTarget + '&';
					// for all elements
					for(var a=0; a<allNodes.length; a++){
						// build the query string from the name and value pairs
						if(
							allNodes[a].nodeName=='INPUT' ||
							allNodes[a].nodeName=='SELECT' ||
							allNodes[a].nodeName=='TEXTAREA'
						)
							if(
								allNodes[a].getAttribute('type')!='submit' &&
								allNodes[a].getAttribute('type')!='image' &&
								allNodes[a].getAttribute('type')!='button' &&
								allNodes[a].getAttribute('type')!='reset'
							)
								//  Add all except the viewstate and eventtarget (.NET)
								if(allNodes[a].name!='__VIEWSTATE' && allNodes[a].name!='__EVENTTARGET')
									postValues += (allNodes[a].checked || (allNodes[a].type!='radio' && allNodes[a].type!='checkbox')) ?
										allNodes[a].name + '=' + escape(allNodes[a].value) + '&' :
										'';
					}
					// add the value of the pressed button
					if(node.nodeName == 'BUTTON' || node.getAttribute('type')=='submit' || node.getAttribute('type')=='button') postValues += node.id + '=' + node.value + '&';
					// add the cookie value too
					if (document.cookie != null) postValues += document.cookie.replace(/; /gi, "&");
					// return the values
					return postValues;
				},
				// events
				clicked: function(that, href){
					var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
					var rfu = classBehaviours.handlers.reloadFromUrl;
					// if the node still exists
					if(objNode!=null){
						// reminder the focus
						rfu.refocus = objNode;
						// try to get a URL from somewhere
						targetHref = (href==null) ? objNode.getAttribute('href') : href ;
						targetSrc = objNode.getAttribute('src');
						targetLongdesc = objNode.getAttribute('longdesc');
						rootForm = classBehaviours.utilities.findParentNode(objNode, 'FORM', null);
						targetAction = rootForm.getAttribute('action');
						//  get the id reference with holds the URI information
						hrefTarget = classBehaviours.utilities.getClassParameter(objNode, 'id', '');
						// decide which URL has priority
						targetUrl = (targetHref != null && targetHref != '') ? targetHref :
							(hrefTarget != null && hrefTarget != '') ? document.getElementById(hrefTarget).href :
							(targetAction != null && targetAction != '') ? targetAction :
							(targetLongdesc != null && targetLongdesc != '') ? targetLongdesc :
							(targetSrc != null && targetSrc != '') ? targetSrc :
							document.location.href;
						// get the post values
						postValues = rfu.getPostValues(objNode);
						// get the post method
						postPrefix = (targetUrl.indexOf('?')<0) ? '?' : '&' ;
						// if this is to be a refresh loop, set the interval for it
						reloadInterval = parseInt(classBehaviours.utilities.getClassParameter(objNode, 'interval', '-1'));
						if(reloadInterval>0){
							setTimeout('classBehaviours.handlers.reloadFromUrl.clicked(document.getElementById("'+objNode.id+'"));', reloadInterval);
						}
						// place the AJAX request and cancel the click
						return (new String(rootForm.getAttribute('method')).toLowerCase() == 'post') ?
							classBehaviours.ajax.addRequest(targetUrl, rfu.insert, rfu.wait, postValues, objNode) :
							classBehaviours.ajax.addRequest(targetUrl + postPrefix  + postValues, rfu.insert, rfu.wait, null, objNode) ;
					}
				},
				changed: function(that){
					var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
					var rfu = classBehaviours.handlers.reloadFromUrl;
					// if the form element is a select filled with url's, assume this is used as navigation and not as form input
					if(objNode.value.indexOf('/')>-1 && objNode.value.indexOf('.')>-1){
						// take the url and use it as an override in the ajax call
						rfu.clicked(objNode, objNode.value);
						return false;
					}else{
						// find the fieldset that belongs to this part of the form
						submitNode = classBehaviours.utilities.findParentNode(objNode, 'FIELDSET', null);
						// use the entire form if no fieldset was found
						if(submitNode.nodeName=='BODY'){
							submitNode = classBehaviours.utilities.findParentNode(objNode, 'FORM', null);
						}
						// find any buttons in this fieldset
						buttonNodes = submitNode.getElementsByTagName('BUTTON');
						if(buttonNodes.length>0){
							submitNode = buttonNodes[0];
						}
						// or find any submit inputs in this fieldset instead
						else{
							inputNodes = submitNode.getElementsByTagName('INPUT');
							for(var a=0; a<inputNodes.length; a++) if(inputNodes[a].type=='submit' || inputNodes[a].type=='button') submitNode = inputNodes[a];
						}
						// post it
						void(rfu.clicked(submitNode));
						return true ;
					}
				}
			}

	// JQUERY WRAPPER
	if(typeof(jQuery)!='undefined'){
		(function($){
			var methods = {
				init : function(options) {
					return this.each(function(){
						classBehaviours.handlers.reloadFromUrl.start($(this).context);
					});
				}
			};
			$.fn.reloadFromUrl = function(method){
				if(methods[method]) {
					return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
				}else if(typeof method === 'object' || !method){
					return methods.init.apply(this, arguments);
				}else{
					$.error('Method ' +  method + ' does not exist on jQuery.reloadFromUrl');
				}
			};
		})(jQuery);

		// JQUERY EVENTS
		$(document).ready(function() {
			$(".reloadFromUrl").reloadFromUrl();
		});
	}

