/****************************************************
 * Extending JS base Classes
 ****************************************************/
// extending the javascript array.
Array.prototype.contains = function (element) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == element) return true;
	}
	return false;
};
// extending javascript string
String.prototype.endsWith = function (ending) {
	return (ending.length > 1) ? this.substr(this.length-ending.length) == ending : false;
}
/****************************************************
 * INIT FUNCTIONS
 ****************************************************/
var kgCore = kgCore ? kgCore : new kgCoreObject();

$(function() {
	initTabs();
	initErrorTooltips();
	initIconTooltips();
	initHoverables();
	initScrollable();
});
function initTabs() {
    // determine active tab by URL
	var calledURL = location.href;
	var activeTab = -1;	 // unknown
	var templateTab = 0; // default

	//console.info('calledURL: ', calledURL);
	$("ul#main-tabs a").each(function (i) {
		if (calledURL.endsWith($(this).attr('href'))) {
			activeTab = i;
			calledURL = calledURL.substr(0, calledURL.length-$(this).attr('href').length);
			return false;
		}
	});

	$("ul#main-tabs a").each(function (i) {
		if (calledURL.endsWith($(this).attr('href').substr(1))) {
			templateTab = i;
			// if no other tab should be shown, show the teplatetab.
			if (activeTab == -1 ) activeTab = templateTab;
			return false;
		}
	});
	if (activeTab == -1) activeTab = templateTab;
	//console.info('view tab: ',activeTab,' template goes to tab: ', templateTab, ' jQ: ',$('.tab-contents > div:eq('+activeTab+')'));
	// template is rendered per default in tab 0
	if (templateTab != 0) {
		// move template content into current tab and remove unneccessary div
		$('#rendered-template').children().appendTo('.tab-contents > div:eq('+templateTab+')');
		$('.tab-contents > div:eq('+templateTab+') *').triggerHandler('onshow');
		$('#rendered-template').empty();
		//$('.tab-contents > div:eq('+templateTab+')');
	}
	// setup tabs to work as tabs for each div directly under div.panes
    var tabs = $("ul#main-tabs").tabs(".tab-contents > div", {
    	initialIndex: activeTab,
    	tabs: 'a:not(.logout)',
    	current: 'ui-state-active',
    	// just before tabs are clicked, we load the contents 
    	onBeforeClick: function(e, i) {
    		// get the pane to be opened 
    		var pane = this.getPanes().eq(i); 
    		// show if hidden
    		if (pane.is(':hidden')) pane.show();
    		// load contents only the first time it's opened 
    		if (pane.is(":empty") && !pane.is('.loaded')) {
    			pane.addClass('loaded');
    			// transform anchor links to page URL's 
    			var url = this.getTabs().eq(i).attr("href").substring(1); 

    			// console.info('Pane ' + pane + ' is empty. Loading "' + url, ' Conf is ', this.getConf());
    			// TODO show loading indicator

    			function finisher(responseText, textStatus, XMLHttpRequest) {
					if (textStatus != 'success') {
						// just reload the whole page.
						location.reload();
					}
				} 

    			// load the page
    			pane.load(url, '', finisher); 
            }
    	},
        onClick: function (e, i) {
    		// get the opened pane
    		var pane = this.getPanes().eq(i);
    		$('*', pane).each(function (i) {
    			$(this).triggerHandler('onshow');
    		});
    		// track view via GoogleAnalytics (if present)
    		if (typeof(pageTracker) != "undefined") {
    			//console.info('GoogleTracker found: ', pageTracker);
    			pageTracker._trackPageview(this.getTabs().eq(i).attr("href").substring(1));
    		}
        }
    });
	if ($('ul#main-tabs').is(':not(.mobile)')) tabs.history();
}
function initErrorTooltips(parent) {
	$('span.error', parent).tooltip({
		bodyHandler: function () {
			return $(this).next('.tip').html();
		},
		extraClass: 'ui-state-error ui-corner-all',
		track: true,
		delay: 0
	});
	// fix bug when tooltipped element is removed and tooltip not...
	$('#tooltip').mouseenter(function (e) { $(this).hide().attr('class',''); } );
}
function initIconTooltips(elements) {
	$('span.ui-icon', elements).not(':empty').tooltip({
		bodyHandler: function () {
			return $(this).html();
		},
		extraClass: 'ui-state-default ui-corner-all',
		delay: 0,
		track: true
	});
}
function initHoverables(elements) {
	$('.hoverable', elements).hover(
		function () { $(this).addClass('ui-state-hover')},
		function () { $(this).removeClass('ui-state-hover')}
	);
}
function initScrollable(elements) {
	// for multiple scrollables
	$('.scrollable', elements).each(function (i){
		var scrollableHeight = 0;
		var itemWidth = $(this).width();
		$('.items .item', this).each(function (i) {
			$(this).css('width', itemWidth+'px');
			if ($(this).height() > scrollableHeight) scrollableHeight = $(this).height();
		});
		$(this).css('height', scrollableHeight+'px');
	});
	$('.scrollable', elements).scrollable({
		size: 1,
		activeClass: 'ui-state-active',
		disabledClass: 'ui-state-disabled',
		clickable: false
	}).navigator({
		navi: '.navi',
		activeClass: 'ui-state-active',
		naviItem: 'a.naviItem',
		indexed: true
		
	});
	
}
/***************************************************
* BASE CLASSES
****************************************************/

//TODO factor out interfaces...
function Observer() {
	this.update = function (action, object) {
		// check whether we are observable, too. if so: delegation should be standard behaviour.
		if (this.notify) {
			this.notify(action, object);
		}
	};
}
function Observable() {
	this.observer	= new Array ();

	/**
	 * notify observers about a change
	 */
	this.notify = function (action, object) {
		for ( var i = 0; i < this.observer.length; i ++) {
			this.observer[i].update(action, object);
		}
	};
	this.addObserver = function (observer) {
		if (!observer) return;
		this.observer.push ( observer );
	};
	this.removeObserver = function ( observer ) {
		for (var i = 0; i < this.observer.length; i++) {
			if ( observer == this.observer[i] ) {
				this.observer.splice ( i, 1 );
				break;
			}
		}
	};	
}
function View() {
}
function Model() {
}

/****************************************************
* Kiwigrid Core Functions/Variables
****************************************************/
function kgCoreObject () {
	/*****************
	 * Private Members
	 *****************/
	var deviceModel = null;
	var loaded = false;
	var loading = false;
	 
	function _lazyLoadDeviceModel() {
		loading = true;
		$.ajax({
			dataType	: 'text',
			cache		: false, // never cache the model, man!
			type		: 'GET',
			url			: url_for('modComponents/deviceTreeRead'),
			success		: function(data, status)
							{	
								var deviceJSON = JSON.parse(data);
								if (typeof deviceJSON == "object") {
									for (var facilityKey in deviceJSON ) {
										// double-check whether this is all stuff.
										if (typeof deviceJSON[facilityKey] == 'object') {
											deviceModel.addChild(deviceJSON[facilityKey]);
											// now we can say we're loaded.
											loaded = true;
										}
									}
								}
							},
			complete	: function(xhr, status)
							{
								// everything went fine? then sucess function was called.
								if (xhr.status == 200) return;
								// retrigger loading in a second.								
								setTimeout("kgCore.getDeviceModel()", 1000);
							}
		});
	}
	
	function _getDeviceModel() {
		if (deviceModel == null) {
			deviceModel = new TreeModel();
		}
		if (!loaded && !loading) _lazyLoadDeviceModel();
		
		return deviceModel;
	}
	
	/*****************
	 * Public Members
	 *****************/
	this.getDeviceModel = function () {
		return _getDeviceModel();
	}
	
	// the ajax request buffer. may be used by anybody.
	this.openRequests = {
		requests: new Object(),
		add:
			function (req, xhr, treeItem, callBack) {
				this.requests[req] = {
					'xhr' 		: xhr,
					'treeItem'	: treeItem,
					'callback'	: callBack
				};
			},
		remove:
			function (req) {
				this.requests[req] = undefined;
			},
		finalize:
			function (req, data, status) {
				if (!this.requests[req]) return;
				if (data == null) {
					data = {status: 'fail', message: __('kg.js.xhr-fail %error%', {'%error%': status} )};
				} else {
					data = JSON.parse(data);
				}
				this.requests[req]['callback'](this.requests[req]['treeItem'], data);
				this.remove(req);
			}
	};
	
	var that = this;
	this.ajaxFormInitializer = function (responseText, textStatus, XMLHttpRequest,container,form) {
		if (textStatus == 'success') {
			if (!container && !form) {
				container = $(this);
				form = container.find('form');
			} else if (container && !form) {
				form = container.find('form');
			}
			//console.info('Ajaxing form: ', form);
			if (container) container.removeClass('loading');
			initErrorTooltips(container);
			initIconTooltips(container);
			initHoverables(container);
			form.submit(
					function() {
						
						if ($(this).data('submitting') == true) return false;
						$(this).data('submitting', true);
						
						if (!container) container = form.parent();
						
						$(this).find('button .icon-loading').show('normal');
						data = $(this).serialize();
						$('input,select', this).attr("disabled","disabled");
						
						$.ajax( {
							url : $(this).attr('action'),
							dataType : 'text',
							data : data,
							type : $(this).attr('method').toUpperCase(),
							success : function(data, textStatus) {
								try {
									container.find('form button .icon-loading').hide('normal');
									$('input,select', container.find('form')).removeAttr("disabled");
									data = JSON.parse(data);
									if (data.status == 'success') {
										if (data.item && 
												container.data('view') && 
												typeof(container.data('view').model) != "undefined" &&
												typeof(container.data('view').model.setField) != "undefined")
											for (field in data.item) {
												container.data('view').model.setField(field,data.item[field],true);
											}
									}
								} catch (e) {
									// no json returned. so just include it.
									container.html(data);
									that.ajaxFormInitializer(responseText,textStatus,XMLHttpRequest,container);
								}
							},
							complete : function() {
								if (textStatus != 'success') {
									// just reload the whole page.
									location.reload();
								}
							}
						});
						return false;
					}
				)
			;
			$(this).show('normal');
		}
	};
}




/****************************************************
* Simple Visual Controls
****************************************************/

function kgConfirm(title, message, positiveCallback, callbackParam) {
	
	if (! $('#kgconfirm-dialog').is('*') ) {
		// create and append markup
		$(	'<div id="kgconfirm-dialog" class="kg-dialog">'+
			'	<p><span class="ui-icon ui-icon-alert"></span><span class="kgdialog-message"></span></p>'+
			'</div>').hide().appendTo('body');
		// create buttons
		var buttons = {};
		buttons[__('kg.js.confirm.no') ] = function () {
			$(this).dialog('close'); 
		};
		buttons[__('kg.js.confirm.yes')] = function () {
			$(this).dialog('close');
			$(this).data('kgcc')($(this).data('kgccp'));
		};
				
		$('#kgconfirm-dialog').dialog({
			autoOpen: false,
			buttons: buttons,
			modal: true
		});
	}
	// show dialog
	$('#kgconfirm-dialog').data('kgcc', positiveCallback);
	$('#kgconfirm-dialog').data('kgccp', callbackParam);
	$('#kgconfirm-dialog').dialog('option', 'title', title);
	$('#kgconfirm-dialog').dialog('option', 'modal', true);	
	$('#kgconfirm-dialog .kgdialog-message').html(message);
	$('#kgconfirm-dialog').dialog('open');
}


/**
* Simple helper for unobstrusivly make a link of an span element.
* @param jqElement The jQuery Element to transform
* @return The transformed jQuery Element.
*/
function makeSpanToLink(jqElement) {
	iHtml = jqElement.html();
	linkElem = $('<a href="#"></a>').html(iHtml);
	jqElement.replaceWith(linkElem);
	return linkElem;
}