/**
* JSAX - JavaScript (Standard) Abstractions for X(HT)ML
*
* written by Florian Sax 20051229 <flosax(at)users.sourceforge.net>
* Copyright (C) 2005 Florian Sax
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
* 
* 
* You can also find the GPL at the following internet adress: <http://www.gnu.org/copyleft/gpl.html>
*
* @version: 20060626
*/
window.JSAX = {
	Version: 20060626,
/**
* JSAX.JSload - include and require for JavaScript ( uses JSAX.HTTP)
*
* @parent JSAX.JSload
*/
JSload: {
	dir: "",
	end: ".js",
/**
* JSAX.JSload.solvPath - This is a helper function for JSAX.JSload.require( fn).
*/
	solvePath: function( file){
		var file = file;
		if( file.indexOf( "?") == -1
		 && ( file.toLowerCase().indexOf( JSAX.JSload.end) == -1
		 || file.toLowerCase().lastIndexOf( JSAX.JSload.end) +JSAX.JSload.end.length != file.length)){
			file += JSAX.JSload.end;
		}
		if( JSAX.JSload.dir){
			if( JSAX.JSload.dir.lastIndexOf( "/") != JSAX.JSload.dir.length -1){
				JSAX.JSload.dir += "/";
			}
		}else{
			JSAX.JSload.dir = "./";
		}
		if( file.indexOf( JSAX.JSload.dir) != 0){
			file = JSAX.JSload.dir+file;
		}
		return file;
	},
/**
* This is a alias to JSAX.HTTP.request
*/
	read: function( file){
		return JSAX.HTTP.request( file, arguments[1], arguments[2], arguments[3]);
	},

/**
* JSAX.JSload.passthrew - Returnes the content of the requested file directly in the document
* NOTE that google is not able to do these actions.
* 
* @param String file - The file which should be pasted into the document
*/
	passthrew: function( file){
		JSAX.HTTP.request( file, "alert( ...); document.write( ...);");
	},

/**
* JSAX.JSload.execute - Execute JavaScript without failure
* 
* @param String code - The code which should be run.
* @param String file - The fileName which will be shown in the alert on a failure
*
* @return Boolean - True on success false on an error.
*/
	execute: function( code, file){
		try{
			eval( code);
		}catch( e){
			var correction = 82; // NOTE this must be set to this lineNumber
			var error = "Error";
			if( e.lineNumber){
				var line = e.lineNumber -correction -1;
				error += " on line "+line;
			}
			alert( error+" in file "+file+": "+e.message+"\n\n"+code);
			return false;
		}
		return true;
	},

/**
* JSAX.JSload.include - Include a JavaScript file.
* 
* @param String file - The path of the .js file (for example: include( "./myLib/myScript.js", "./myLib/myOtherScript.js"))
* @param String [file2] - The name of the 2. file
* @param String [file3] - ...
*
* @return String - The number of files which could be loaded without failure.
*/
	include: function( file){
//		var file = JSAX.JSload.solvePath( file);
		if( arguments.length > 1){
			var succeed = 0;
			for( var i=0; i < arguments.length; i++){
				if( JSAX.JSload.include( arguments[i])){
					succeed++;
				}
			}
			return succeed;
		}

		var code = JSAX.JSload.read( file);
		return JSAX.JSload.execute( code, file);
	},

	requiredFiles : [],
/**
* JSAX.JSload.require - Include a JSAX library once. this function has a pathcorrection.
*
* @param String file - The name of the JSAX object (for example: include( "proto/String"))
* @param String [file2] - The name of the 2. script
* @param String [file3] - ...
*
* @return String - The number of files which could be loaded without failure.
*/
	require: function( file){
		var file = JSAX.JSload.solvePath( file);
			var succeed = 0;
		if( arguments.length == 1 && typeof( arguments[0]) == "object"){
			arguments = arguments[0];
		}
		if( arguments.length > 1){
			for( var i=0; i < arguments.length; i++){
				if( JSAX.JSload.require( arguments[i])){
					succeed++;
				}
			}
			return succeed;
		}

		if( typeof( JSAX.JSload.requiredFiles[file]) != "string"){
			var content = read( file)
			JSAX.JSload.execute( content, file);
			JSAX.JSload.requiredFiles[file] = content;
			return ;
		}
		return true;
	}
},

/**
* JSAX.HTTP - file reading ( works only on the host of the HTML file wich this is on)
* This procedure is called Ajax
*
* @parent JSAX.HTTP
*/
HTTP: {

/**
* JSAX.HTTP - file reading ( works only on the host of the HTML file wich this is on)
* 
* @param String URL - The path to the file (or script)
* @param String [method] - The request method (GET or POST, default=GET) to send the data
* @param Array [data] - The request data ( as a HTMLform)
*
* @return String - The result of your request (file content, script result)



	function ajaxRequest(url, method, param, onSuccess, onFailure){
		var xmlHttpRequest = new XMLHttpRequest();
		xmlHttpRequest.onreadystatechange = function() {
			if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) onSuccess(xmlHttpRequest);
			else if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status != 200) onFailure(xmlHttpRequest);
		};
		xmlHttpRequest.open(method, url, true);
		if (method == 'POST') xmlHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		xmlHttpRequest.send(param);
	}
*/
	objects: [],
	request: function( URL, eva, method, data){
		if( !method){
			var method = "GET";
		}
		if( typeof( data) == "undefined"){
			var data = "";
		}
		var reqObj = JSAX.HTTP.requestObject();
		if( !reqObj){
			return false;
		}
		if( eva){ // asynchron
			if( typeof( eva) == "string"){
				var eva = eva;
				eva = eva.split( "...").join( "t.responseText")
				eva = eva.split( "this.").join( "t.responseText");
				eva = new Function( "t", eva);
			}
			var id = JSAX.HTTP.objects.length;
			JSAX.HTTP.objects[id] = [reqObj, eva, URL];
			reqObj.onreadystatechange = new Function( "JSAX.HTTP.respond( "+id+");");
			reqObj.open( method, URL, true);
//			reqObj.setRequestHeader("Content-type", "multipart/form-data");
			reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			reqObj.setRequestHeader("Content-length", data.length);
			reqObj.setRequestHeader("Connection", "close");
			reqObj.send( data);
//			alert( JSAX.HTTP.objects[id]);

//			JSAX.HTTP.respond( id);
			return true;
		}else{ // wait
			reqObj.open( method, URL, false);
			reqObj.send( data);
			return reqObj.responseText;
		}
	},
	states: {0:'Uninitialized', 1:'Loading', 2:'Loaded', 3:'Interactive', 4:'Complete'},
	statusCodes: {
		// 10X Informational
		100:'Continue',
		101:'Switching Protocols',
		// 20X Success
		200:'OK',
		201:'Created',
		202:'Accepted',
		203:'Non-Authoritative Information',
		204:'No Content',
		205:'Reset Content',
		206:'Partial Content',
		// 30X Redirection
		300:'Multiple Choices',
		301:'Moved Permanently',
		302:'Found',
		303:'See Other',
		304:'Not Modified',
		305:'Use Proxy',
		306:'Switch Proxy',
		307:'Temporary Redirect',
		// 4XX Client Error
		400:'Bad Request',
		401:'Unauthorized',
		402:'Payment Required',
		403:'Forbidden',
		404:'Not Found',
		405:'Method Not Allowed',
		406:'Not Acceptable',
		407:'Proxy Authentication Required',
		408:'Request Timeout',
		409:'Conflict',
		410:'Gone',
		411:'Length Required',
		412:'Precondition Failed',
		413:'Request Entity Too Large',
		414:'Request-URI Too Long',
		415:'Unsupported Media Type',
		416:'Requested Range Not Satisfiable',
		417:'Expectation Failed',
		// 50X Server Error
		500:'Internal Server Error',
		501:'Not Implemented',
		502:'Bad Gateway',

		// HTTP Extensions
		102:'Processing',

		207:'Multi-Status',

		418:'Im a Teapot',
		422:'Unprocessable Entity',
		423:'Locked',
		424:'Failed Dependency',
		425:'Unordered Collection',
		426:'Upgrade Required',
		449:'Retry With',

		506:'Variant Also Negotiates',
		507:'Insufficient Storage',
		509:'Bandwidth Limit Exceeded',
		510:'Not Extended'
	},

	respond: function( id){
		var reqObj = JSAX.HTTP.objects[id][0];
		if( !reqObj){
			alert( "hmmm..."); return;
		}
		if( reqObj.readyState == 0){
			alert( "failed to load URL( "+JSAX.HTTP.objects[id][2]+").");
		}
		if( reqObj.readyState == "1"){
//			setTimeout( "JSAX.HTTP.respond( "+id+");", 50);
			return;
		}
//		alert( JSAX.HTTP.states[reqObj.readyState]+" "+reqObj.URL);
		if( reqObj.readyState == 4){
			if( reqObj.status != 200){
				reqObj = { responseText: JSAX.HTTP.statusCodes[reqObj.status] };
			}
			var e = false;
			try{
//				alert( reqObj.readyState+":"+JSAX.HTTP.states[reqObj.readyState]);
				JSAX.HTTP.objects[id][1]( reqObj);
			}catch( e){
				alert( e.message);
			}
			if( !e){ // no error
//				reqObj.onreadystatechange = null;
				reqObj = null;
				JSAX.HTTP.objects[id] = null;// empty object on success
			}
		}
//		reqObj.onreadystatechange = null;
//		window.JSAX.HTTP.objects[id] = null;
	},
/**
* Internal helper function for JSAX.HTTP.request()
* @return Object - XMLHttpRequest request Object
*/
	requestObject: function(){
		if( typeof( XMLHttpRequest) != "undefined"){
			return new XMLHttpRequest();
		}else{ // M$IE
			var possible = new Array(
				"Microsoft.XMLHTTP",
				"Msxml2.XMLHTTP",
				"MSXML2.XMLHTTP.3.0",
				"MSXML2.XMLHTTP.4.0"
			);
			var reqObj = false;
			var done = false;
			for( var i=0; i < possible.length; i++){
				try{
					reqObj = new ActiveXObject( possible[i]);
					done = true;
				}catch( e){
					reqObj = false;
				}
				if( done){
					return reqObj;
				}
			}
		}
		return false;
	}
	
},
/**
* object handling helpers
* @parent JSAX.object
*/
object: {

/**
* JSAX.object.concat - Makes a new object of any number of objects, the first object is the most dominating. This function does not modify the given objects, it makes a copy.
* @param Object object1
* @param [Object object2]
* @return Object - Combined object of object1 and object2 ... where object2 has priority if a value exists in both objects.
*/
	concat: function( object1, object2){
		var newObj = new Object();
		for( var i = 0; i < arguments.length; i++){
			for( var child in arguments[i]){
				newObj[child] = arguments[i][child];
			}
		}
		return newObj;
	},
/**
* JSAX.object.glue - Makes a new object of any number of objects, the first object is the most dominating. This function does not modify the given objects, it makes a copy. This function is a alias of JSAX.object.concat
* @param Object object1
* @param [Object object2]
* @return Object - Combined object of object1 and object2 ... where object2 has priority if a value exists in both objects.
*/
	glue: function( object1, object2){
		return JSAX.object.concat( object1, object2);
	},
/**
* JSAX.object.attachTo - Assigns attach to target. This function has no return, the target object will be modified.
* @param Object attach - The object you wan to attach to the target (for example your prototype library).
* @param Object target - The target object. CAUTION: the original of this object will be modified.
* @return Object combined object of object1 and object2 where object2 has priority if a value exists in both objects.
*/
	attachTo: function( attach, target){
		for( var child in attach){
			try{
				target[child] = attach[child];
			}catch( e){}
		}
	}
},
/**
* container to gather prototype extensions
* @parent JSAX.proto
*/
proto: {}

};

// assign the main functions to window, so they are easy available
window.include		= JSAX.JSload.include;
window.require		= JSAX.JSload.require;
window.read		= JSAX.HTTP.request;

if( !JSAX.HTTP.requestObject()){
	alert( "Your browser does not support JavaScript HTTP reading!\nPlease download Firefox from 'http://www.mozilla.org/'.");
}

