/*	Copyright © 2008 eXtraMile Web Development. All Rights Reserved.
	FreedomJS - http://www.freedomjs.org
	Date: September 11, 2008
	File Name: ajax.js
	***LEAVE THIS COMMENT HEAR
	Terms of Use: http://www.freedomjs.com/terms.php	*/

//1. ADD FILE UPLOAD
//2. TEST & DEBUG
//3. RELEASE
var ajaxRef = 0;
var ajaxCurrent = new Array();
var ajax = new freedomAjax();
//CLASS: AJAX
function freedomAjax(){
	//PUBLIC PROPERTIES:
	this.update = 0;
	this.formRef = null;		//referance to form
	this.headers = new Array();	//array of headers to include in the request
	this.recentRequest = null;	//stores the most recent request data or null
	this.addRefresh = true;		//[ON, off] - ensure that the page refreshes by adding a customajax.js varible to the url query string
	this.sendMethod = "GET";	//[GET, post] - set the way the data should be transmitted
	this.formAction = "";		//[url] - what page should the request be sent to
	this.actionUser = null;		//request url login username
	this.actionPassword = "";	//request url login password
	this.formData = "";			//form data from form
	this.finishHandler = null;	//[function to call onfinish] - what function should the result be sent to
	this.handlerData = "";		//varibles to pass to the handler
	this.onErrorHandler = null;	//function the error data should be sent to
	this.timer = null;			//automatically re-starts the request
	this.timerInterval = null;	//number of milliseconds between request

	//METHODS
    this.addRefresh = function(){
		if(!this.addRefresh) return "r=0"
		this.update++;
		return "update="+this.update;
	}
    this.getSymbol = function(sUrl){
		if(sUrl.indexOf('?') >= 0) return "&";
		else return "?";
	}
    this.replaceChars = function(string, char, newChar){
		var newString="";
		for(i=0;i<string.length;i++){
			if(string.charAt(i)==char)
				newString+=newChar;
			else
				newString+=string.charAt(i);
		}
		return newString;
	}
	this.splitFunction = function(strFunction){
		varStartIndex = strFunction.indexOf("(");
		strVar = "";
		if(varStartIndex == -1) return {name:strFunction, varibles:strVar};
		fName = strFunction.slice(0, varStartIndex);
		strVar = strFunction.slice(varStartIndex+1, strFunction.length-1);
		return {name:fName, varibles:strVar};
	}
	this.getXMLHttp = function(){
		var XMLHttp=null;
		if (window.XMLHttpRequest){
				XMLHttp=new XMLHttpRequest();
		}
		else if (window.ActiveXObject){
			try{
				XMLHttp=new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch(e){
				XMLHttp=new ActiveXObject("Microsoft.XMLHTTP");
			}
		}
		return XMLHttp;
	}
	this.uploadHttp = function(){
		//create iframe
		//submit form to iframe
		//return html
		//distory iframe
	}
	this.ajaxError = function(err, errMsg){
	   	var errHandler = splitFunction(this.onErrorHandler);
		eval(errHandler.name+"("+err+", "+errMsg+", "+errHandler.varibles+")");
	}
	//PUBLIC METHODS:
    this.startTimer = function(timeInt){
		if(typeof timeInt != "undefined") this.timerInterval = timeInt;
		this.timer = setTimeout("ajax.startRequest()", this.timerInterval);
	}
	this.stopTimer = function(){
		clearTimeout(this.timer);
	}
	this.getNameAndValue = function(sName, sValue){
		return {name:sName, value:sValue};
	}
	this.addHeader = function(sName, sValue){
		this.headers.push(this.getNameAndValue(sName, sValue));
	}
	this.contentType = function(sValue){
		var sName = "Content-type";
		if(this.headers.length == 0){
			var isExist = false;
		}
		else{
			var isExist = false;
			for(intVar in this.headers){
				header = this.headers[intVar];
				if(header.name == sName){
					header.value = sValue;
					isExist = true;
					break;
				}
			}
		}
		if(!isExist){
			this.addHeader(sName, sValue);
		}
	}
    this.getHeader = function(sName){
		for(intVar in this.headers){
			header = this.headers[intVar];
			if(header.name == sName) return header.value;
		}
	}
    this.sliceChars = function(string, start, end){
		//removes characters within a string and returns string
		var newString="";
		if(end==null){end=start;}
		for(i=0;i<string.length;i++){
			if(i<start||i>end)
			newString+=string.charAt(i);
		}
		return newString;
	}
	this.countInputsByName = function(name){
		var myCount = 0;
        var inputs = this.formRef.elements;
		for(i in inputs){
			input = inputs[i];
			if(name == input.getAttribute("name")) myCount++;
		}
		return myCount;
	}
	//GET DECENDENTS OF OBJECT BY TAGNAME
	this.decendents = new Array();
	this.getTagsByName = function(parentObj, tagsName){
		tagsName = tagsName.toUpperCase();
		var children = parentObj.childNodes;
		//loop through all direct children of parent
		for(var i=0;i<children.length;i++){
			//varify is valid dom object
			if(children[i].nodeType==1){
				//varify tagName and append object to array
				if(children[i].tagName==tagsName) this.decendents.push(children[i]);
				//recruisve function to get all decendents
				this.getTagsByName(children[i], tagsName);
			}
		}
		return this.decendents;
	}
	this.setupForm = function(replaceFormRef){
		//CLEAR CURRENT FORM DATA
		this.formData = "";
		//SET FORM REF
		if(replaceFormRef != undefined) this.formRef = replaceFormRef;
		//SET CONTENT TYPE
		if(this.formRef.enctype != undefined) this.contentType(this.formRef.enctype);
		//SET METHOD
		this.sendMethod = this.formRef.method.toUpperCase();
		if(this.sendMethod==null||this.sendMethod=="") this.sendMethod = "GET";
		//SET FORM ACTION
   		this.formAction = this.formRef.action;
		if(this.formAction==null||this.formAction=="") this.formAction = "";
		//SET RESULT HANDLER
		if(this.formRef.getAttribute("resultHandler") != null)
			this.finishHandler = this.formRef.getAttribute("resultHandler");
		//GET FORM DATA
        this.getTagsByName(this.formRef, "input");
        this.getTagsByName(this.formRef, "textarea");
        this.getTagsByName(this.formRef, "button");
		for(i in this.decendents){
			input = this.decendents[i];
			try{
				name = input.getAttribute("name"); value = input.value; type = input.type;
				if(!((type == "checkbox" || type == "radio") && !input.checked)){
					if(name != "" && name != null && value != "") this.formData += "&" + name + "=" + escape(value);
				}
			}
			catch(err){}
		}
		//REMOVE FIRST & CHAR
		this.formData = this.sliceChars(this.formData, this.formData.indexOf("&"));
	}
	this.startRequest = function(formRef){
		if(formRef != undefined) this.setupForm(formRef);
		//BUILD URL
		var urlBuild = this.formAction;
		var sendData = this.formData;
		//IF REQUEST TYPE IS FORM SUBMITTION
		if(this.formRef != null){
			if(this.getHeader("Content-type") == "multipart/form-data"){	//FILE UPLOAD FORM
				//multipart/form-data - file upload - use iframe
			}
			else if(this.sendMethod.toLowerCase() == "get"){
				urlBuild = urlBuild + this.getSymbol(urlBuild) + this.formData;
				urlBuild = urlBuild + this.getSymbol(urlBuild) + this.addRefresh();
		   		sendData = null;
			}
			else if(this.sendMethod.toLowerCase()=="post"){	//POST FROM
				sendData = sendData + "&" + this.addRefresh();
			}
		}
		else{ //IF REQUEST TYPE IS URL
			this.sendMethod = "GET";
			urlBuild = urlBuild + this.getSymbol(urlBuild) + this.addRefresh();
			sendData = null;
		}
		//BUILD XMLHTTP OBJECT
		xmlHttp=this.getXMLHttp();
		//SETUP XMLHTTP
		if(urlBuild == "") urlBuild = "#";
		if(this.actionUser != null) xmlHttp.open(this.sendMethod.toUpperCase(), urlBuild, true, this.actionUser, this.actionPassword);
		else xmlHttp.open(this.sendMethod.toUpperCase(), urlBuild, true);
		//ADD HEADERS
		//for(intVar in this.headers){
			//item = this.headers[intVar];
			//if(item != undefined) xmlHttp.setRequestHeader(item.name, item.value);
		//}//parseInt(this.ajaxRef)
		xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	    ajaxRef = ajaxCurrent.length + 1;
		ajaxCurrent[ajaxRef] = this;
		//SETUP FINISH ACTION
		xmlHttp.onreadystatechange = function(){ajaxCurrent[ajaxRef].stateChangedSubmit()};

		xmlHttp.send(sendData);
		return false; //stop form from normal execution
	}
	this.stateChangedSubmit = function(testItem){
		if(xmlHttp.readyState==4 || xmlHttp.readyState=="complete"){
			if(xmlHttp.status==404) this.ajaxError(xmlHttp.status, xmlHttp.statusText);
			else{ //status=200
				if(this.finishHandler != null && this.finishHandler != ""){
                    /*	this.finishHandler
						this.handlerData	*/
					//SAVE MOST RECENT REQUEST DATA
					this.recentRequest = xmlHttp.responseText;
					//PREP HANDLER CALL
					var finishHandlerData = this.splitFunction(this.finishHandler);
	   				handlerVaribles = finishHandlerData.varibles;
					if(this.handlerData != "") handlerVaribles + ", " + this.handlerData;
					if(this.handlerData != "") handlerVaribles = ", " + this.replaceChars(handlerVaribles, "`", "'");
					finishAction = finishHandlerData.name + "(xmlHttp.responseText" + handlerVaribles + ")";
					//RUN COMPLETED FUNCTION
					eval(finishAction);
				}
			}
		}
	}
    //CLASS CONSTRUCTOR
	this.constructor = function(){
		this.contentType("application/x-www-form-urlencoded");
	}
	this.constructor();
}