// UWAGA: Uzycie tej funkcji przy ladowaniu ajax'owym powodowalo blad objawiajacy sie czyszczeniem strony
// i niekonczoncym sie requestem chwilowo trzeba dolaczac pliki w html'u
//function loadFile(file) {
//	document.write("<script type=\"text/javascript\" src=\"" + file + "\" ></script>");
//}

/**
 * Detektor przegladarki. 
 * http://www.quirksmode.org/js/detect.html
 * Jako WebapplesBrowserDetect.browser moze zwrocic:
 * "OmniWeb", "Safari", "Opera", "iCab", "Konqueror", "Firefox", "Camino", "Netscape", "Explorer", "Mozilla", "An unknown browser";
 * jako WebapplesBrowserDetect.version wersje przegladarki lub "an unknown version".
 * jako WebapplesBrowserDetect.OS: "Windows", "Mac","Linux", "an unknown OS".
 */
var WebapplesBrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1) {
					return data[i].identity;
				}
			}
			else if (dataProp) {
				return data[i].identity;
			}
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) {return;}
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
WebapplesBrowserDetect.init();


/*
 * rejestruje listenera. Listener powinien miec metode doPerform(event)
 * gdzie event jest nazwa zdarzenia (onclick, onmouseover, ....)
 */
function EventReceiver_sendEvent(event, sender) {
	for (var i = 0; i < this.listeners.length; i++) {
		if(this.listeners[i][0] == sender.id) {
			this.listeners[i][1].doPerform(event, sender);
		}
	}
}

function EventReceiver_registerListener(senderId, listener) {
	this.listeners[this.listeners.length] = [senderId, listener];
}

function EventReceiver() {
	this.listeners = [];
	this.sendEvent = EventReceiver_sendEvent;
	this.registerListener = EventReceiver_registerListener;
}

var eventReceiver = new EventReceiver();

function BaseMediator() {
	this.elementId = '';
	this.instanceName = '';
	this.setElementId = function(elementId) {
		this.elementId = elementId;
	};
	this.getElementId = function () {
		return this.elementId;
	};
	this.setInstanceName = function(name) {
		this.instanceName = name;
	};
	this.getInstanceName = function() {
		return this.instanceName;
	};
	this.request = function(url) {
		//TODO tu powinna nastapic analiza url i czy to odwolanie ajax (moze osobny parametr) i jezeli to ajax i mozliwe odwolanie
		// ajax to odwolanie ajax a jesli niemozliwe to z przeladowaniem strony
		window.location = url; 
	};
	
	this.init = function() {
	};
}

function WebapplesPageElementMediator() {
	// od _updateHtml_ zaczynaja sie nazwy zmiennych uzywanych wewnatrz metody updateHtml()
	// nie uzywamy tam lokalnych zmiennych by zabezpieczyc sie przed mozliwymi kolizjami ze zmiennymi deklarowanymi 
	// wewnatrz wykonywanych tam skryptach html, ktore sa pobierane ze wstawianych kawalkow html.
	this._updateHtml_div = null;
	this._updateHtml_scripts = null;
	this._updateHtml_script = null;
	/**
	 * public
	 * Wrzuca podany html do glownego elementu div zawierajacego tesc portletu.
	 * @param string html 
	 */
	this.updateHtml = function(html) {
		this._updateHtml_div = document.getElementById(this.getElementId());
		if(!this._updateHtml_div) {
			alert('Main element div (id: '+this.getElementId()+')not found!');
		} else {
			this._updateHtml_div.innerHTML = html;
			// wykonujemy wszystkie skrypty ktore byly w dolaczonym html'u
			this._updateHtml_scripts = this._updateHtml_div.getElementsByTagName('script');
			for(var i = 0; i < this._updateHtml_scripts.length; i++) {
				this._updateHtml_script = this._updateHtml_scripts[i];
				if(this._updateHtml_script.type == 'text/javascript') {
					eval(this._updateHtml_script.text);
				}
			}
		}
	};
}
WebapplesPageElementMediator.prototype = new BaseMediator();

function WebapplesPage() {
	this.mediators = {};
	
	this.pageId = null;
	this.reqParamNameElement = null;
	this.reqParamNamePage = null;
	this.reqParamNameAction = null;
	this.reqParamNameFormreset = null;
	this.reqParamNameFormsave = null;
	this.reqParamNameFormrestore = null;
	this.reqParamNameFormcopyclear = null;
	this.reqParamNameAjax = null;
	this.reqParamNameCallback = null;
	
	this.currVisibleCenteredPanelId = null;
	
	/**
	 * Ta metoda powinna byc wywolana w glownym layout'cie strony, by obiekt strony znal id strony, ktore moze byc mu potrzebne
	 * do realizacji odwolan ajax do serwera. Mozna ustawic ta wartosc korzystajac ze specjalnej zmiennej "{_page_id}".
	 * @param string pageId id strony (modul:nazwa).
	 */
	this.setPageId = function(pageId) {
		this.pageId = pageId;
	};
	
	/**
	 * @return string id strony (modul:nazwa) ustawione wczesniej metoda setPageId (powinno byc ustawione gdzies na poczatku strony).
	 */
	this.getPageId = function() {
		return this.pageId;
	};
	
	this.setReqParamNameElement = function(name) {
		this.reqParamNameElement = name;
	}; 
	this.getReqParamNameElement = function() {
		return this.reqParamNameElement;
	}; 
	this.setReqParamNamePage = function(name) {
		this.reqParamNamePage = name;
	}; 
	this.getReqParamNamePage = function() {
		return this.reqParamNamePage;
	}; 
	this.setReqParamNameAction = function(name) {
		this.reqParamNameAction = name;
	}; 
	this.getReqParamNameAction = function() {
		return this.reqParamNameAction;
	}; 
	this.setReqParamNameFormreset = function(name) {
		this.reqParamNameFormreset = name;
	}; 
	this.getReqParamNameFormreset = function() {
		return this.reqParamNameFormreset;
	}; 
	this.setReqParamNameFormsave = function(name) {
		this.reqParamNameFormsave = name;
	}; 
	this.getReqParamNameFormsave = function() {
		return this.reqParamNameFormsave;
	}; 
	this.setReqParamNameFormrestore = function(name) {
		this.reqParamNameFormrestore = name;
	}; 
	this.getReqParamNameFormrestore = function() {
		return this.reqParamNameFormrestore;
	}; 
	this.setReqParamNameFormcopyclear = function(name) {
		this.reqParamNameFormcopyclear = name;
	}; 
	this.getReqParamNameFormcopyclear = function() {
		return this.reqParamNameFormcopyclear;
	}; 
	this.setReqParamNameAjax = function(name) {
		this.reqParamNameAjax = name;
	}; 
	this.getReqParamNameAjax = function() {
		return this.reqParamNameAjax;
	}; 
	this.setReqParamNameNorefresh = function(name) {
		this.reqParamNameNorefresh = name;
	};
	this.getReqParamNameNorefresh = function() {
		return this.reqParamNameNorefresh;
	};
	
	this.getReqParamNameCallback = function() {
		return this.reqParamNameCallback;
	};
	this.setReqParamNameCallback = function(name) {
		this.reqParamNameCallback = name;
	};
	
	this.createRequestObject = function() {
		var xmlHttp;
		try	{
			// Firefox, Opera 8.0+, Safari
			xmlHttp=new XMLHttpRequest();
		} catch(e) {
			// Internet Explorer
			try	{
				xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e)	{
				try {
					xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
				} catch (e)	{
					return false;
				}
			}
		}
		return xmlHttp;
	};
	
	this.registerMediator = function(mediator) {
		this.mediators[mediator.getElementId()] = mediator;
	};
	
	this.getURLToMainScript = function() {
		var url = window.location.href;
		var endIndex = url.indexOf('?');
		if(endIndex != -1) {
			return url.substr(0, endIndex);
		}
		return url;
	};
	
	/**
	 * public
	 * Odswiezenie widoku elementow strony, ktore sie zmienily.
	 */
	this.update = function() {
		//var addr = this.getURLToMainScript();
		//addr += "?";
		//addr += this.getReqParamNamePage() + "="+ this.getPageId();
		
		this.callServerAction('GET', window.location.href, null, false);
	};
	
	this.createRequestContentFromForm = function(form) {
        var aParams = [];
        for (var i=0 ; i < form.elements.length; i++) {
        	var element = form.elements[i];
        	// przesylamy tylko jezeli element nie jest wylaczony
        	if(!element.disabled) {
        		// jezeli to checkbox lub radio, to wysylamy go tylko wtedy kiedy jest zaznaczony
        		if(!element.type || (element.type != "checkbox" && element.type != "radio" || element.checked)) {
		        	var sParam = encodeURIComponent(form.elements[i].name);
		            sParam += "=";
		            sParam += encodeURIComponent(form.elements[i].value);
		            aParams.push(sParam);
        		}
            }
        }
        return aParams.join("&");
	}; 
	
	this.jsFixedCenteredPanel = function() {
		return WebapplesBrowserDetect.browser == 'Explorer' && WebapplesBrowserDetect.version < 7;
	};
	
	/**
	 * public 
	 * Pokazuje na srodku okna przegladarki element blokowy o podanym id (div, p...). Element bedzie mial niezmienna pozycje niezaleznie 
	 * od przewijania strony. Jezeli przegladarka to IE < 7 to realizowane jest to przez obliczenie wsp. polozenia przy pomocy javascript
	 * ktore wykonywane jest w obsludze zdarzenia: window.onscroll.
	 * @param string panelId id elementu blokowego do pokazania.
	 */
	this.showCenteredPanel = function(panelId) {
		if(this.currVisibleCenteredPanelId === null) { 
			var panel = document.getElementById(panelId);
			panel.style.display = "block";
			
			var scrPosX = (document.body.offsetWidth - panel.offsetWidth) / 2;
			
			var h = - 1;
			if(window.innerHeight) { 
				h = window.innerHeight;
			} else if(document.documentElement.clientHeight) { 
				h = document.documentElement.clientHeight;
			} else if(document.body) { 
				h = document.body.clientHeight;
			}
			var scrPosY;
			if(h < 0) {
				scrPosY = 100;
			} else {
				scrPosY = (h - panel.offsetHeight) / 2;
			}
			
			panel.style.left = '' + scrPosX + 'px';
			panel.style.top = '' + scrPosY + 'px';
			if(this.jsFixedCenteredPanel()) {
				window.onscroll = function () {
					panel.style.top = scrPosY + document.documentElement.scrollTop + 'px';
					panel.style.left = scrPosX + document.documentElement.scrollLeft + 'px';
				};
			} else {
				panel.style.position = 'fixed';
			}
			
			panel.style.visibility = 'visible';
		}
	};
	
	/**
	 * public 
	 * Chowa element blokowy o podanym id pokazany przy pomocy metody showCenteredPanel.
	 * Jezeli showCenteredPanel dodala obsluge zdarzenia: window.onscroll to hideCenteredPanel przypisze window.onscroll = null.
	 * @param string panelId id elementu blokowego do schowania.
	 */
	this.hideCenteredPanel = function(panelId) {
		var panel = document.getElementById(panelId);
		panel.style.visibility='hidden';
		panel.style.display = 'none';
		if(this.jsFixedCenteredPanel()) {
			window.onscroll = null;
		} else {
			panel.style.position = 'absolute';
		}
		this.currVisibleCenteredPanelId = null;
	};
	
	/**
	 * public
	 * Pozwala na wykonanie po stronie serwera akcji i odswiezenie elementow strony, ktore sie zmienily.
	 * @param string method "GET" lub "POST".
	 * @param string addr adres odwolania, nie powinien okreslac strony lub powinien wskazywac na biezaca.
	 * @param string elemformid id elementu formualarza - jezeli ma byc wyslany formularz (jesli nie to null).
	 * @param boolean norefresh czy pobierac dane do odswiezenia strony (mozna nie odswiezac strony lub nie odswiezac jej w standardowy sposob
	 *   - wtedy mozna pobrac dane z odpowiedzi akcji i samodzielnie zaktualizowac html).
	 */
	this.callServerAction = function(method, addr, elemformid, norefresh, callback) {
		var request = this.createRequestObject();
		var form = null;
		if(request) {
			var requestContent = null;
			// todo odwolanie ajax
			request.onreadystatechange = function() {
				if(request.readyState == 4) {
					__page.performResponse(request.responseText);
				}
			};
			if(elemformid !== null && elemformid.length > 0) {
				// sprawdzamy czy jest formularz	
				form = document.getElementById(elemformid);
				if(!form) {
					throw new Error("Form with id = " + elemformid + " not exists");
				} else {
					//todo musimy wyslac formularz - trzeba stworzyc lancuch parametrow i przekazac go get'em lub post'em
					var str = this.createRequestContentFromForm(form);
					if(method == "POST") {
						requestContent = str;
					} else {
						// doklejamy do adresu
						if(addr.indexOf('?') != -1) {
							addr += '&';
						} else {
							addr += '?';
						}
						addr += str;
					}
				}
			}
			addr += '&' + this.getReqParamNameAjax() + "=1";
			if(norefresh) {
				addr += '&' + this.getReqParamNameNorefresh() + "=1";
			}
			if(callback) {
				addr += '&' + this.getReqParamNameCallback() + '=' + callback; 
			}
			request.open(method, addr, true);
			request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			request.send(requestContent);
			// pokazujemy komunikat proszacy o chwile cierpliwosci przy ladowaniu i zmieniamy kursor muszy
			document.body.style.cursor = 'wait';
			this.showCenteredPanel('pleasewaitScreen');
		} else {
			// brak obslugi ajax
			// jezeli jest tylko adres, nie ma formularza, to przeladowujemy po prostu strone na podany adres
			if(elemformid === null || elemformid.length === 0) {
				window.location = addr;
			} else {
				form = document.getElementById(elemformid);
				if(!form) {
					throw new Error("Form with id = " + elemformid + " not exists");
				} else {
					// wysylamy formularz, wczesniej przypisujac podany adres i metode
					form.action = addr;
					form.method = method;
					form.send();
				}
			}
		}
	};
	
	this.performRefresh = function(refreshDataObj) {
		if(refreshDataObj.subelements.length === 0) {
			this.mediators[refreshDataObj.elementname].updateHtml(refreshDataObj.html);
		} else if(refreshDataObj.subelements && refreshDataObj.subelements.length > 0) {
			for(var i = 0; i < refreshDataObj.subelements.length; i++) {
				this.performRefresh(refreshDataObj.subelements[i]);
			}
		}
	};
	
	this.performResponse = function(responseText) {
		var responseObj = null;
		
		// chowamy komunikat proszacy o chwile cierpliwosci przy ladowaniu i zmieniamy kursor myszy
		document.body.style.cursor = 'auto';
		this.hideCenteredPanel('pleasewaitScreen');
		
		if(WebapplesBrowserDetect.browser == 'Explorer') {
			window.onscroll = null;
		}
		
		try {
			//var responseObj = eval('(' + responseText + ')');
			responseObj = responseText.parseJSON();
		} catch(e) {
			alert('Nieprawidlowa odpowiedz serwera. Sprobuj odswiezyc strone.');
		} 
		if(responseObj !== null) {
			// jezeli jest jakas odpowiedz z akcji to odsylamy ja do mediatora, ktory wywolal akcje
			if(responseObj.actionresponse && responseObj.callback) {
				var toEval = '(' + responseObj.callback + '(responseObj.actionresponse))';
				eval(toEval);
			}
			// jezeli bylo przekierowanie
			if(responseObj.redirect) {
				
				if(responseObj.ajax) {
					this.callServerAction('GET', responseObj.redirect, null, responseObj.norefresh);
				} else {
					window.location = responseObj.redirect;
				}
			} else {
				// jezeli przeslany jakis obiekt z danymi do odswiezenia widoku to odswiezamy
				if(responseObj.refreshdata) {
					this.performRefresh(responseObj.refreshdata);
				}
			}
			//TODO odeslanie ewentualnej odpowiedzi akcji do inicjatora 
		}
	};
}


var __page = new WebapplesPage();