var Class = {
   create: function() {
     return function() {
       if (this.initialize) {
    	   var cmd = 'this.initialize(';
    	   if (arguments.length > 0){
	    	   var args = [];
	    	   for( var i = 0; i < arguments.length; i++ ) args.push("'" + arguments[i] + "'");
	   		   cmd += args.join(',');
    	   }
    	   cmd += ');';
    	   eval(cmd);
       }
     }
   }
 }
var AjaxDispatcher = {
	busy: false,
	queue: new Array(0),
	addWaitingEvent: function (request){
		this.queue.push(request);
	},
	executeWaitingEvent: function(){
		if (this.queue.length == 0) {
			this.busy = false;
			return;
		}
		this.busy = true;
		this.executedRequest = this.queue.shift();
		
		var data = this.executedRequest.options.data || this.executedRequest.options.postBody;
		
		var options = { 
			complete: AjaxDispatcher.onComplete, 
			success: AjaxDispatcher.onSuccess, 
			error: AjaxDispatcher.onFailure, 
			data:data
		};
		options.type = "POST";
		options.dataType = "json";
		
		options.url = this.executedRequest.method;
		
		if (this.executedRequest.options.onStart != undefined) this.executedRequest.options.onStart();
		if (this.executedRequest.options.silent != true)
			Loading.show();
		$.ajax(options);
	},
	executedRequest:null,
	request: function(method, options){
	    if (options == undefined) options = {};
		AjaxDispatcher.addWaitingEvent({method: method, options: options});
		if (!AjaxDispatcher.busy)
			AjaxDispatcher.executeWaitingEvent();
	},
	onComplete: function(){
		Loading.hide();
		AjaxDispatcher.executeWaitingEvent();
	},
	onFailure: function(obj, text, err){
		SMessages.error.show('System error: ' + text);
		Loading.hide();
		// ONCOMPLETE
		if (AjaxDispatcher.executedRequest.options.onComplete != undefined)
			AjaxDispatcher.executedRequest.options.onComplete();
	},
	onSuccess: function(response){
		if (response == null){
			if (AjaxDispatcher.executedRequest.onError != undefined)
				AjaxDispatcher.executedRequest.onError();
		    AjaxDispatcher.onFailure({status:"handling", statusText:"invalid response" + response});
			return;
	    }
		var callSuccess = true;
		var callParam = null;
	// ONCOMPLETE
		if (AjaxDispatcher.executedRequest.options.onComplete != undefined)
			AjaxDispatcher.executedRequest.options.onComplete(response);
	// REDIRECT	
		if (response.redirect != undefined){
			callSuccess = false;
			var loc =  response.redirect;
			if (loc.substr(0,8) == '::reload') window.location.reload();
			else window.location = loc;
	    }
	// ERROR
		if (response.error != undefined){
			callSuccess = false;
			SMessages.error.show(unescape(response.error));
			if (AjaxDispatcher.executedRequest.options.onError != undefined){
				AjaxDispatcher.executedRequest.options.onError(unescape(response.error));
			}
	    }
	// RESPONSE	
		if (response.response != undefined){
		    if (typeof(response.response) == 'string'){
		        try{
	    		    callParam = unescape(response.response);
	        		if (AjaxDispatcher.executedRequest.options.updateElement != undefined){
	        			$(AjaxDispatcher.executedRequest.options.updateElement).update(callParam);
	                }
	                //callParam.evalScripts();
	        	}catch(e){
	                alert(e.message);
	        	}
			}else{
			    callParam = response.response;
		    }
		}
	// STATUS
		if (response.status != undefined){
			SMessages.status.show(unescape(response.status));
		}
	// SUCCESS
		if (callSuccess && (AjaxDispatcher.executedRequest.options.onSuccess != undefined) ) 
			AjaxDispatcher.executedRequest.options.onSuccess(callParam, AjaxDispatcher.executedRequest.extraParam);
	}
}
function ajaxUpdate (element, method, options){
    if (options == undefined) options = {};
	options.updateElement = element;
	return ajaxRequest(method, options);
}
function ajaxFormSubmit(form, onSuccess, options){
	if (options == undefined) options = {};
	options.postBody = $(form).serialize();
	options.sender = form;
	options.onSuccess = onSuccess;
	ajaxRequest(form.action, options);	
	return false;
}
function ajaxRequest(method, options){return AjaxDispatcher.request(method,options);}

var Loading = {
		id:'#loadIndicator',
		arrange: function(){ 
			$(Loading.id).css('top', $(window).scrollTop() );
		},
		show: function(){
			Loading.arrange();
			$(Loading.id).show();
			SMessages.hide();
			$(window).bind('scroll', Loading.arrange);
		},
		hide: function(){
			$(Loading.id).fadeOut();
			$(window).unbind('scroll', Loading.arrange);
		}
	}
var SMessages = {
	ttl: 10000,
	error: {
		id: '#error',
		isShown: false,
		text: function(message){
			if (!message) return;
			var reg=/errortip{(.+?)}(.+)/; 
			var reg2=/^\w+$/; 
			var chunks = message.split(';');
			var restMsg = [];
			for (var i=0; i < chunks.length; i++){
				var result=reg.exec(chunks[i]);
				if (result == null) {
					restMsg.push(chunks[i]);
					continue;
				}
				var doc = $('body');
				if (AjaxDispatcher.executedRequest != null)
					if (AjaxDispatcher.executedRequest.options.sender != undefined)
						doc = $(AjaxDispatcher.executedRequest.options.sender);
				var s = reg2.test(result[1]) ? '#' + result[1] : result[1];
				var obj = doc.find(s);
				if (obj.size() == 0)
					obj = doc.find('[name="' + result[1] + '"]');
				var message = result[2];
				if(obj.size() > 0){
					obj.after('<span class="errorTip" onclick="$(this).fadeOut()"><span class="arrow">&nbsp;</span>' + message + '</span>').addClass('errorTip');
				}else{
					restMsg.push(message + " (" + result[1] + ")");
				}
			}
			SMessages.error.toShow = (restMsg.length > 0);
			if (SMessages.error.toShow){
				$('#error span.text').text(restMsg.join('<br/>'));
			}
		},
		show: function(message){
			if (SMessages.error.isShown) return;
			if(message.length == 0) return;
			SMessages.error.text(message);
			SMessages.error.onShow();
			SMessages.error.isShown = true;		
			clearInterval(SMessages.error.timerId);
			SMessages.error.timerId = setTimeout("SMessages.error.hide()", SMessages.ttl);
		},
		hide: function(){
			if (!SMessages.error.isShown) return;
			SMessages.error.onHide();
			SMessages.error.isShown = false;
		},
		onShow: function(){ $(this.id).stop().fadeIn(); },
		onHide: function(){ $(this.id).stop().fadeOut(); }
	},
	status:{
		id: '#status',
		timerId: null,
		isShown: false,
		text: function(message){ $(SMessages.status.id).html(message); },
		show: function(message){
			if (SMessages.status.isShown) return;
			if(message.length == 0) return;
			SMessages.status.text(message);
			SMessages.status.onShow();
			SMessages.status.isShown = true;
			clearInterval(SMessages.status.timerId);
			SMessages.status.timerId = setTimeout("SMessages.status.hide()", SMessages.ttl);
			},
			hide: function(){
				if (!SMessages.status.isShown) return;
				SMessages.status.onHide();
				SMessages.status.isShown = false;
			},
			onShow: function(message){ $(this.id).stop().fadeIn(); },
			onHide: function(){ $(this.id).stop().fadeOut(); }
		},
	hide: function(){
		SMessages.error.hide();
		SMessages.status.hide();
		$('span.errorTip').remove();
		$('.errorTip').removeClass('errorTip');
	}
}
