// <license>BorgWorX PUBKLIC SOURCE LICENSE</license>
// <copyright>
// Portions Copyright (c) 2003-2005 SediSys Information Technologies, Ges.m.b.H. All Rights Reserved.
//
// This file contains Original Code and/or Modifications of Original Code
// as defined in and that are subject to the BorgWorX Public Source License
// Version 1.0 (the 'License'). You may not use this file except in
// compliance with the License. Please obtain a copy of the License at
// http://www.SediSys.com/BPL/ and read it before using this
// file.
//
// The Original Code and all software distributed under the License are
// distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
// EXPRESS OR IMPLIED, AND BorgWorX HEREBY DISCLAIMS ALL SUCH WARRANTIES,
// INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
// Please see the License for the specific language governing rights and
// limitations under the License.
// </copyright>
// <authors>
// Michael Schwarz <info@schwarz-interactive.de>
// </authors>
// <changes>
// Christian Hubinger <chubinger@sedisys.com>
// 4.10.2005 - fix type error with non existing data
// 5.10.2005 - remove native javascript object prototyping, causes nasty side effects with 3rdParty components
// 3.11.2005 - fix for DateTime convesrion. contributed by Franceschina, Nick <NFranceschina@fujitecamerica.com>
// 12.1.2006 - Adding Loading indication support
// 12.1.2006 - Adding request id handling
// 12.1.2006 - Adding request cache
// 12.1.2006 - Adding client-side trace support
// </changes>
if( ! window.AddNamespace ) {
	window.AddNamespace = function( ns ) 	{
		var nsParts = ns.split(".");
		var root = window;

		for( var i = 0; i < nsParts.length; i++ ) 		{
			if( typeof root[ nsParts[ i ] ] == "undefined" ) {
				root[ nsParts[ i ] ] = new Object();
			}
			root = root[ nsParts[ i ] ];
		}
	}
}

// JavaScript objects wrappers
JSONObject = function( obj ) {
	this.obj = obj;
	
	this.toJSON = function() {
		if ( this.obj == null ) {
			return 'null';
		}
	//	debugger
		switch( this.obj.constructor ) {
			case Object:
				return ObjectToJSON( this.obj );
				break;
			
			case Array:
				return ArrayToJSON( this.obj );
				break;
				
			case String:
				return StringToJSON( this.obj );
				break;
			
			case Date:
				return DateToJSON( this.obj );
				break;
			
			case Number:
			case Boolean:
				return String( this.obj );
				break;
		}
	}
	
	function ObjectToJSON( obj ) {
		var v=[];
		for( attr in obj ) 	{
			if( typeof obj[ attr ] != "function" ) {
				var attribute = new JSONObject( obj[attr] );
				v.push('"' + attr + '": ' + ( obj[attr] != null ? attribute.toJSON() : 'null' ) );
			}
		}
		if( v.length > 0 ) {
			return "{" + v.join(", ") + "}";
		} else {
			return "{}";
		}
	
	}
	
	function StringToJSON( obj ) {
		var s = obj; // .encodeURI();
		s = '"' + s.replace(/(["\\])/g, '\\$1') + '"';
		s = s.replace(/\n/g,"\\n");
		s = s.replace(/\r/g,"\\r");
		s = s.replace(/\t/g,"\\t");
		return s;	
	}
	
	function DateToJSON( obj ) {
		var o = new Object();
		o.__type = "System.DateTime";
		o.Year = obj.getUTCFullYear();
		o.Month = obj.getUTCMonth() + 1;
		o.Day = obj.getUTCDate();
		o.Hour = obj.getUTCHours();
		o.Minute = obj.getUTCMinutes();
		o.Second = obj.getUTCSeconds();
		o.Millisecond = obj.getUTCMilliseconds();
		o.TimezoneOffset = obj.getTimezoneOffset();
		return new JSONObject( o ).toJSON();
	}
	
	function ArrayToJSON( obj ) {
		var v = [];

		for( var i = 0; i < obj.length; i++ ) {
			var elem = new JSONObject( obj[ i ] );
			v[v.length] = obj[ i ] != null ? elem.toJSON() : 'null';
		}
		return "[" + v.join(", ") + "]";
	}
}


JSONArray = function() {
	this.inherits = Array;
	this.inherits();
	
	this.push = function( o ) 	{
		this[ this.length ] = o;
	}
	
	this.getLast = function() 	{
		if( this.length == 0 ) {
			return null;
		}
		return this[ this.length -1 ];
	}
	
	this.getFirst = function() {
		if( this.length == 0 ) {
			return null;
		}
		return this[ 0 ];
	}
}


// .NET wrapper objects
AddNamespace( "System.Data" );

System.Data.DataSet = function( name ) {
	this.__type = "System.Data.DataSet, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
	this.Name = name != null ? name : "";
	this.Tables = [];
}

System.Data.DataTable = function( name ) {
	this.__type = "System.Data.DataTable, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
	this.Name = name != null ? name : "";
	this.Columns = [];
	this.Rows = [];
	
	this.addColumn = function( name, type ) {
		var c = new Object();
		c.Name = name;
		c.__type = type;
		this.Columns.push( c );
	}
}

// Browser related members
AddNamespace("MS.Browser" );

MS.Browser.isIE = (window.navigator.appName.toLowerCase().indexOf('explorer') != -1 || window.navigator.appName.toLowerCase().indexOf('msie') != -1 );

// Debug
AddNamespace( "MS.Debug" );

MS.Debug.enabled = false;
MS.Debug.trace = function( s ) {}

// Ajax.NET related members
AddNamespace( "AjaxNET" );

var ___tracerAvailable = -1;
AjaxNET.Trace = function( msg ) {
	if ( ___tracerAvailable == -1 ) {
		if ( typeof( Tracer ) == 'object' && Tracer ) {
			___tracerAvailable = true;
		} else {
			___tracerAvailable = false;
		}
	}
	
	if ( ___tracerAvailable ) {
		Tracer.Trace( msg );
	}
} 
AjaxNET.LastRequestID = 0;

AjaxNET.NewRequestID = function() {
	return ++AjaxNET.LastRequestID;
}

AjaxNET.ReuqestCache = new Array();
AjaxNET.GetXmlRequestObject = function () {
	var xml = null
	var len = AjaxNET.ReuqestCache.length;
	for( var i = 0; i < len; i++ ) {
		if ( AjaxNET.ReuqestCache[i].readyState == 4 ) {
			AjaxNET.ReuqestCache[i].abort();
			AjaxNET.Trace( "AjaxNET ReuqestCache: Hit" );
			return AjaxNET.ReuqestCache[i];
		}
	}	
	
	if( ! window.XMLHttpRequest ) {
		try { 
			xml = new ActiveXObject( "Msxml2.XMLHTTP.4.0" ); 
		} catch( ex ) { xml = null; }
		try { 
			xml = new ActiveXObject( "MSXML2.XMLHTTP" ); 
		} catch( ex ){ xml = null; }
		try { 
			xml = new ActiveXObject( "Microsoft.XMLHTTP" ); 
		} catch( ex ){ xml = null; }
	} else {
		xml = new XMLHttpRequest();
	}
	
	if ( xml == null ) {
		alert("Fatal ERROR: Could not initialise an XMLHttpReuqest object");
		return
	}
	AjaxNET.ReuqestCache[AjaxNET.ReuqestCache.length] = xml;
	AjaxNET.Trace( "AjaxNET ReuqestCache: Created new request object" );
	AjaxNET.Trace( "AjaxNET ReuqestCache: Using " + AjaxNET.ReuqestCache.length + " requests" );
	return xml;
}

AjaxNET.CurrentRequest = null;
AjaxNET.PendingReuqestCount = 0;
AjaxNET.ReuqestStarted = function() {
	AjaxNET.PendingReuqestCount++;
	AjaxNET.CheckLoading();
}
AjaxNET.ReuqestFinished = function() {
	AjaxNET.PendingReuqestCount--;
	AjaxNET.CheckLoading();
}
AjaxNET.CheckLoading = function() {
	if ( AjaxNET.PendingReuqestCount > 0 ) {
		if ( typeof( AjaxNET.ShowLoading ) == 'function' ) {
			AjaxNET.ShowLoading();
		}
	} else {
		if ( typeof( AjaxNET.HideLoading ) == 'function' ) {
			AjaxNET.HideLoading();
		}
	}
}

AjaxNETRequestQueue = function() {
	var _queue = new Array();
	var _inWork = false;
	
	this.AddRequest = function( reuqest ) {
		AjaxNET.Trace( "AjaxNET RequestQueue: Adding Request ID: " + reuqest.GetID() + " at index: " + _queue.length );
		_queue[_queue.length] = reuqest;
		this.Process();
	}
	
	this.Process = function( forceReuest ) {
		if ( ! forceReuest ) {
			if ( _inWork ) {
				return;
			}
		} else {
			AjaxNET.Trace( "AjaxNET RequestQueue: Forced Seinding Request ID: " + _queue[0].GetID() );
		}
		
		if ( _queue.length > 0 ) {
			_inWork = true;
			AjaxNET.Trace( "AjaxNET RequestQueue: Sending Request ID: " + _queue[0].GetID() );
			AjaxNET.CurrentRequest = _queue[0];
			_queue[0].SendRequest();
		} 
	}

	this.RequestFinished = function() {
		AjaxNET.Trace( "AjaxNET RequestQueue: Finished Request ID: " + _queue[0].GetID() );
		var len = _queue.length;
		var newQueue = new Array();
		for( var i = 0; i < ( len - 1 ); i++ ) {
			newQueue[ i ] = _queue[ i + 1 ];
		}
		_queue = newQueue;
		_inWork = false;
		AjaxNET.Trace( "AjaxNET RequestQueue: " + ( len - 1 ) + " Requests Pending" );
		this.Process();	
	}
}

var RequestQueue = new AjaxNETRequestQueue();

AjaxNET.ShowLoading = null;
AjaxNET.HideLoading = null;

AjaxNET.NoOperation = function() {}
AjaxNET.cryptProvider = null;
AjaxNET.token = "";
AjaxNET.Response = function() {
	this.url = null;
	this.error = null;
	this.request = null;
	this.value = null;
	this.responseText = null;
}


AjaxNET.Request = function( m, args, c, url ) {
	var _self = this;
	var xml = AjaxNET.GetXmlRequestObject();
	var requestData = new Object();
	var requestID = -1;
	var async = null;
	var data = "";
	var dataLength = 0;

	PrepareRequest( m, args, c, url );
	
	this.GetID = function() {
		return requestID;
	} 
	
	this.QueueRequest = function() {
		AjaxNET.Trace( "AjaxNET Queue Request: " + requestID );
		RequestQueue.AddRequest( this );
		// this.SendRequest();
	}
	
	this.SendRequest = function() {
		AjaxNET.ReuqestStarted();
		xml.send( data );
	
		if( ! async ) {
			return createResponse();
		}
		return true;	
	}
	
	function CleanUp() {
		delete xml;
		delete requestData;
		delete requestID;
		delete async;
		delete data;
		delete dataLength;
	}
	
	function PrepareRequest( m, args, c, url ) {
		requestData.method = m;
		requestData.args = args;
		requestData.callback = c[ 1 ].length > c[ 0 ] ? c[ 1 ][ c[ 0 ] ] : AjaxNET.NoOperation;
		requestData.context = c[ 1 ].length > c[ 0 ] + 1 ? c[ 1 ][ c[ 0 ]+1 ] : null;
		requestData.session = c[ 2 ];
		async = typeof requestData.callback == "function" && requestData.callback != AjaxNET.NoOperation;
		requestID = AjaxNET.NewRequestID();
	
		ProcessRequestData();
	
		if( async ) {
			xml.onreadystatechange = stateChanged;
		}
		xml.open( "POST", url, async );
		xml.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
		xml.setRequestHeader( "Content-length", dataLength );
		xml.setRequestHeader( "Ajax-method", requestData.method );
		xml.setRequestHeader( "Ajax-session", requestData.session );
		// xml.setRequestHeader( "Ajax-token", AjaxNET.token );
	
		if( MS.Browser.isIE ) {
			xml.setRequestHeader( "Accept-Encoding", "gzip, deflate" );
		} else {
			xml.setRequestHeader( "Connection", "close" );		// Mozilla Bug #246651
		}
	
		if( AjaxNET.cryptProvider != null ) {
			data = AjaxNET.cryptProvider.encrypt( data );
		}
		if( MS.Debug.enabled ) {
			MS.Debug.trace( "XMLHttpRequest: " + url + "\r\n  Method: " + requestData.method + "\r\n  Data: " + data );
		}
	}
	
	
	
	function ProcessRequestData() {
		for( attr in requestData.args )	{
			if( typeof requestData.args[ attr ] != "function") {
				var attribute = new JSONObject( requestData.args[attr] );
				data += attr + "=" + (requestData.args[attr] != null ? attribute.toJSON() : 'null') + "\r\n";
			}
		}

		if( MS.Debug.enabled ) {
			MS.Debug.trace( "JSON string: " + data );
		}	
	
		if( data.length != 0 ) {
			dataLength = data.length;
		} else {
			// alert("Test");
			data = new Date().getTime();
			dataLength = String( new Date().getTime() ).length;
		}
	}	
	
	function stateChanged() {
		// AjaxNET.Trace( "AjaxNET.Invoke: stateChanged()" );
		
		/* if ( xml.readyState == 1 ) { req.onLoadingInternal(req); }
		if ( xml.readyState == 2 ) { req.onLoadedInternal(req); }
		if ( xml.readyState == 3 ) { req.onInteractiveInternal(req); } */
		if ( xml.readyState == 4 ) { doCallback(); }
	}	
		
	function doCallback() {
		AjaxNET.Trace( "AjaxNET Request: " + requestID + " doCallback()" );
		
		if( xml.readyState != 4 ) {
			return;
		}

		try {
			if ( typeof( xml.status ) == 'undefined' ) {
				alert( 'xml.status == undefined' );
				return;
			}
			if( xml.status == 200 ) {
				RequestQueue.RequestFinished();
				requestData.callback( createResponse() );
			}
		} catch ( e ) { 
			AjaxNET.Trace( "AjaxNET Request: " + e.message ) 
			// alert( "Forcing Reuest" );
			// RequestQueue.Process( true );
		}
		
		// xml = null;
	}
	
	function OnTimeout() {
		AjaxNET.Trace( "AjaxNET.Invoke: OnTimeout()" );
		
		if ( typeof( AjaxNET.TimeOut ) == 'function' ) {
			AjaxNET.TimeOut();
		}
	}
	
	function createResponse() {
		var responseData = new AjaxNET.Response();
		responseData.url = url;
		responseData.error = null;
		responseData.request = requestData;
		responseData.value = null;
		responseData.responseText = xml.responseText;

	//	AjaxNET.Trace( "AjaxNET Response: " + requestID + " " + url + "\r\n  Method: " + requestData.method + "\r\n  Response: " + resopnseData.responseText );

		if( MS.Debug.enabled ) {
			MS.Debug.trace( "XMLHttpResponse: " + url + "\r\n  Method: " + requestData.method + "\r\n  Response: " + responseData.responseText );
		}
		if( AjaxNET.cryptProvider != null ) {
			responseData.responseText = AjaxNET.cryptProvider.decrypt( responseData.responseText );
		}
		if( MS.Debug.enabled ) {
			MS.Debug.trace( "JSON string: " + responseData.responseText );
		}
		
		// alert( r.responseText );
		eval( "responseData.value = " + responseData.responseText + ";" );
		AjaxNET.ReuqestFinished();
		CleanUp();
		return responseData;
	}
}


