/*
Script: CiUI.js

Handles iPhone-optimized pages and mimics iPhone UI behavior

License:
	http://clientside.cnet.com/wiki/cnet-libraries#license
*/

(function() {

var bodyEl; // see ciUI.initialize() for details
var buttonForward = "go_forward";
var buttonMap = "change_map";
var buttonBackward = "go_back";
var buttonHome = "go_home";
var buttonLoadMore = "load_more";
var buttonLoadTags = "load_tags";
var linkGoTo = "go_on_page";
var doNothing = "do_nothing";
var backButtonEl; // see ciUI.initialize() for details
var pageTitleEl; // see ciUI.initialize() for details
var mapDivEl;
var update = "do_update";
var updateAttr = "update";

var pages = []; // see ciUI.initialize() for details
var pageHistory = []; 

var homePage = location.href;
var hashPrefix = "#__";
var currentHash = location.hash;
var currentPage = 1; // possible values are 1 or -1 (1: from, -1: to)

var animSpeed = 20; // smaller number means slower animation
var navigationCheckInterval = 300;
var navigtionChangeTimer;
var uiIsActive;

window.ciUI = {
	initialize: function() {
		bodyEl = $("iphone_body");
		backButtonEl = $("iphone_backbutton");
		pageTitleEl = $("iphone_title");
		mapDivEl = $("mapview");
		if (!bodyEl || !backButtonEl || !pageTitleEl) return;
		if (pageTitleEl && pageTitleEl.innerHTML == "") pageTitleEl.innerHTML = document.title;
		this.setupPages();
		this.animating = false;
		if(window.orientation != 0) updateMap(document.getElementById("uid").value+"-1");
		setTimeout(scrollTo, 100, 0, 1);
		return true;
	},
	
	setupPages: function() {
		var page1 = document.createElement('div');
		var page2 = document.createElement('div');
		var home  = document.createElement('div');
		var ascrolltop = document.createElement('a');

		page1.id = "__page1__";
		page1.className = "iphone_page";
		page1.style.left = "0%";
		page1.style.display = "block";
		
		page2.id = "__page2__";
		page2.className = "iphone_page";
		page2.style.left = "100%";
		page2.style.display = "none";
		
		home.id	= "__home__";
		home.style.display = "none";
		ascrolltop.id = "__scroll_top__";
		ascrolltop.name = "";
		
		page1.innerHTML = home.innerHTML = bodyEl.innerHTML;
		bodyEl.innerHTML = "";
		bodyEl.appendChild(page1);
		bodyEl.appendChild(page2);		
		document.body.appendChild(home);
		document.body.insertBefore(ascrolltop, document.body.firstChild);

		this.adjustBodyToEl(page1);
	
		pages[1] = $(page1.id);
		pages[0] = $(home.id);
		pages[-1] = $(page2.id);
	},
	
	goToPage: function(target, backwards, home) {
		if (backwards === undefined) backwards = false;

		this.slidePages(backwards);
		if(home){
		    pageHistory.push(pageHistory[0]);
		}
		// BACKWARD
        else if (backwards) { 
			currentHash = location.hash;
			pageHistory.splice(pageHistory.indexOf(target)+1, pageHistory.length);
		}
		// FORWARD
		else {
   			pageHistory.push(target);								
		}
		this.updatePage(target);
	},
	
	loadMore: function(target) {
	   if(target.className == "load_more_loaded")
	    {
		   var t = target.parentNode;
		   t.removeChild(t.lastChild);
		   t.removeChild(t.lastChild);
	       t.firstChild.innerHTML = t.firstChild.innerHTML.substring(4);
	       t.firstChild.className = "load_more";
	       ciUI.adjustBodyToEl(pages[currentPage]);
           scrollToTop();
	       return;
	    }
		target.className = "load_more_loading";
		(new this.ajax(target.href, updatePage)).run();
		
		function updatePage(content) {
    		if( target.className != "load_more_loaded" )
            {
			var newElem = document.createElement('p');
			var newLink = document.createElement('a');
            newElem.innerHTML = content;
			target.parentNode.appendChild(newElem);
			newLink.className = "load_more_loaded";
            target.className = "load_more_loaded";
			newLink.innerHTML = "Hide "+target.innerHTML;
			newLink.href = target.href;
			target.innerHTML = "Hide "+target.innerHTML;
			target.parentNode.appendChild(newLink);
            }
			ciUI.adjustBodyToEl(pages[currentPage]);
		}
	},
	
	loadTags: function(target) {
  	        $('tagging').innerHTML = "Tagging Loading...";
		    $('tagging').className = "load_more_loading";
         	(new this.ajax(target.href, updatePage)).run();
         	
         	function updatePage(content) {
 				$('tagging').innerHTML = "<div id=\"tags\"></div>";
  	            $('tagging').className = "";
                $('tags').innerHTML = content;
			    ciUI.adjustBodyToEl(pages[currentPage]);
	    }
	},
	
	updateMapPage: function(target) {
		(new this.ajax(target.target, this.updateMapContent)).run();
		ciUI.adjustBodyToEl(pages[currentPage]);
	},
	
	updatePage: function(target) {
		var nextHash = hashPrefix + (pageHistory.length);
		backButtonEl.style.display = (!target || pageIndexFromHash(nextHash) == 0 || (target.href != null && target.href.indexOf("index.php") != -1)) ? "none" : "block";
		// Update body with new page content
		if (pageIndexFromHash(nextHash) == 0 || !target) {
			//pageTitleEl.innerHTML = trim(document.title);
			this.updatePageContent(pages[0].innerHTML); // page[0] is home, no need for AJAX
		}			
		else {
			backButtonEl.innerHTML = (pageHistory[pageHistory.length-2]) ? trim(pageHistory[pageHistory.length-2].title, 15) : "Back";
			var url = target.href;
			if (!url && target.tagName.toLowerCase() == "form") url = target.action+"?"+target.toQueryString();
			(new this.ajax(url, this.updatePageContent)).run();
		}
	},
	
	updatePageContent: function(content) {
		var updateTimer = setInterval(update, 0);
			
		function update() {
			if (!ciUI.animating) {
				$("__scroll_top__").name = currentHashName(true);
				pages[currentPage].innerHTML = content;
				pages[-currentPage].innerHTML = "";
				clearInterval(updateTimer);								
				location.href = currentHash = currentHashName();
				if (ciUI.callbackFunct) ciUI.callbackFunct();
				mapDivEl.innerHTML = $('mapviewloaded').innerHTML;
				if(window.orientation != 0) scrollMap();
				$('mapviewloaded').innerHTML = "";
				$('bod').onorientationchange = 'updateMap('+$('map').width+');';
				ciUI.adjustBodyToEl(pages[currentPage]);				
			}			
		}		
	},
	
	updateMapContent: function(content) {
		var updateTimer = setInterval(update, 0);
			
		function update() {
			if (!ciUI.animating) {
				mapDivEl.innerHTML = content;
			}			
		}		
	},
	
	slidePages: function(backwards) {
		this.animating = true;
		
		var fromPage = pages[currentPage];
		var toPage = pages[-currentPage];
		var progress = 100;
		
		toPage.innerHTML = this.loadingPage();
		mapDivEl.innerHTML = this.loadingPage();
		toPage.style.display = "block";
		
		if (!backwards) toPage.style.left = "100%";
		
		clearInterval(navigationChangeTimer); // pause the history daemon during animation.
		setTimeout(scrollTo, 100, 0, 1);
		var animTimer = setInterval(animate, 0);
		
		function animate() {
			progress -= animSpeed;
			
			if (progress <= 0) {
				clearInterval(animTimer);				
				navigationChangeTimer = setInterval(navigationChangeAgent, navigationCheckInterval); // restart the history daemon
				currentPage *= -1;
				progress = 0;
				ciUI.animating = false;
			}			
			fromPage.style.left = (backwards ? (100 - progress) : (progress - 100)) + "%";
			toPage.style.left = (backwards ? -progress : progress) + "%";
		}
	},
	
	ajax: function(sourceURL, responseConsumer, responseType) {
		var httpRequest = false;
		
		this.run = function()
		{
			if (responseType === undefined) responseType = "TEXT";
			responseType = responseType.toUpperCase();
			
			if (window.XMLHttpRequest) { 
				httpRequest = new XMLHttpRequest();
				if (httpRequest.overrideMimeType) {
					httpRequest.overrideMimeType('text/xml');
				}
			} 
			else if (window.ActiveXObject) { 
				try {
					httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
				} 
				catch (e) {
					try {
						httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
					} 
					catch (e) {}
				}
			}
			
			if (!httpRequest) {
				//console.log('Giving up, cannot create an XMLHTTP instance');
				return false;
			}
	
			httpRequest.open('GET', sourceURL, true);
			httpRequest.onreadystatechange = getResponse;
			httpRequest.send(null);	
		};
		
		function getResponse() {	
			if (httpRequest.readyState == 4)
				if (httpRequest.status == 200) {
					if (responseType == "XML")
						responseConsumer(httpRequest.responseXML);
					else
						responseConsumer(httpRequest.responseText);
				}
				else
					;//console.log("There was a problem with the request: " + sourceUrl);
		}
	},
	
	update: function(url, element) {	
		(new this.ajax(url, function(html){
			if (!element.tagName) element = $(element);
			element.innerHTML = html;
	       ciUI.adjustBodyToEl(pages[currentPage]);
		})).run();
	},
		
	cancel: function(event) {
		pageHistory = [];
		location.reload(true);
		location.hash = "";
		location.href = homePage;
		return false;
	},
	
	loadingPage: function() {
		return $("iphone_loading_page").innerHTML;
	},
	
	// a dirty hack to move the footer to proper location since iphone_body doesn't expand with content
	adjustBodyToEl: function(el) {
		bodyEl.style.height = el.offsetHeight + "px";
	}	
	

};

addEventListener("load", function(event) {
	uiIsActive = ciUI.initialize();
	if (uiIsActive) navigationChangeTimer = setInterval(navigationChangeAgent, navigationCheckInterval);
}, false);

addEventListener("click", function(event) {
	if (!uiIsActive) return;
	var a = findParent(event.target, "a");
	// We don't want to prevent defaults by default because there may be actual hrefs going to outside pages
	if (a && a.hasClass(linkGoTo)) {
        event.preventDefault();
	} else if (a && a.hasClass(doNothing)) {
        event.preventDefault(); 
    } else if (a && a.hasClass(buttonForward)) {
		ciUI.goToPage(a);
		event.preventDefault();
	} else if (a && a.hasClass(buttonBackward)) {
		history.back();	
		event.preventDefault();
	} else if (a && a.hasClass(buttonHome)) {
		ciUI.goToPage(a, true);	
		event.preventDefault();
	} else if (a && a.hasClass(buttonLoadMore)) {
		ciUI.loadMore(a);
		event.preventDefault();	
	} else if (a && a.hasClass(buttonLoadTags)) {
        ciUI.loadTags(a);
	    event.preventDefault();  
	}
}, true);

addEventListener("submit", function(event) {
	if (!uiIsActive) return;
	var a;
	var form = findParent(event.target, "form");
	if (!form) return;
	if (form.hasClass(buttonForward)) {	
		event.preventDefault();
		return ciUI.goToPage(form);
	} else if (form.hasClass(update)) {
		event.preventDefault();
		ciUI.update(form.action+"?"+form.toQueryString(), form.getAttribute(updateAttr));
		}
}, true);

addEventListener("click", function(event) {
	if (!uiIsActive) return;
	var a = findParent(event.target, ("a"));
	if (!a || !a.hasClass(update)) return;
	ciUI.update(a.href, a.getAttribute(updateAttr));
}, true);

function trim(text, maxLength) {
	if (maxLength === undefined) maxLength = 20;
	return (text.length > maxLength) ? text.substring(0, maxLength - 3) + "..." : text;
};

function currentHashName(ommitHashSymbol) {
	return (ommitHashSymbol) ? hashPrefix.substr(1, hashPrefix.length) + (pageHistory.length) : hashPrefix + (pageHistory.length);
};

function navigationChangeAgent() {
	if (currentHash != location.hash) {
		ciUI.goToPage(pageHistory[pageHistory.length-2], true);
	}
};

function pageIndexFromHash(hash) {
	return (hash) ? hash.substr(hash.lastIndexOf("_") + 1, hash.length) : 0;
};

Element.prototype.hasClass = function(name) {
	return this.className.indexOf(name) != -1;
};

Element.prototype.toQueryString = function(){
	var qs = "";
	var getvals = function(element){
		var kids = element.childNodes;
		for (var i=0; i < kids.length; i++) {
			var el = kids[i];
			if (el.tagName) {
				var t = el.tagName.toLowerCase();
				if (t.toLowerCase() == "input" && el.getAttribute("type") == "checkbox" && !el.checked) {continue;}

				if (t.toLowerCase() == "input" || t.toLowerCase() == "textarea") qs += el.name + "=" + escape(el.value) + "&";
				else if (t == "select") qs += el.name + "=" + escape(el.options[el.selectedIndex].value) + "&"; //no support for multiselect yet
				else getvals(el);
			}
		}
	};
	getvals(this);
	return qs;
}

// This function is courtesy of iUI
function findParent(node, localName) {
    while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
        node = node.parentNode;
    return node;
};

function $(id) { return document.getElementById(id); };

})();
