/***********************************************************************
 * ajax.js
 *
 * Otávio Ribeiro <otavio.ribeiro@w21.com.br> @ 2006
 *
 * Javascript code to be used with ajax applications
 ***********************************************************************/

function ajax_object_from_xml(node, nodeStr){
	var tmpNodes = node.childNodes;
	var obj = new Object();
	for(i=0; i < tmpNodes.length; i++){
		if(tmpNodes[i].nodeType==1 && tmpNodes[i].nodeName == nodeStr){
			var tmpChildNodes = tmpNodes[i].childNodes;
			for(j=0;j < tmpChildNodes.length; j++){
				if(tmpChildNodes[j].nodeType == 1){
					eval("obj."+tmpChildNodes[j].nodeName+"= tmpChildNodes[j].firstChild.nodeValue");
				}
			}
			break;
		}
	}
	return obj;
}




/***********************************************************************
 * Function: function ajax_get_form_values(forms,validade)
 *
 * input: form     - a form object
 *        validate - a validate function that will be called for every 
 *                   processed field.
 *
 * output: A string encoded to post the values using ajax post method
 ***********************************************************************/
function ajax_get_form_values(forms,validade)
{
    var str = ""; 
    for(var i = 0;i < forms.elements.length;i++) {
        switch(forms.elements[i].type){
            case "text":
            case "hidden":
            case "textarea":
	    case "password":
                if(validade != null){
                    validade.validadeForm(forms.elements[i].name, forms.elements[i].value);
                }
                str += forms.elements[i].name + "=" + escape(forms.elements[i].value) + "&";
                break;
                
            case "select-one":
                if(validade != null){
                    validade.validadeForm(forms.elements[i].name, forms.elements[i].options[forms.elements[i].selectedIndex].value);
                }
                str += forms.elements[i].name + "=" + escape(forms.elements[i].options[forms.elements[i].selectedIndex].value) + "&"; 
            	break;    
            	
            case "checkbox":
                if(forms.elements[i].checked){
                	str += forms.elements[i].name + "=" + escape(forms.elements[i].value) + "&";
                }	
            	break;
            	
            case "radio":
                if(forms.elements[i].checked){
                    str += forms.elements[i].name + "=" + escape(forms.elements[i].value) + "&";
                }    
            	break;	
            	
            case "select-multiple":
            	var j = 0;
            	for(j = 0; j < forms.elements[i].options.length; j++){
            	    if(forms.elements[i].options[j].selected){
            	        str += forms.elements[i].name + "=" + escape(forms.elements[i].options[j].value) + "&"; 
            	    }
            	}
            	break;
            	
            default:
            	//alert('tipo n?o conhecido: ' + forms.elements[i].type);
            	break;
        }
    }
    
    return str;
}

/*
 * timer object, this will hold an instance to our ajax class object and will control
 * all the timer operation
 */
var ajax_self = null;

/***********************************************************************
 * Function: function ajax_back_check(){
 *
 * input: nothing
 *
 * output: nothing
 *
 * description: timer function to check url changes. When this function
 *              detect that the URL changes it will check on our stack 
 *              for the related function and call it to rebuild the page.
 *
 *              The main goal of this function is to workarround the ajax 
 *              back button insues.
 *              
 ***********************************************************************/
 function ajax_back_check(){

    var classe = ajax_self;
    
    var strLocation = "";
    var index = 0;
    
    if(classe.isIE()){
        try{
            strLocation = classe.iframe.contentWindow.document.getElementById('ajax_back_div').innerHTML;
	} catch(E){
	}    
    } else {
        strLocation = window.location.hash;
    }    
    
    index = strLocation.indexOf('stack-');
    
    if(index > 0){
    
        strLocation = strLocation.substring(index,strLocation.length);
        
	if(!classe.checkEnabled && strLocation == classe.lastMark){
	    classe.checkEnabled = 1;
	    setTimeout("ajax_back_check()",400);
	    return;
	}    

	if(!classe.checkEnabled) {
	    setTimeout("ajax_back_check()",400);
	    return;
	}
	
        if(strLocation != classe.lastMark){
        
            var pos = strLocation.substring(6,strLocation.length)
            
            classe.lastPos = pos;
            
            classe.back = 1;
            
            classe.lastMark = strLocation;
            
            if(classe.isIE()){
                document.location.hash=classe.lastMark;
            }
	    
            eval(classe.stack[pos]);
        }
    }
    setTimeout("ajax_back_check()",400);
}


/***********************************************************************
 * Function: function ajax_control(loading, url)
 *
 * input: loading - a string with the URL to the loading page. Will be 
 *                  used to present a loading frame when waiting for some
 *                  operation.
 *
 *        url     - Prefix that will be used on ajax requests. Usualy will
 *                  be the website domain.
 *
 * output: nothing
 *
 * description: Construct a new object of the "ajax_control" type.
 *
 * example: 
 *
 *    var ajax = new ajax_control("/inc/loading.html","http://mydomain.com");
 *              
 ***********************************************************************/
function ajax_control(loading, url)
{
    this.ajax_default_loading_page = loading;
    this.ajax_url_prefix = url;
    
    /** IE **/
    if(this.isIE()){
       document.write("<iframe style='border: 0px; width: 0px; "
                               + "height: 0px; position: absolute; bottom: 0px; "
                               + "right: 00px; visibility: visible;' "
                               + "name='ajax_back_frame' id='ajax_back_frame_id' "
                               + "src='blank.html'>"
                               + "</iframe>");
    
        this.iframe = document.getElementById("ajax_back_frame_id");
	
        this.currentWait = 400;
    } else {
        this.currentWait = 200;
    }
    
    /** back control **/
    this.stack = new Array();
    this.lastPos = -1;
    this.lastMark = "";
    this.checkEnabled = 1;
    this.back = 0;
}

ajax_control.prototype.init_timer = function(){
    ajax_self = this;
    setTimeout("ajax_back_check()", 400);
}

/***********************************************************************
 * Function: function create_http_request()
 *
 * input: nothing
 *
 * output: a XMLHttpRequest object
 *
 * description: Cross browser function to create an XMLHttpRequest object.
 *
 * example: 
 *
 *    var ajax = new ajax_control("/inc/loading.html","http://mydomain.com");
 *    var request = ajax.create_http_request();
 *              
 ***********************************************************************/
ajax_control.prototype.create_http_request = function()
{
    var xmlhttp=false;
    
    if(window.XMLHttpRequest){
        try{
            xmlhttp = new XMLHttpRequest();
        } catch(e){
            xmlhttp = false;
        }
    } else if(window.ActiveXObject){
        try{
            xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");
        } catch (E) {
            try {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (E) {
                xmlhttp = false;
            }
        }
    } else {
        xmlhttp = false;
    }
    
    if(!xmlhttp)
        alert("ajax nao suportado");
    
    return xmlhttp;
}

/**
 * INTERNAL FUNCTION ONLY
 **/
ajax_control.prototype.isIE = function()
{
    var str = navigator.userAgent.toLowerCase();
    if(str.indexOf("msie") > 0)
        return true;
	
    return false;
}

/***********************************************************************
 * Function: function get_xml(xmlRequest,file,listener)
 *
 * input: xmlRequest - XMLHttpRequest object
 *        file       - file that will be called
 *        backCall   - an object with a function property "onResponse"
 *
 * output: nothing
 *
 * description: Will make a call to the file and after completion will call
 *              the onResponse method from the listener object.
 *
 * example: 
 *
 *    var ajax = new ajax_control("/inc/loading.html","http://mydomain.com");
 *    var request = ajax.create_http_request();
 *
 *    var listener = new Object();
 *    listener.onResponse = function(){
 *        alert("your code here");
 *    }
 *
 *    ajax.get_xml(request,"/pages/list.jsp?id=100",listener);
 *              
 ***********************************************************************/
ajax_control.prototype.get_xml = function(xmlRequest,file,listener)
{
    
    //Inicia a chamada do arquivo XML
    xmlRequest.onreadystatechange = listener.onResponse;
    xmlRequest.open("GET",this.ajax_url_prefix + file, true);
    xmlRequest.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
    xmlRequest.setRequestHeader("Cache-Control", "no-cache");
    xmlRequest.send(null);
}


/***********************************************************************
* Function: function get_xml_and_wait(xmlRequest,file)
*
* input: xmlRequest - XMLHttpRequest object
* file - file that will be called
*
* output: nothing
*
* description: Will make a call to the file and will wait for a response
*
* example:
*
* var ajax = new ajax_control("/inc/loading.html","http://mydomain.com");
* var request = ajax.create_http_request();
*
* ajax.get_xml(request,"/pages/list.jsp?id=100");
*
* //response will be valid at this point
*
***********************************************************************/
ajax_control.prototype.get_xml_and_wait = function(xmlRequest,file)
{
//Inicia a chamada do arquivo XML
xmlRequest.open("GET",this.ajax_url_prefix + file, false);
xmlRequest.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
xmlRequest.setRequestHeader("Cache-Control", "no-cache");
xmlRequest.send(null);
}

/***********************************************************************
 * Function: function post_xml(xmlRequest,file,parameters,listener)
 *
 * input: xmlRequest - XMLHttpRequest object
 *        file       - file that will be called
 *        parameters - post parameters to send
 *        backCall   - an object with a function property "onResponse"
 *
 * output: nothing
 *
 * description: Will make a call to the file and after completion will call
 *              the onResponse method. The parameters will be posted to the file.
 *
 * example: 
 *
 *    var ajax = new ajax_control("/inc/loading.html","http://mydomain.com");
 *    var request = ajax.create_http_request();
 *
 *    var listener = new Object();
 *    listener.onResponse = function(){
 *        alert("your code here");
 *    }
 *
 *    var params = ajax_get_form_values(document.myForm,NULL)
 *
 *    ajax.post_xml(request,"/pages/list.jsp",params,listener);
 *              
 ***********************************************************************/
ajax_control.prototype.post_xml = function(xmlRequest,file,parameters,listener)
{
    //Inicia a chamada do arquivo XML
    xmlRequest.onreadystatechange = listener.onResponse;
    xmlRequest.open("POST",this.ajax_url_prefix + file, true);
    xmlRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlRequest.setRequestHeader("Content-length", parameters.length);
    xmlRequest.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
    xmlRequest.setRequestHeader("Cache-Control", "no-cache");
    xmlRequest.send(parameters);
}

/***********************************************************************
 * Function: function load_xml(xml)
 *
 * input: xml - A XML string to be parsed
 *
 * output: a DOMParser object
 *
 * description: Cross browser function to create a DOMParser object from a
 *              XML string.
 *              
 ***********************************************************************/
ajax_control.prototype.load_xml = function(xml)
{
    var obj=null;
    var isMoz=false;
    var isIE=false;
        
	try{//to get the mozilla parser
		obj = new DOMParser();
		isMoz=true;
	}catch(e){
		try{//MS XML parser
			obj = new ActiveXObject("Msxml2.DomDocument.4.0"); 
			isIE=true;
		}catch(e){
			try{//MS XML parser
				obj = new ActiveXObject("Msxml2.DomDocument"); 
				isIE=true;
			}catch(e){
				try{//MS XML parser mais velho
					obj = new ActiveXObject("microsoft.XMLDOM"); 
					isIE=true;
				}catch(e){
					alert('Erro ao criar parser XML');
				}
			}
		}
	}
	
    try{
		if(isMoz){
			obj = obj.parseFromString(xml, "text/xml");
			return obj;
		}else if(isIE){
			obj.loadXML(xml);
			return obj;
		}
	}catch(e){
		alert('Erro ao ler XML');
	}	
	return null;
}

/***********************************************************************
 * Function: function load_javascript(url)
 *
 * input: url - Will dynamically load the javascript file pointed by this
 *              URL
 *
 * output: nothing
 *
 * description: Will be used to dynamically load a javascript file
 *
 * example: 
 *
 *    var ajax = new ajax_control("/inc/loading.html","http://mydomain.com");
 *    ajax.load_javascript("/js/user.js");
 *
 ***********************************************************************/
ajax_control.prototype.load_javascript = function(url)
{
    var xmlRequest = this.create_http_request();
     	
    var listener = new Object();
    listener.onResponse = function(){
        if(xmlRequest.readyState == 4){
            eval(xmlRequest.responseText);
     	}
    };
    
    var tmpUrl = url;
    tmpUrl += "?" + Math.random();
    this.get_xml(xmlRequest,tmpUrl,listener);
}


/***********************************************************************
 * Function: function init_loading(content,lock)
 *
 * input: content - div object to put the loading content
 *        lock    - just to make sure that the loading content will not
 *                  be changed after the original content be presented.
 *
 * output: nothing
 *
 * description: Will change the div content with the loading content.
 *              The lock object must have the status property set to 0.
 *              After the real content has been received the status must be
 *              changed to 1 to prevent this function to replace it.
 *
 * example: 
 *
 *    TODO
 *
 ***********************************************************************/
ajax_control.prototype.init_loading = function(content,lock)
{
    var xmlRequest = this.create_http_request();
	
    var listener = new Object();
    listener.onResponse = function(){
        if(xmlRequest.readyState == 4 && lock.status == 0){
            content.innerHTML = xmlRequest.responseText;
        }	
    }; 
    
    this.get_xml(xmlRequest,this.ajax_default_loading_page,listener);
}

/**
 * INTERNAL FUNCTION ONLY
 **/
ajax_control.prototype.back_control_clean = function(pos){
    var total = this.stack.length;

    for(i = total-1; i > pos; i--){
        this.stack.pop();
    }
}

/***********************************************************************
 * Function: function add_mark(chamada)
 *
 * input: chamada - the string representation for the load function.
 *
 * output: nothing
 *
 * description: add a bookmark to this function at our stack. when the
 * fuck user click at the browser back button the function "chamada" will 
 * be called to setup that content again.
 *
 * example: 
 *
 *    TODO
 *
 ***********************************************************************/
ajax_control.prototype.add_mark = function(chamada){

    var name = null;
    var add = true;
    
    if(this.back){
        this.back = 0;
        return;
    }
    
    if(this.lastPos < this.stack.length-1 && !this.back)
        this.back_control_clean(this.lastPos);
    
    if(this.lastPos >= this.stack.length || this.stack[this.lastPos] != chamada){
    
        this.checkEnabled = 0;
            
        var pos = this.stack.length;
        this.lastPos = pos;
        
        name="stack-"+pos;
        this.lastMark=name;
        
        this.stack.push(chamada);
        
        var self = this;
        
        var execute = function(){
            if(self.isIE()){
    	        //self.iframe.src = "blank.html?"+self.lastMark;
		self.iframe.contentWindow.location.href = "/ajax/ajax.asp?show="+self.lastMark;
            }
            window.location.hash = self.lastMark;
        };
        
        setTimeout(execute, this.currentWait)
    }
    
    return name;
}