/* Copyright (c) 2010 CRMSoftware Piotr Głodzik piotr.glodzik@crmsoftware.pl
 * --------------------------------------------------
 * Armazon, version 0.2.5
 * Data utworzenia pliku: 2010-05-11
 * Ostatnia modyfikacja:  2010-08-08
 *
 * Framework javascript Armazon jest integralną częścią Frameworka Armazon dla PHP
 * Jednym właścielem praw autorkich i majątkowych do kodu składającego się na Framework Armazon jest Piotr Głodzik.
 * Rozpowszechnianie kodu, korzystanie z niego w celach niekomercyjnych, oraz komercyjnych bez zgody i wiedzy autora
 * jest zabronione.
 */
(function(window){
	
	/**
	 * Argumentem moze być string - id elementu do pobrania, lub gotowy obiekt
	 * Jeżeli obiekt został pobrany to go zwraca powiększonego o dodatkowe metody
	 * Jeżeli nie, to zwraca null
	 */
	var Arm = function (i) {
			
		if(i){			
			// Jeżeli Arm jest wywoływana z zewnątrz, to this wskazuje na window
			var o=this.A.getO(i);
			// Do pobranego elementu przypisuję wszystkie właściwości prototypu Arm
			// Niestety normalnym sposobem nie da się tego przypisac jako prototyp obiektu w IE, bo IE elementy DOM traktuje inaczej
			if(o!=null){
				for(var p in Arm.prototype ) {
				
					// Ale tylko wtedy, kiedy takiej właściwości jeszcze nie ma							
					if (( typeof o[p])=='undefined') {										
						//x.__proto__[p] = Arm.prototype[p];
						o[p] = Arm.prototype[p];
					}
				}
			}
			return o;					
		}
				
		return null;		
	}

	Arm.prototype = {
			
			ver : '0.2.5',
			
			/**
			 * Pobiera obiekt. Jeżeli argumentem był string, to getElementById, jeżeli obiekt, to zwraca ten sam obiekt
			 * Jeżeli nie było argumentu, to zwraca null
			 */
			getO : function(i) {
				var t=typeof i;					
				if(t=='string')return document.getElementById(i);				
				if(t=='object')return i;
				throw'A.getO: Bad parameter type';
			},
			
			/**
			 * Dodaje event do obiektu
			 * @param object/string i
			 * @param string t
			 * @param function f 
			 */
			addEvent : function(i,t,f) {		    					
				var o = this.getO(i);		       		                
		        o.attachEvent?o.attachEvent('on'+t,function(){f.call(o,window.event)}):o.addEventListener(t,f,false);		        		        		        		        		        		        
		    },	
		    
		    // Usuwa eventa
		    removeEvent : function(i,t,f) {		    	
		    	var o = this.getO(i);
		    	o.detachEvent?o.detachEvent('on'+t,function(){f.call(o,window.event)}):o.removeEventListener(t,f,false);		    	
		    	
		    },		    		    
			    
		    /**
		     * Dodaje eventa - metoda stosowana w odniesieniu bezpośrednio do obiektu
		     * t - zdarzenie do jakiego przypisać listenera
		     * f- funkcja eventListener
		     * n - nazwa własciwości obiektu, do którego będzie przypisany eventListener, w której będzie referencja do anonimovegoEventListenera
		     * o - dowolne parametry przekazywane do funkcji eventListener
		     */
		    aE : function(t,f,n,o) {		    	
		    	var c=this;
		    	if(this.attachEvent){		    		
		    		function x(){f.call(c,window.event,o)};
		    		(function(h){h.attachEvent('on'+t,x)}(this));		    				    		
		    		eval('this.'+n+'=x');
		    	}else{eval('this.'+n+'=function (event){f.call(c,event,o)}');this.addEventListener(t,eval('this.'+n),false)}		    			    			    	
		    	return this;
		    },
		    
		    /**
		     * Usuwa eventa - metoda stosowana w odniesieniu bezpośrednio do obiektu
		     * e - zdarzenie dla którego usuwać listenera
		     * f - funkcja do usunięcia
		     */		    
		    rE : function(t,f) {		    	
		    	this.detachEvent?this.detachEvent('on'+t,f):this.removeEventListener(t,f,false);
		    },
		    
		    /**
		     * Pobiera target dla eventa
		     */
		    gET : function(e) {		    	
		    	return e.target||e.srcElement;
		    },
		    
		    /**
		     * Wyłącza zaznaczanie elementu
		     */
		    pS : function() {		    			    	
		    	
		    	this.aE('mousedown', function(e){if (e.preventDefault)e.preventDefault()} ); //Moz,Opera		    	
		    	this.aE('selectstart',function(e){e.returnValue = false});// IE
		    	
		    },		    
		    /**
		     * Metoda ustawia właściwości obiektu, na wartości domyślne, oraz sprawdza, czy są ustawiane wymagane parametry.
		     * Jeżeli parametr nie jest ustawiony, to metoda rzuca wyjątek.
		     * Obiekt z definijami wartości domyślnych ma postać:
		     * { nazwaWlasciwosci : { reguired : true/false, def : wartość_domyślna/null } 
		     * @param object
		     * @param defaultObject
		     * @return object
		     */
		     sD : function( obj, defObject ) {
		     
		        var i,x;
		        // Iteruję po obiekcie z definicjami
		        for( i in defObject ) {
		            
		            // Jeżeli iterowany parametr jest wymagany
		            if ( defObject[i].required == true ) {
		                                
		                // Sprawdzam, czy parametr zostal podany
		                // Jeżeli nie, to rzucam wyjątek                                
		                if ( !obj[i] ) {
		                                    
		                    throw 'Armazon.setDefault: Missing required parameter: ' + i;
		                }
		                
		            } else { // Jezeli nie jest wymagany
		                
		                // Ustawiam go na wartosc domyslna, jezeli jest null
		                if( obj[i] == null ) {
		                
		                    obj[i] = defObject[i].def;
		                    
		                }
		            }
		        }
		        
		        return obj;
		     },
		     
		     /**
		      * Metoda składa poststringa.
		      * Jej działanie polega na tym, że z parametru pstr, który jest tablicą
		      * pobiera identyfikatory pól input, następnie pobiera z tych pól
		      * ich wartości i nazwy i składa ciąg, który można wysłać metodą send obiektu HttpRequest
		      * @param Array f
		      * @return string
		      */
		     pStr : function ( f ) {
		             
		             for(var i=0;i<f.length;i++ ) {
		                 // encodeURIComponent musi tutaj być ze względów bezepieczeństwa oraz
		                 // dlatego że jeżeli za pomocą POST wyślę AJAXEm znak plusa, to dostanę spację
		                 f[i]=this.getO(f[i]).name + '=' + encodeURIComponent(this.getO(f[i]).value);
		             }        
		                     
		             return f.join('&')
		             
		     },
		              		     		     		    
		    /**
		     * Ajax
		     * Funkcja jako parametr przyjmuje pojednyczy obiekt, którego własnościami mogą być:
		     * - 'url' (default: window.location.href) Adres gdzie wysłać zapytanie
		     * - 'serviceFunc' function (default: null) referencja do Funkcji obsługi po otrzymaniu danych
		     * - 'serviceFuncWait' function (default: null) referencja do funkcji obsługi podczas pobierania danych
		     * - 'method' string POST lub GET (default GET)
		     * - 'async' boolean czy zapytanie asynchroniczne true/false (default true)
		     * - 'pStr' string wpostaci param_name=param_value&param1_name=param1_value do wysłania postem, jeżeli pstr jest podany
		     *   jako tablica, to string post jest składany z wartości pól, których id są przekazane w tej tablicy
		     * - 'mimeType' - typ mime jaki ma być zasosowany do overrida (default text/xml)
		     * - 'param' (null) dowolny parametr, służący jako bufor np do przekazywania zmiennych do funkcji
		     *    obsługi
		     * Klasa wywołując zapytanie przedstawia się nagłówkiem X-User-Agent: ArmazonEasyAjax, co pozwala rozróżnić zapytanie od zapytań
		     * wysłanych za pomocą mechanizmów samej przeglądarki lub innych. Przydatne jeżeli np. przy logowaniu trzba wysłać dane XML, 
		     * lub zawartość HTML.
		     * 
		     * Obiekt przekazywany jako parametr jest podczas wykonania zapytania wzbogacany o kilka właściwości:
		     * - text
		     * - XML
		     * - responseHeaders
		     * - statusText
		     * - status
		     * a następnie przekazywany jako parametr do funkcji obsługi wait i po ready
		     */
		     aGet : function(ob) {
		    	 		    	 
		    	 // this tutaj to nasz Arm
		    	 // Domyślne właściwości obiektu
		    	 var dP = { url             : { required : false, def : window.location.href },
		    	            serviceFunc     : { required : false, def : null },
		    	            serviceFuncWait : { required : false, def : null },
		    	            method          : { required : false, def : 'GET' },
		    	            async           : { required : false, def : true },
		    	            pStr            : { required : false, def : '' },		    	               
		    	            mimeType        : { required : false, def  : 'text/xml' },
		    	            param           : { required : false, def : null }
		    	           };
		    	    
		    	 // Ustawienie wartości domyślnych
		    	 try { var o = this.sD(ob,dP) } catch (ex) {alert( 'Exception: '+ex.message );return} 		           
		    	 			    	 
		    	 // Request		    	 		         		    	    		    	   
		    	 var hr = false;
		    	 if (window.XMLHttpRequest) { // Mozilla, Safari,...
		    		 
		    	    hr = new XMLHttpRequest();
		    	    
		    	    if (hr.overrideMimeType) {		    	               
		    	        hr.overrideMimeType(o.mimeType);		    	        
		    	    }
		    	    		    	    
		    	 } else if (window.ActiveXObject) { // IE
		    		 try {hr = new ActiveXObject("Msxml2.XMLHTTP");} catch (e) {try {
		    			 hr = new ActiveXObject("Microsoft.XMLHTTP");
		    	 } catch (e) {}}}
		    	 
		    	if(!hr){throw'I can\'t make xmlHttpRequest object'}
		    			    			    	 		    			    	
		    	hr.onreadystatechange = function() {		    				    		
		    					    				    			    		
		    		if (hr.readyState == 4) {
		    			
		    			if (hr.status == 200) {
		    		
		    				// to powinno być zrobione inaczej - do funkcji obsługi powinny być przekazywane przynjmniej dwa parametry
		    				// o - zewnętrzny
		    				// r - odpowiedź http
		    				// powinno być tak zrobione ze względnu na możliwość nadpisania (poniżej) właściwości parametru o przekazanego z zewnątrz
		    				o.text=hr.responseText;
		    				o.XML=hr.responseXML;
		    				o.responseHeaders=hr.getAllResponseHeaders();
		    				o.statusText=hr.statusText;
		    				o.status = hr.status;
		    			
		    				o.serviceFunc(o);
		    	   
		    			} else alert('Wystąpił problem z zapytaniem xmlHttp');
		    			
		    		}else{
		    			
		    			o.serviceFuncWait(o);
		    		}
		    		
		    	}
		    	
		    	// Uwaga, tutaj jest ważna kolejność. Metoda open musi zostać wywołana przed nadpisaniem nagłówka
		    	hr.open(o.method,o.url,o.async);
		    	// Jeżeli dane mają zostać wysłane metodą POST, to trzeba nadpisać nagłówek
		    	if(o.method=='POST')hr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		    	// Dla odróżnienia po stronie serwera czy żądanie przyszło ajaxem, czy też nie, trzeba się ładnie przedstawić
		    	// TODO: Wartość X-User-Agent powinna zostać sparametryzowana w ten sposób, żeby można było ją konfigurować z zewnątrz
		    	hr.setRequestHeader('X-User-Agent', 'ArmazonEasyAjax' );

		    	hr.send((o.pStr!=null &&(typeof o.pStr=='object'))?this.pStr(o.pStr):o.pStr);
		    			    	
		     },
		    
		    
		    /**
		     * Funkcja pozwala na testowanie odwołań do funkcji frameworka
		     */
		    aT : function(s) {
		    	alert(s);
		    },
		    
		     /**
		      * Metoda usuwa wszystkie pozycje option z selecta.
		      * @param string
		      */
		     cO : function(s) {		    	  
		    	var o;
		    	o=s?this.getO(s):this;		    			    			    
		    	if(o && o.nodeName=='SELECT') {		    				    		
		    		for(var i=o.options.length;i>=0;i--){
		    			o.options[i] = null;
		    		}
		    	} else {
		    		throw(o + 'is not an select element')
		    	}
		     },
		     
		     /**
		      * Metoda otwierająca nowe okno
		      * Jako parametr przyjmuje obiekt, którego właściwościami mogą być:      
		      * Parametry, które normlanie przyjmuje metoda window.open
		      * string url [Domyślnie:'']      
		      * string name [Wymagany]
		      * string toolbar [Domyślnie:no]
		      * string menubar [Doyślnie:no]
		      * string location [Domyślnie:no]
		      * string status [Domyślnie:no]
		      * string scrollbars [Domyślnie:no]
		      * string resizable [Domyślnie:no]
		      * string directories [Domyślnie:no]
		      * string copyhistory[Domyślnie:no]
		      * integer height [Wymagany]
		      * integer width [Wymagany]
		      * integer left [Domyślnie:0]
		      * integer top [Domyślnie:0]
		      * @param object      
		      */
		      nW : function (ob) {
		    		    	 
		        // Właściwości domyślne		    
		        var dP = { url :  { required : false, def : ''},
		                   name : { required : true, def : null },
		                   toolbar : { required : false, def : 'no' },
		                   menubar : { required : false, def : 'no' },
		                   location : { required : false, def : 'no' },
		                   status : { required : false, def : 'no' },
		                   scrollbars : { required : false, def : 'no'},
		                   resizable : { required : false, def : 'no' },
		                   direcotries : { required : false, def : 'no' },
		                   copyhistory : { required : false, def : 'no' },
		                   height : { required : true, def : null },
		                   width : { required : true, def : null },
		                   left : { required : false, def : 0 },
		                   top : { required : false, def : 0 } };
		        
		        
		    	 try { var o = this.sD(ob,dP) } catch (ex) { alert( 'Exception: '+ex.message );return } 		           
		    	 		     
		         return window.open(o.url,o.name,'toolbar='+o.toolbar+',menubar='+o.menubar+',location='+o.location+',status='+o.status+',scrollbars='+o.scrollbars+',resizable='+o.resizable+',directories='+o.direcories+',copyhistory='+o.copyhistory+',height='+o.height+',width='+o.width+',left='+o.left+',top='+o.top);
		         
		         //return;
		                 
		      }
		      
			
	}

	// This tutaj wskazuje na obiekt window
	// Teraz w dalszych częściach mamy dostępny gotowy obiekt A, z którego możemy wykorzystywać wszystkie funkcje i właściwości
	this.A = new Arm();
	// A to pozwala nam, na prototypowanie obiektów na zewnątrz za pomocą: Arm.prototype
	this.Arm = Arm;
	
}(window));

// W tym miejscu mamy gotowy dostępny obiekt A, który jest naszym frameworkowym narzędziem.



