// (C)opyright OpenJaw Technologies 2007
// $Header: /usr/local/cvsroot/IBE/web/static/common/scripts/ajax.js,v 1.3 2010/03/02 17:01:52 stevec Exp $

//This is a shortcut to retrieve an element
function $(id){
    return document.getElementById(id);
}

//Submits the form specified using AJAX and loads the result in the div with the id specified
//The parameter onCompleted is code that will be executed after the call is completed (success or fail)
// It can be a function reference or a string with code
function submitForm(form, divId, onCompleted) {
    var postData = generateAttributeValue(form);
    postToURL(form.action, postData, divId, onCompleted);
    return false;
}

//Loads the given url in the specified div
//The parameter onCompleted is code that will be executed after the call is completed (success or fail)
// It can be a function reference or a string with code
function loadDiv(url, divId, onCompleted) {
    getFromURL(url, divId, onCompleted);
    return false;
}



function evalJavascript(responseText){
    do {    
        //This variable is used for the search to be case insensitive
        var lresponseText = responseText.toLowerCase();

        var scriptOpenTagStartPos = lresponseText.indexOf("<script");
        var scriptOpenTagEndPos = lresponseText.indexOf(">", scriptOpenTagStartPos);
        var scriptCloseTagStartPos = lresponseText.indexOf("</script", scriptOpenTagEndPos);
        
        //It's important that the substring uses the original string, not the lowercased        
        var js = responseText.substring(scriptOpenTagEndPos + 1, scriptCloseTagStartPos);
    
        if(scriptOpenTagStartPos != -1 && scriptCloseTagStartPos != -1){
            //Execute the code inside
            eval(js);
            //Check if the script source if somewhere else
            var scriptOpenTagEndPos = responseText.indexOf(">", scriptOpenTagStartPos);
            var src = getScriptSrc(responseText.substring(scriptOpenTagStartPos, scriptOpenTagEndPos));
            if (src != null){
                addScriptLink(src);
            }
            
            //We are done with the current script block
            responseText = responseText.substring(scriptCloseTagStartPos + 1);
        }
    } while(scriptCloseTagStartPos != -1);
}

//Links that current page with the external script source specified
function addScriptLink(src){
    scriptElem = document.createElement('script');
    scriptElem.setAttribute('src', src);
    scriptElem.setAttribute('type', 'text/javascript');
    document.body.appendChild(scriptElem);
}

//Retrieves the value of the "src" attribute attribute in the tag string
// or null if the tag doesn't contain that attribute
function getScriptSrc(tag){
    var result = null;
    var srcIndex = tag.indexOf("src");
    if (srcIndex != -1){
        var eqIndex = tag.indexOf("=", srcIndex);
        
        //The attribute may be defined with quotes or apostrophes
        var aposStart = tag.indexOf("'", eqIndex);
        var quotStart = tag.indexOf('"', eqIndex);
            
        if (aposStart != -1 && (quotStart == -1 || aposStart < quotStart)){
            var aposEnd = tag.indexOf("'", aposStart + 1);
            result = tag.substring(aposStart + 1, aposEnd);
        } else  if (quotStart != -1 && (aposStart == -1 || quotStart < aposStart)){
            var quotEnd = tag.indexOf('"', quotStart + 1);
            result = tag.substring(quotStart + 1, quotEnd);
        }
    }
    return result;
}

// Request counter used to generate one unique parameter for getFromURL().
var reqCounter = 1;

//Only one Ajax request can be active at a time
var request = null;

//This parameter is used to inform the server this is an ajax call
//It should be sent will all Ajax calls. 
//The server response to this calls should be the MIME text/xml so the 
//XMLHttpRequest parses the response as a XML that can be handled
var ajaxParameter = "ajaxCall=true";

//This is the id of the error messages div. If it is present in the page then 
// the errors loaded when the form is submited instead of the hole div.
//This way the values of the pages are not lost
var errorMessageDivID = "errorMessages";

//This array is a stack of pending callbacks
//New callbacks are appended at the end of the array and the last ones are the
// first to be executed and removed from the array
var pendingCallbacks = new Array();

//This function is not meant to be called directly. Use loadDiv() instead
function getFromURL(sURL, divId, onCompleted) {
    if (request != null){
        return; //The previous request is not done yet
    }
    if (sURL.indexOf('?') == -1){
        sURL = sURL + '?';
    } else {
        sURL = sURL + '&';
    }
    sURL = sURL + ajaxParameter;
    
	//Show the spinner
	showFilterSpinner(divId);

  // We add a bogus parameter to the end of the URL string to
  // ensure that the data at the given URL is reloaded (not cached).
  // The ActiveX object has no way of turning off caching.
    reqCounter = reqCounter + 1;
    sURL = sURL+"&RequestCounter="+reqCounter;
    var html = '';
   
    if(divId != null || onCompleted != null) {
      request = new XMLHttpRequest();
      if (request) {
          request.onreadystatechange = function() {ajaxCallback(divId, onCompleted);}
          request.open("GET", sURL, true);
          request.send(null);        
      }
    } else {
      if (window.XMLHttpRequest) {
      request = new XMLHttpRequest();
      } 
      else if (window.ActiveXObject){
      request = new ActiveXObject("Microsoft.XMLHTTP");
      }
      if (request){
        request.open("GET", sURL, false);
        request.send(null);
        if (request.status == 200){
          html = request.responseText;
        } else {
          html = 'Error: ' + request.status + ' ' + request.statusText;
        }
      }
      return html;
    }     	
}

//This function is not meant to be called directly. Use submitForm() instead
function postToURL(sURL, postBody, divId, onCompleted) {	
    if (request != null){
        return; //The previous request is not done yet
    }
	
	//Show the spinner
	showFilterSpinner(divId);
	
    request = newXMLHttpRequest();
    if (request) {
        request.onreadystatechange = function() {ajaxCallback(divId, onCompleted);}
        request.open("POST", sURL, true);
        request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;');
        request.send(postBody);        
    }  			
}

function ajaxCallback(divId, onCompleted){
    if (request.readyState==4) {
        var loadDiv;
        var resultStr;
        if (request.status==200){
            var newLoc = request.getResponseHeader("Location");
            //Check if a redirection was instructed
            if (newLoc != null && newLoc.length > 0) {
                window.location = newLoc;
                return;
            }
    
            resultStr = request.responseText;            
            var errorDiv = $(errorMessageDivID);
            if (errorDiv != null){
                loadDiv = checkErrorMsgInResponse(errorDiv, resultStr);
            } else {
                loadDiv = true;
            }
            if (loadDiv && divId != ''){
        		if(resultStr.indexOf('|') > 0) {
        		    $(divId).innerHTML = resultStr.substr(0, resultStr.indexOf('|'));
        		}
        		else {
        		    $(divId).innerHTML = resultStr;
        		}
            }
        }
        request = null;
		
        //Hide the spinner
		hideFilterSpinner(divId);
		
        //Run Javascript code loaded into the div
        if (loadDiv && resultStr != null){
    	    if(resultStr.indexOf('|') > 0) {
    		evalJavascript(resultStr.substr(resultStr.indexOf('|')+1));
    	    }
    	    else {
    		evalJavascript(resultStr);
    	    }
        }
        //If the code just evaluated issues an Ajax request we
        // enque the "onComplete" callback until this request is done
        if (onCompleted != null && request != null){        
            pendingCallbacks[pendingCallbacks.length] = onCompleted;
        } else {
            executeCallback(onCompleted);
        }
        //Check if we have a pending callback
        if (request == null && pendingCallbacks.length > 0){
            //Execute the last callback added to the stack
            var callback = pendingCallbacks[pendingCallbacks.length - 1];
            executeCallback(callback);
            //Remove the callback from the stack
            pendingCallbacks.length = pendingCallbacks.length - 1; 
        }
    }
}

//Executes the code given wether it is a function reference
// or a string with the code to run.
function executeCallback(callback){
    if (callback == null || callback == 'undefined'){
        return;
    }
    var typeOf = typeof(callback);
    switch(typeOf){
        case 'function': 
            callback();
            break;
        case 'string':
            eval(callback);
            break;             
    }
}

//Checks if the error response contains an error messages div and 
// it contains errors. In that case the errors are loaded in the main document
// and false is returned to signal that no further load is needed.
//Otherwise returns true to signal that the ajax call should load the result 
function checkErrorMsgInResponse(errorDiv, resultStr){
    var result = true; 

    //Load the html in a temporary element that won't be appended don't the document
    var container = document.createElement("container");
    container.innerHTML = resultStr;
    var divs = container.getElementsByTagName('div');
    if (divs != null){
        for (var i=0; i<divs.length; i++) {
            var div = divs.item(i);
            if (div == null){
                continue;
            }
            if (div.id != null && div.id == errorMessageDivID){
                //Check if the error div contains errors
                if (div.hasChildNodes()) {
                    //Check if the operation was successfull
                    var child = div.childNodes.item(0);
                    if (child.id != 'success'){
                        var parent = errorDiv.parentNode;
                        parent.replaceChild(div, errorDiv);
                        result = false;
                    }
                }
            } 
        }
    }
    container = null;

    return result;
}

function newXMLHttpRequest(){
    if (window.XMLHttpRequest){
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        return new ActiveXObject("Microsoft.XMLHTTP");
    }
    return null;
}

function generateQueryString(formId) {
    return formId.action + generateAttributeValue(formId);
}

function generateAttributeValue(formId) {
    var qString = ajaxParameter;
    for(j=0; j<formId.elements.length; j++) {
        var formObj = formId.elements[j];
        //some elements don't have a type - embedded objects, fieldsets...
        if(formObj.type){
            var formType = formObj.type.toLowerCase();
            if( (formType == "text") || (formType=="hidden") 
                || (formType=="textarea") || (formType=="password") ) {
                    qString = qString+"&"+formObj.name+"="+encodeURIComponent(formObj.value);
            } else if (formType=="checkbox") {
                qString = qString+"&"+formObj.name+"="+encodeURIComponent(formObj.checked);
            } else if (formType=="radio") {
                if (formObj.checked) {
                    qString = qString+"&"+formObj.name+"="+encodeURIComponent(formObj.value);
                }
            } else if(formType.substring(0,6) == "select") {
                if (formType.indexOf ("multiple") != -1) {
                    qString = qString+"&"+formObj.name+"=";
                    for (i =0; i < formObj.options.length; i++) {
                        if (formObj.options[i].selected == true) {
                            qString = qString+encodeURIComponent(formObj.options[i].value)+"|";
                        }
                    }
                } else {
                    var index = formObj.selectedIndex;
                    if (index != -1){
                        qString = qString+"&"+formObj.name+"="+encodeURIComponent(formObj.options[index].value);
                    }
                }
            }
        }
    }         
    return qString;
}


function hideFilterSpinner(id) {
    document.getElementById(id).style.opacity = '1';
}

function showFilterSpinner(id)
{
    document.getElementById(id).style.opacity = '0.5';
}
