/**
 * @projectDescription Projekt do zarządania akcjami
 * 
 * @copyright 2007 Robert (nospor) Nodzewski
 * @author Robert Nodzewski (nospor at gmail dot com)
 * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
 * @version 1.1
 */

/**
 * Klasa do zarządzania okienkami akcji. Wszystkie jej metody powinny być wywoływane statycznie
 * 
 * @example ActionsManager.nazwametody(); //dobrze
 * var am = new ActionsManager();am.nazwametody();//źle
 * 
 * @classDescription Klasa do zarządzania okienkami akcji
 * @id ActionsManager
 */
function ActionsManager(){};

/**
 * Inicjalizuje nowy obiekt akcji
 * 
 * @param {Map} params Obiekt parametrów.
 * @optionsFor params
 * @option {String} guid (required) identyfikator obiektu. Na podstawie guid będą rozpoznawane okna. Jeśli utworzymy kilka okien o tym samym guid, będą one dzielić tego samego diva. Jeśli damy różne guid, każdka okcja utworzy własnego oddzielnego diva.
 * Dla tego samego guid będzie można określić, czy pozwalamy by w trakcie trwania jednej akcji, mogła uruchomić się kolejna (parametr: allowRunRunning)
 * @option {String} link (required) link pod jaki wysyłać żądanie 
 * @option {Boolean} closeLastOpened (optional:false) czy zamkykać ostatnio otwarte okno
 * @option {Boolean} closeAfterSuccess (optional:false) czy zamykać okno gdy akcja się powiedzie. Dotyczy tylko wyników zwracanych jako xml  
 * @option {String} className (optional:'actionsManager') klasa głównego diva okna
 * @option {String} title (optional:pusty) tytuł w nagłówku
 * @option {String} titleRunning (optional:null) tytuł w nagłówku podczas trwania akcji. Jeśli podamy null, tytuł główny nie ulegnie zmianie.
 * @option {Boolean} refresh (optional:true) czy ponownie wykonać akcję jeśli już istnieje
 * @option {Boolean} toggle (optional:false) gdy klikamy na akcje i jest juz ona otwarta, to zamyka ją
 * @option {Boolean} allowRunRunning (optional:false) czy pozwalać na uruchamianie trwających już akcji w obrębie tego samego guid
 * @option {String} messagesAddingType (optional:'last') - w jakis sposób dodawać nowe wiadomości: first - na początku wiadomości, last - na końcu wiadomości 
 * @option {Map} params (optional:null) parametry akcji jakie mają być dodatkowo wysłane ajaxem, np: {'param1' : 'wartosc1', 'param2':'wartosc2'}
 * @option {jQuery} attachParams - formularz, z którego załadować parametry (obiekt jQuery) (domyślnie null) (tylko dla jQuery)
 * @option {String} method (optional:'post') metoda wysłania żądania
 * @option {Boolean} clear (optional:true) czy czyścić zawartość okienka
 * @option {String} type (optional:'xml') typ pobieranych danych: html, xml,inne. Można podać własne typy, należy wówczas dla
 * każdego typu zdefiniować metodę AjaxAction.prototype.writeTYPE = function(obj){...}, gdzie "TYPE" to pisane z dużej litery
 * określony przez was "type", a "obj" to obiekt, jaki zwraca ajax po wykonaniu akcji.
 * @option {Function} beforeSetup (optional:null) callback (funkcja) jaka ma się wykonać przed inicjalizacją. Funkcja jako parametr dostaje "params". Jeśli funkcja zwróci false, nie dojdzie do inicjalizacji obiektu
 * @option {Function} afterSetup (optional:null)  callback (funkcja) jaka ma się wykonać po inicjalizacji. Funkcja jako parametr dostaje stworzony obiekt
 * @option {Function} beforeRun (optional:null) callback (funkcja) jaka ma się wykonać przed uruchomieniem akci. Funkcja jako parametry dostaje obiekt akcji oraz parametry jego wywołania. Jeśli funkcja zwróci false, nie dojdzie do uruchomienia akcji
 * @option {Function} afterRun (optional:null) callback (funkcja) jaka ma się wykonać po uruchomieniu akcji. Funkcja jako parametry dostaje obiekt ajaxa, obiekt akcji, parametry wywołania akcji oraz informację czy żądanie przebiegło pomyślnie
 *
 * @see AjaxAction
 * @example 
 * function runAction(objLink){
 * var obj = ActionsManager.setup({
 * 	guid : 'basic', 
 * 	link : 'example.php?ex=basic', //link do akcji
 * 	title : 'Przykładowa akcja', //główny tytuł okna
 * 	titleRunning : 'Przykładowa akcja w toku...' //tytuł okna podczas trwania akcji
 * });
 * //Pobranie pozycji linka. Zmienna objLink jest obiektem DOM naszego wciśniętego linka
 * var lPos = Mixed.getPosition(objLink);
 * //ustawienie okienka pod linkiem
 * obj.element.style.left = lPos.x + 'px';
 * obj.element.style.top = lPos.y + 20 + 'px'; 
 * }
 * @desc Pierwszy banalny przykład. Odpalenie akcji, która coś tam robi. Ustawiamy okienko pod linkiem akcji.
 * @html
 * <a onclick="runAction(this);return false;" href="">Kliknij tu by rozpocząć przykładową akcję</a>
 * @htmlex
 * <a onclick="runAction(this);return false;" href="">Kliknij tu by rozpocząć przykładową akcję</a>
 * <div style="margin-top: 150px;"></div>
 * <script type="text/javascript">
 * function runAction(objLink){
 * var obj = ActionsManager.setup({
 * 	guid : 'basic', 
 * 	link : 'example.php?ex=basic',
 * 	title : 'Przykładowa akcja', //główny tytuł okna
 * 	titleRunning : 'Przykładowa akcja w toku...' //tytuł okna podczas trwania akcji
 * });
 * //Pobranie pozycji linka. Zmienna objLink jest obiektem DOM naszego wciśniętego linka
 * var lPos = Mixed.getPosition(objLink);
 * //ustawienie okienka pod linkiem
 * obj.element.style.left = lPos.x + 'px';
 * obj.element.style.top = lPos.y + 20 + 'px'; 
 * }
 * </script>
 * 
 * @example function runPreviewAction(id, objLink){
 * //id - id podglądu (może to być np. id rekordu)
 * var obj = ActionsManager.setup({
 * 	guid : 'preview'+id, //dzięki unikalnemu guid, pogląd dla danego rekordu będzie odbywał się w innym oknie
 * 	link : 'linkdoakcji',
 * 	closeLastOpened : true, //zamykamy ostatnio otwarte okno, byśmy naraz widzieli tylko jeden podgląd
 * 	refresh : false, //jeśli dany podgląd już raz sie wykonał, ponowme otwarcie jego okna nie odświerzy go 
 * 	                 //(dla danego rekordu będzie tylko jedno żądanie na serwer)
 * 	title : 'Podgląd',
 * 	titleRunning : 'Pobieranie danych...',
 * 	type : 'html', //spodziewamy się danych zwrotnych jako html
 * 	params : {id : id} //wraz z żądaniem na serwer, wysyłamy id rekordu
 * 	});
 * //Pobranie pozycji linka. Zmienna objLink jest obiektem DOM naszego wciśniętego linka
 * var lPos = Mixed.getPosition(objLink); //korzystamy z klasy Mixed
 * //ustawienie okienka obok linku. obj jest obiektem naszego okna
 * obj.element.style.left = lPos.x + 120 + 'px';
 * obj.element.style.top = lPos.y + 'px';
 * } 
 * @desc Typowa akcja podglądu. Może być wywoływana np. przy naciśnięciu liknu podglądu na gridzie
 * @html <a onclick="runPreviewAction(1, this);return false;" href="">Podgląd 1</a><br/>
 * <a onclick="runPreviewAction(2, this);return false;" href="">Podgląd 2</a><br/>
 * <a onclick="runPreviewAction(3, this);return false;" href="">Podgląd 3</a>
 * @htmlex 
 * <a onclick="runPreviewAction(1, this);return false;" href="">Podgląd 1</a><br/>
 * <a onclick="runPreviewAction(2, this);return false;" href="">Podgląd 2</a><br/>
 * <a onclick="runPreviewAction(3, this);return false;" href="">Podgląd 3</a>
 * <script type="text/javascript">
 * function runPreviewAction(id, objLink){
 * //id - id podglądu (może to być np. id rekordu)
 * var obj = ActionsManager.setup({
 * 	guid : 'preview'+id, //dzięki unikalnemu guid, pogląd dla danego rekordu będzie odbywał się w innym oknie
 * 	link : 'example.php?ex=preview',
 * 	closeLastOpened : true, //zamykamy ostatnio otwarte okno, byśmy naraz widzieli tylko jeden podgląd
 * 	refresh : false, //jeśli dany podgląd już raz sie wykonał, ponowme otwarcie jego okna nie odświerzy go 
 * 	                 //(dla danego rekordu będzie tylko jedno żądanie na serwer)
 * 	title : 'Podgląd',
 * 	titleRunning : 'Pobieranie danych...',
 * 	type : 'html', //spodziewamy się danych zwrotnych jako html
 * 	params : {id : id} //wraz z żądaniem na serwer, wysyłamy id rekordu
 * });
 * //Pobranie pozycji linka. Zmienna objLink jest obiektem DOM naszego wciśniętego linka
 * lPos = Mixed.getPosition(objLink); //korzystamy z klasy Mixed
 * //ustawienie okienka obok linku. obj jest obiektem naszego okna
 * obj.element.style.left = lPos.x + 120 + 'px';
 * obj.element.style.top = lPos.y + 'px';
 * } 
 * </script>
 * 
 * @example
 * function runSharedAction(id, objLink){
 * 	obj = ActionsManager.setup({
 * 	guid : 'actionshared', //wszystkie akcje w tym samym oknie poprzez nadanie tego samego guid
 * 	link : 'linkdoakcji', 
 * 	move : true, //dajemy możliwość przesuwania okienka
 * 	resize : {minWidth: 200,minHeight:60}, //pozwalamy na zmiane rozmiarów okna i określamy minimalne rozmiary
 * 	title : 'Akcja', //tytuł akcji
 * 	titleRunning : 'Trwanie akcji...',
 * 	allowRunRunning : false, //nie powalamy, by wykonywało się kilka akcji naraz
 * 	params : {id : id} //przekazujemy razem z żądaniem id akcji (rekordu)
 * });
 * //Pobranie pozycji linka. Zmienna objLink jest obiektem DOM naszego wciśniętego linka
 * lPos = Mixed.getPosition(objLink);
 * //ustawienie okienka pod linkami
 * obj.element.style.left = lPos.x + 'px';
 * obj.element.style.top = lPos.y + 20 + 'px';
 * }
 * @desc Kilka akcji wykonywać się będzie w tym samym oknie. Nie pozwalamy by w trakcie trwania jednej akcji, 
 * wykonywała się druga. Jeśli uruchomicie jedną akcję, szybko kliknijcie na inną, zanim ta pierwsza się skończy.
 * @html
 * <a onclick="runSharedAction(1, this);return false;" href="">Akcja 1</a>
 * <a onclick="runSharedAction(2, this);return false;" href="">Akcja 2</a>
 * <a onclick="runSharedAction(3, this);return false;" href="">Akcja 3</a> 
 * @htmlex
 * <a onclick="runSharedAction(1, this);return false;" href="">Akcja 1</a>
 * <a onclick="runSharedAction(2, this);return false;" href="">Akcja 2</a>
 * <a onclick="runSharedAction(3, this);return false;" href="">Akcja 3</a>
 * <div style="margin-top: 150px;"></div>
 * <script type="text/javascript">
 * function runSharedAction(id, objLink){
 * 	obj = ActionsManager.setup({
 * 	guid : 'actionshared', //wszystkie akcje w tym samym oknie poprzez nadanie tego samego guid
 * 	link : 'example.php?ex=shared', 
 * 	move : true, //dajemy możliwość przesuwania okienka
 * 	resize : {minWidth: 200,minHeight:60}, //pozwalamy na zmiane rozmiarów okna i określamy minimalne rozmiary
 * 	title : 'Akcja', //tytuł akcji
 * 	titleRunning : 'Trwanie akcji...',
 * 	allowRunRunning : false, //nie powalamy, by wykonywało się kilka akcji naraz
 * 	params : {id : id} //przekazujemy razem z żądaniem id akcji (rekordu)
 * });
 * //Pobranie pozycji linka. Zmienna objLink jest obiektem DOM naszego wciśniętego linka
 * lPos = Mixed.getPosition(objLink);
 * //ustawienie okienka pod linkami
 * obj.element.style.left = lPos.x + 'px';
 * obj.element.style.top = lPos.y + 20 + 'px';
 * }
 * </script>
 * 
 * @example
 * function runRemoveAction(id, objLink){
 * obj = ActionsManager.setup({
 * 	guid : 'actionremove', //wszystkie akcje w tym samym oknie
 * 	link : 'link do akcji',
 * 	move : true,
 * 	resize : {minWidth: 200,minHeight:60},
 * 	center : true, //okno ustawimy w centrum
 * 	title : 'Akcja usuwania',
 * 	titleRunning : 'Usuwam...',
 * 	closeAfterSuccess:true,//zamknij okno gdy akcja się powiedzie
 * 	allowRunRunning : true, //powalamy, by wykonywało się kilka akcji naraz
 * 	params : {id : id}, //przekazujemy razem z żądaniem id akcji (rekordu),
 * 	objLink : objLink //przekazujemy nasz parametr (objekt linku), który później wykorzystamy
 * });
 * }
 * @desc Kilka akcji usuwania wykonywać się będzie w tym samym oknie. 
 * Tym razem pozwalamy na uruchomienie jednoczesne kilku akcji. Dodatkowo, po pomyślnym zakończeniu akcji, 
 * usuniemy link, który wciśnięto by uruchomić akcję. Akcja 1 i 3 zakończą się pomyślnie (zostanie wówczas zamknięte okno), 
 * natomiast akcja 2 kończyć będzie się błędem. Po odświerzeniu strony linki znowu się pojawią, 
 * gdyż nie usuwam ich na stałe.
 * @html
 * <a onclick="runRemoveAction(1, this);return false;" href="">Akcja 1</a>
 * <a onclick="runRemoveAction(2, this);return false;" href="">Akcja 2</a>
 * <a onclick="runRemoveAction(3, this);return false;" href="">Akcja 3</a>
 * @htmlex
 * <a onclick="runRemoveAction(1, this);return false;" href="">Akcja 1</a>
 * <a onclick="runRemoveAction(2, this);return false;" href="">Akcja 2</a>
 * <a onclick="runRemoveAction(3, this);return false;" href="">Akcja 3</a>
 * <div style="margin-top: 150px;"></div>
 * <script type="text/javascript">
 * function runRemoveAction(id, objLink){
 * obj = ActionsManager.setup({
 * 	guid : 'actionremove', //wszystkie akcje w tym samym oknie
 * 	link : 'example.php?ex=remove',
 * 	move : true,
 * 	resize : {minWidth: 200,minHeight:60},
 * 	center : true, //okno ustawimy w centrum
 * 	title : 'Akcja usuwania',
 * 	titleRunning : 'Usuwam...',
 * 	closeAfterSuccess:true,//zamknij okno gdy akcja się powiedzie
 * 	allowRunRunning : true, //powalamy, by wykonywało się kilka akcji naraz
 * 	params : {id : id}, //przekazujemy razem z żądaniem id akcji (rekordu),
 * 	objLink : objLink, //przekazujemy nasz parametr (objekt linku), który później wykorzystamy
 * 	'afterRun' : function(ajaxObj,obj, params, resultOk){
 * 		if (resultOk && obj.getResult(ajaxObj) == '0'){
 * 			params.objLink.parentNode.removeChild(params.objLink);
 * 		}	
 * 	}
 * });
 * }
 * </script>
 * @memberOf ActionsManager
 * @id setup
 * @return {AjaxAction} Obiekt akcji
 */
ActionsManager.setup = function(params){
	function pd(name, def) { if (typeof params[name] == "undefined") { params[name] = def; }; };
	
	pd("closeLastOpened", false);
	pd("closeAfterSuccess", false);
	pd("className", 'actionsManager');
	pd("title", '');
	pd("titleRunning", null);
	pd("params", null);
	pd("attachParams", null);
	pd("method", 'post');
	pd("refresh", true);
	pd("toggle", false);
	pd("clear", true);
	pd("allowRunRunning", false);
	pd("type", 'xml');
	pd("messagesAddingType", 'last');
	if (!ActionsManager.beforeSetup(params)) return null;
	if (typeof params.beforeSetup != 'undefined' && !params.beforeSetup(params)) return null;
	if (typeof ActionsManager.objects[params.guid] == "undefined" || !ActionsManager.objects[params.guid]){
		ActionsManager.objects[params.guid] = new AjaxAction(params);
		ActionsManager.create(ActionsManager.objects[params.guid]);
		ActionsManager.objects[params.guid].afterSetup();
		if (typeof params.afterSetup != 'undefined') params.afterSetup(ActionsManager.objects[params.guid]);
		ActionsManager.run(ActionsManager.objects[params.guid],params);
	} else {
		if (params.refresh){
			canRun = ActionsManager.canRun(params);
			if (canRun != true){
				ActionsManager.objects[params.guid].afterSetup();
				if (typeof params.afterSetup != 'undefined') params.afterSetup(ActionsManager.objects[params.guid]);
				ActionsManager.runningErrorInfo(params, canRun);
			}	
			else {
				if (params.clear)
					ActionsManager.objects[params.guid].clear();
				ActionsManager.objects[params.guid].params = params;
				ActionsManager.objects[params.guid].afterSetup();
				if (typeof params.afterSetup != 'undefined') params.afterSetup(ActionsManager.objects[params.guid]);	
				ActionsManager.run(ActionsManager.objects[params.guid], params);
			};
		} else {
			ActionsManager.objects[params.guid].afterSetup();
			if (typeof params.afterSetup != 'undefined') params.afterSetup(ActionsManager.objects[params.guid]);
		}	
	};
	return ActionsManager.objects[params.guid];	
};

/**
 * Wgrywa pluginy
 * 
 * @param {String} plugins Lista pluginów oddzielonych przecinkiem, np: dynamic,position
 */
ActionsManager.loadPlugins = function(plugins){
	if (!plugins) return false;
	var plugins = plugins.split(','),plugin,script;
	var shead = document.getElementsByTagName("head")[0];
	var pLength = plugins.length;
	for(ilp=0;ilp<pLength;ilp++) {
		plugin = plugins[ilp].replace(/^\s+/, '').replace(/\s+$/, '');
		if (typeof ActionsManager.loadedPlugins[plugin] == 'undefined'){
			ActionsManager.loadedPlugins[plugin] = true;
			script = document.createElement( 'script' );
			script.type = 'text/javascript';
			script.src = ActionsManager.pluginsPath + 'ActionsManager_'+plugin+'.js';
			shead.appendChild(script);
		};
	};
};

ActionsManager.pluginsPath = 'scripts/plugins/';
ActionsManager.loadedPlugins = {};

ActionsManager.txtClose = 'Zamknij';
ActionsManager.txtRunning = 'Akcja w toku i nie można jej ponownie urochomić. Proszę czekać na zakończenie.';

/**
 * Ostatnio otwarte okienko
 * 
 * @type {AjaxAction}
 */
ActionsManager.lastOpened = null;

/**
 * Obiekt zawierający utworzone obiekty akcji.
 * 
 * @type {object}
 */
ActionsManager.objects = {};

/**
 * Metoda wywoływana przed inicjalizacją okna
 * 
 * @param {Object} params Parametry wywołania
 * @return {Boolean} jeśli zostanie zwrócony false, okienko się nie otworzy i akcja nie zostanie wykonana
 */
ActionsManager.beforeSetup = function(params){
	if (params.closeLastOpened)
		ActionsManager.hide(ActionsManager.lastOpened);
	return true;
};

/**
 * Mówi czy można uruchomić akcję. Defacto sprawdza, czy akcja nie jest przypadkiem w toku
 * 
 * @param {Object} params Parametry wywołania akcji
 * @return {Boolean, String} 
 * - false - nie można uruchomić akcji
 * - String - nie można uruchomić akcji. Zwrócony tekst jest tekstem do wyświetlenia
 * - true - można uruchomić akjcę 
 */
ActionsManager.canRun = function(params){
	var aacrObject = ActionsManager.getObject(params.guid);
	if (!aacrObject) return false;
	return aacrObject.running && !params.allowRunRunning ? false : true;
};

/**
 * Wyświetla informację o trwaniu akcji. 
 * Metoda jest wywoływana, gdy próbujemy uruchomić akcję, która jest już uruchomiona
 * @param {Object} params Parametry wywołania akcji
 * @param {String} errorText Tekst do wyświetlenia
 */
ActionsManager.runningErrorInfo = function(params, errorText){
	if (typeof errorText != 'string')
		errorText = ActionsManager.txtRunning;
	ActionsManager.objects[params.guid].addMessage(errorText,'error');
};

/**
 * Tworzy DOM okienka akcji
 * 
 * @param {AjaxAction} aaObject Obiekt akcji
 * @return {Boolean}
 */
ActionsManager.create = function(aaObject){
	var parentObj = document.getElementsByTagName("body")[0];
	aaObject.element = Mixed.createElement('div', parentObj, null, 'pm'+aaObject.params.guid, aaObject.params.className);
	aaObject.objects.header = Mixed.createElement('div', aaObject.element, aaObject.params.title, null, 'amHeader');
	
	aaObject.objects.wait = Mixed.createElement('div', aaObject.objects.header, null, null, 'amWait');
	aaObject.objects.close = Mixed.createElement('div', aaObject.objects.header, null, null, 'amClose');
	aaObject.objects.close.title = ActionsManager.txtClose;
	aaObject.objects.close.onclick = function(){
		ActionsManager.hide(aaObject);
	};
	aaObject.objects.container = Mixed.createElement('div', aaObject.element, null, null, 'amContainer');
	aaObject.objects.errors = Mixed.createElement('div', aaObject.objects.container, null, null, 'amErrors');
	aaObject.objects.messages = Mixed.createElement('div', aaObject.objects.container, null, null, 'amMessages');
	aaObject.objects.content = Mixed.createElement('div', aaObject.objects.container, null, null, 'amContent');
	if ( jQuery && jQuery.fn.bgiframe )
		jQuery(aaObject.element).bgiframe();	
};

/**
 * Niszczy podany obiekt
 * 
 * @param {AjaxAction} aaObject
 */
ActionsManager.destroy = function(aaObject){
	if (!aaObject) return;
	var parentObj = document.getElementsByTagName("body")[0];
	parentObj.removeChild(aaObject.element);
	ActionsManager.objects[aaObject.params.guid] = null;
};
/**
 * Wysyła żądanie do serwera w celu uruchomienia akcji
 * 
 * @param {AjaxAction} aaObject Obiekt akcji
 * @param {Object} params Parametry obiektu. Duplikowane jest ten parametr, gdyż może zdarzyć się sytuacja, gdzie aaObject.params!=params 
 * @return {Boolean} false, gdy akcja nie zostanie uruchomiona
 */
ActionsManager.run = function(aaObject,params){
	if (!aaObject.beforeRun()) return false;
	if (typeof params.beforeRun != 'undefined' && !params.beforeRun(aaObject, params)) return false;
	aaObject.countRunning++;
	aaObject.showHideWait(true);
	aaObject.root = null;
	aaObject.running = true;
	aaObject.setTitle(params.titleRunning);
	if (params.attachParams && jQuery){
		var par = ActionsManager.getParams(params.attachParams);
		if (par != null){
			if (aaObject.params.params != null)
				jQuery.extend(aaObject.params.params, par);
			else	
				aaObject.params.params = par;
		}
	}
	ActionsManager.ajaxRun(aaObject, params);
	return true;
};

ActionsManager.getParams = function(objForm){
	var p = objForm.find(':input');
	var params = {};
	var are = false;
	p.each(function(){
		var j = jQuery(this);
		var v = j.val();
		if (v == null)	return;
		var n = j.attr('name');
		if (j.is(':checkbox') || j.is(':radio')){
			if (!j.is(':checked'))
				return;
		}
		if (typeof v == 'object'){
			var ar = new Array();
			jQuery.each(v, function(i,iv){
				ar.push(v);
			});
		}
		if (typeof params[n] != 'undefined'){
			if (typeof params[n] != 'object'){
				var tv = params[n];
				params[n] = new Array();
				params[n].push(tv);
			}
			params[n].push(v);
		} else {
			params[n] = v;
			are = true;
		}	
	});
	
	return are ? params : null;
}


/**
 * Ukrywa podane okienko
 * 
 * @param {AjaxAction} aaObject
 */
ActionsManager.hide = function(aaObject){
	if (!aaObject) return false;
	if (typeof aaObject == 'string')
		aaObject = ActionsManager.getObject(aaObject);
	if (!aaObject) return false;
	aaObject.element.style.display = 'none';
};

/**
 * Pokazuje podane okienko
 * 
 * @param {AjaxAction} aaObject
 */
ActionsManager.show = function(aaObject){
	if (!aaObject) return false;
	aaObject.element.style.display = 'block';
};

/**
 * Zwraca obiekt o zadanym guid
 * @param {String} guid Identyfikator obiektu
 * @return {AjaxAction} Zwraca obiekt akcji
 */
ActionsManager.getObject = function(guid){
	if (typeof ActionsManager.objects[guid] == "undefined")
		return null;
	return ActionsManager.objects[guid];
};

/**
 * Pobiera tekst z podane znacznika. Pobiera z tylko pierwszego znalezionego
 * 
 * @param {Object} ajaxObj obiekt wyniku
 * @param {String} tagName nazwa znacznika
 */
ActionsManager.getText = function(ajaxObj, tagName){
	var root = Mixed.getRoot(ajaxObj, 'actionsmanager');
	if (!root) return null;
	var text = root.getElementsByTagName(tagName);
	if (text && text.length>0)
		return Mixed.getText(text.item(0));
	return null;
};

/**
 * @classDescription Klasa akcji
 * @param {object} params Obiekt z parametrami
 * @constructor
 */
function AjaxAction(params){
	this.params = params;
	this.position = {};
	this.objects = {};
	this.running = false;
	this.countRunning = 0;
};

/**
 * Metoda wywoływana po inicjalizacji obiektu
 */
AjaxAction.prototype.afterSetup = function(){
	if (this.params.toggle && this.element.style.display == 'block'){
		ActionsManager.hide(this);
		return true;
	}
	this.setZIndex();
	ActionsManager.show(this);
	ActionsManager.lastOpened = this;
};

/**
 * Metoda wywoływana przed uruchomieniem akcji. 
 * 
 * @return {Boolean} jeśli zostanie zwrócony false, akcja się nie wykona
 */
AjaxAction.prototype.beforeRun = function(){
	return true;
};

/**
 * Metoda wywoływana po odebraniu wyniku akcji
 * 
 * @param {Object} ajaxObj Obiekt wyniku
 * @param {Object} params Parametry obiektu. Duplikowany jest ten parametr, gdyż może zdarzyć się sytuacja, gdzie this.params!=params 
 * @param {Boolean} resultOk czy pobrano poprawnie
 */
AjaxAction.prototype.afterRun = function(ajaxObj,params, resultOk){
	if (resultOk)
		this.write(ajaxObj, params);
	this.countRunning--;
	if (this.countRunning == 0){
		this.showHideWait(false);
		if (params.titleRunning != null)
			this.setTitle(params.title);
		if ((params.closeAfterSuccess || typeof params.closeAfterSuccess == 'number') && resultOk && this.getResult(ajaxObj) == '0'){
			if (typeof params.closeAfterSuccess == 'number'){
				setTimeout("ActionsManager.hide('"+params.guid+"')",params.closeAfterSuccess);
			} else {
				ActionsManager.hide(this);
			}
		}	
		
	};	
	this.running = false;
	if (typeof params.afterRun != 'undefined') params.afterRun(ajaxObj, this, params, resultOk);
};

/**
 * Ustawia tytuł okienka
 * 
 * @param {String} title Tytuł do ustawienia
 */
AjaxAction.prototype.setTitle = function(title){
	if (title == null) return true;
	var tn = document.createTextNode(title);
	if (this.objects.header.firstChild != this.objects.wait)
		this.objects.header.replaceChild(tn, this.objects.header.firstChild);
	else	
		this.objects.header.insertBefore(tn, this.objects.wait);
};


/**
 * Ustawia dla danego obiektu zindex o jeden większy od ostatnio zmienianego
 */
AjaxAction.prototype.setZIndex = function(){
	if (typeof ActionsManager.zindex == "undefined")
		ActionsManager.zindex = 1000;
	ActionsManager.zindex++;	
	this.element.style.zIndex = ActionsManager.zindex;
};


/**
 * Pokazuje/ukrywa diva z ikoną czekania
 * 
 * @param {Boolean} show Czy pokazać
 */
AjaxAction.prototype.showHideWait = function(show){
	this.objects.wait.style.display = show ? 'block' : 'none'; 
};
/**
 * Pobiera wynik akcji
 * 
 * @param {Object} obj Obiekt ajaxa
 * @param {Object} params Parametry obiektu. Duplikowany jest ten parametr, gdyż może zdarzyć się sytuacja, gdzie this.params!=params 
 * @return {Boolean}
 */
AjaxAction.prototype.write = function(obj, params){
	eval('this.write'+this.params.type.toUpperCase()+'(obj, params);');		
		
};
/**
 * Pobiera wynik akcji jako XML
 * 
 * @param {Object} obj Obiekt ajaxa
 * @param {Object} params Parametry obiektu. Duplikowany jest ten parametr, gdyż może zdarzyć się sytuacja, gdzie this.params!=params 
 * @return {Boolean}
 */
AjaxAction.prototype.writeXML = function(obj, params){
	var root = Mixed.getRoot(obj, 'actionsmanager');
	if (!root) return false;
	this.writeMessages(root, 'error', this.objects.errors);
	this.writeMessages(root, 'message', this.objects.messages);
	
	var content = root.getElementsByTagName('content');
	if (content && content.length>0){
		content = Mixed.getText(content.item(0));
		if (content)
			this.objects.content.innerHTML += content;
	};
	
	return true;
};

/**
 * Pobiera wynik akcji jako HTML
 * 
 * @param {Object} obj Obiekt ajaxa
 * @param {Object} params Parametry obiektu. Duplikowany jest ten parametr, gdyż może zdarzyć się sytuacja, gdzie this.params!=params 
 * @return {Boolean}
 */
AjaxAction.prototype.writeHTML = function(obj, params){
	if (!obj || !obj.responseText) return false;
	this.objects.content.innerHTML += obj.responseText;
	return true;
};

/**
 * Pobiera rezultat akcji z roota. 
 * Należy wywoływać tylko wtedy, gdy spodziewamy się wyniku w postaci xml
 * 
 * @param {Object} ajaxObj Obiekt jaki zwraca ajax
 * @return {String, null} 
 *  - 0 - akcja zakończona sukcesem
 *  - innystring - akcja zakończona niepowodzeniem. Może to być numer błędu lub komunikat błędu
 *  - null - zapewne niepoprawny xml
 */
AjaxAction.prototype.getResult = function(ajaxObj){
	var grroot = Mixed.getRoot(ajaxObj, 'actionsmanager');
	if (!grroot) return null;
	return grroot.getAttribute('result');
};

/**
 * Pobierze z xmla wiadomości/błędy
 * @param {DOM} root Nasz root
 * @param {String} type Typ wiadomośći (error, message)
 * @param {DOM} divMessage Obiekt diva, do którego wpisać wiadomośći
 */
AjaxAction.prototype.writeMessages = function(root, type, divMessage){
	var messages = root.getElementsByTagName(type);
	if (messages && messages.length>0){
		var messagesLength = messages.length, _msg;
		if (!divMessage.firstChild)
			Mixed.createElement('ul',divMessage);
		for (i=0;i<messagesLength;i++){
			_msg = messages.item(i);
			messageText = Mixed.getText(_msg);
			if (messageText)
				Mixed.createElement('li', divMessage.firstChild,messageText,null,null,null,(this.params.messagesAddingType == 'first'));
		};
	};
};

/**
 * Dodaje wiadomość/błąd
 * 
 * @param {String} message Wiadomość/błąd
 * @param {Object} type Typ wiadomości (message, error)
 */
AjaxAction.prototype.addMessage = function(message, type){
	var divM;
	if (!type || type == 'message')
		divM = this.objects.messages;
	else	
		divM = this.objects.errors;
	if (!divM.firstChild)
		Mixed.createElement('ul',divM);
	Mixed.createElement('li', divM.firstChild,message, null,null,null,(this.params.messagesAddingType == 'first'));
};

/**
 * Czyści okienko akcji 
 */
AjaxAction.prototype.clear = function(){
	if (this.objects.errors.firstChild)
		this.objects.errors.removeChild(this.objects.errors.firstChild);
	if (this.objects.messages.firstChild)
		this.objects.messages.removeChild(this.objects.messages.firstChild);
	this.objects.content.innerHTML = '';	
};