/**
 * (C) 2006 IMIS group AG, Zurich, Switzerland.
 *
 * Java Script Logger class.
 */

/* Log level constants */
Logger.TRACE = 0;
Logger.DEBUG = 1;
Logger.INFO = 2;
Logger.WARN = 3;
Logger.ERROR = 4;
Logger.FATAL = 5;
Logger.OFF = 10;

/**
 * Static LogFactory
 */
function LogFactory()
{
	return LogFactory;
}

LogFactory.LOG_LEVEL = Logger.OFF;

LogFactory.getLog = function(_source)
{
	var log = new Logger();
	log.logSource = _source;
	log.logLevel = LogFactory.LOG_LEVEL;
	return log;
}

/**
 * Constructor
 */
function Logger()
{
	
	/* Level to log (defaults to INFO) */
	var logLevel = Logger.INFO;
	
	/* Log source name */
	var logSource = "Unknown";
	
}




/**
 * Log trace message
 */
Logger.prototype.trace = function(_msg)
{
	if(this.logLevel <= Logger.TRACE)
	{
		this.internalDoLog(Logger.TRACE, _msg);
	}
}

/**
 * Log debug message
 */
Logger.prototype.debug = function(_msg)
{
	if(this.logLevel <= Logger.DEBUG)
	{
		this.internalDoLog(Logger.DEBUG, _msg);
	}
}

/**
 * Log info message
 */
Logger.prototype.info = function(_msg)
{
	if(this.logLevel <= Logger.INFO)
	{
		this.internalDoLog(Logger.INFO, _msg);
	}
}

/**
 * Log warn message
 */
Logger.prototype.warn = function(_msg)
{
	if(this.logLevel <= Logger.WARN)
	{
		this.internalDoLog(Logger.WARN, _msg);
	}
}

/**
 * Log error message
 */
Logger.prototype.error = function(_msg)
{
	if(this.logLevel <= Logger.ERROR)
	{
		this.internalDoLog(Logger.ERROR, _msg);
	}
}

/**
 * Log fatal message
 */
Logger.prototype.fatal = function(_msg)
{
	if(this.logLevel <= Logger.FATAL)
	{
		this.internalDoLog(Logger.FATAL, _msg);
	}
}

/**
 * Internal log implementation (override this method if necessary)
 */
Logger.prototype.internalDoLog = function(_level, _msg)
{
	var message = new Date() + ":" + this.logSource + " (" + _level + "): " + _msg;
	window.status = message;
	var out = this.internalGetLogWindow();
	if(out)
	{
		out.innerHTML = out.innerHTML + "<br />" + message;
	}
}

/**
 * Internal method to create log output
 */
Logger.prototype.internalGetLogWindow = function()
{
	if(document.getElementById("Logger.output"))
	{
		return document.getElementById("Logger.output");
	}
	var logoutput = document.createElement("div");
	logoutput.setAttribute("id", "Logger.output");
	var body = document.getElementsByTagName("body")[0];
	if(body)
	{
		var firstBodyChild = body.firstChild;
		body.insertBefore(logoutput, firstBodyChild);
		logoutput.style.position = "absolute";
		logoutput.style.bottom = "5px";
		logoutput.style.height = "200px";
		logoutput.style.width = "900px";
		logoutput.style.overflow = "auto";
		logoutput.style.backgroundColor = "#ffffff";
		logoutput.style.border = "1px solid black";
		logoutput.style.fontFamily = "monospace";
		logoutput.style.fontSize = "9px";
		logoutput.style.zIndex = "500";
		return logoutput;
	}
	return null;
}



/**
 * (C) 2006 IMIS group AG, Zurich, Switzerland.
 * 
 * XMLRPCProvider class, based on code from:
 * 
 * ------------------------------------------------------ JavaScript Refactoring
 * for safer, faster, better AJAX.
 * 
 * Copyright 2005, Pavel Simakov, http://www.softwaresecretweapons.com
 * ------------------------------------------------------
 * 
 * @author tam
 */

// http method constants
XMLRPCProvider.METHOD_GET = "GET";
XMLRPCProvider.METHOD_POST = "POST";

// constructor
function XMLRPCProvider() {

	this.log = LogFactory.getLog("XMLRPCProvider");

	this.status = null;
	this.async = true;

	var method = XMLRPCProvider.METHOD_GET;
	var url = null;
	var body = null;
	var req = null;
	var inProgress = false;
	var isComplete = false;
}

// tells us whether we are busy waiting for the response to another request
XMLRPCProvider.prototype.internalIsBusy = function() {
	return this.inProgress && !this.isComplete;
}

// internal callback function for the browser; it is called when a state of a
// request object changes
XMLRPCProvider.prototype.internalRequestComplete = function() {

	var STATE_COMPLETED = 4;
	var STATUS_200 = 200;

	if (!this.internalIsBusy()) {
		this.log.error("internalRequestComplete: error - no request submitted");
	}

	this.onProgress(this.req.readyState);

	this.log
			.debug("internalRequestComplete: readyState " + this.req.readyState);

	if (this.req.readyState == STATE_COMPLETED) {
		this.status = this.req.status;
		this.inProgress = false;
		this.isComplete = true;

		this.log.debug("internalRequestComplete: status " + status);

		if (this.status == STATUS_200) {
			this.log
					.debug("internalRequestComplete: calling callback on content with length "
							+ this.req.responseText.length + " chars");
			this.log.debug("internalRequestComplete: response headers = "
					+ this.req.getAllResponseHeaders());
			this.log.debug("internalRequestComplete: xml document: "
					+ this.req.responseXML);
			if (this.onComplete) {
				this.onComplete(this.req.responseText, this.req.responseXML);
			}
			this.log.info("internalRequestComplete: complete on " + new Date());
		} else {
			this.log
					.warn("internalRequestComplete: error - bad status while fetching "
							+ this.url + " - status: " + this.status);
		}
	} else {
		// do nothing in particular
	}
}

// call this function to figure out version of this class
XMLRPCProvider.prototype.getVersion = function() {
	return "1.0.0";
}

// call this function to figure out if current browser supports XML HTTP
// Requests
XMLRPCProvider.prototype.isSupported = function() {
	var nonEI = window.XMLHttpRequest;
	var onIE = window.ActiveXObject;

	if (onIE) {
		onIE = new ActiveXObject("Microsoft.XMLHTTP") != null;
	}

	return window.XMLHttpRequest || onIE;
}

// internally called to create new instance of XMLHttpRequest
XMLRPCProvider.prototype.internalNewRequest = function() {
	var xmlhttp = false;
	var xmlhttp=false;
	/*@cc_on @*/
	/*@if (@_jscript_version >= 5)
	// JScript gives us Conditional compilation, we can cope with old IE versions.
	// and security blocked creation of the objects.
	 try {
	  this.log.debug("Trying to use Msxml2.XMLHTTP ActiveX Object...");
	  xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	 } catch (e) {
	  try {
	   this.log.debug("Trying to use Microsoft.XMLHTTP ActiveX Object...");
	   xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	  } catch (E) {
	   this.log.error("failed to create xml http request (MSIE)");
	   xmlhttp = false;
	  }
	 }
	 if(xmlhttp)
	 {
	   this.log.debug("created xml http request successfully (MSIE)");
	 }
	 this.log.debug("cache request headers set (MSIE)");
	@end @*/
	if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
		xmlhttp = new XMLHttpRequest();
	}
	return xmlhttp;
}

// call this function to find out if more calls are possible and if request has
// been completely received
XMLRPCProvider.prototype.isBusy = function() {
	return this.internalIsBusy();
}

/**
 * Submit POST request
 */
XMLRPCProvider.prototype.post = function(_url, _body) {
	this.submit(XMLRPCProvider.METHOD_POST, _url, _body);
}

/**
 * Submit GET request
 */
XMLRPCProvider.prototype.get = function(_url) {
	this.submit(XMLRPCProvider.METHOD_GET, _url, null);
}

/**
 * Submit called by post / get methods.
 * 
 * Todo: Add support for sync requests???
 */
XMLRPCProvider.prototype.submit = function(_method, _url, _body) {
	if (this.internalIsBusy()) {
		this.log.error("submit: error - busy processing another request "
				+ _url);
	}

	this.msgCount = 0;
	this.log.info("submit: started on " + new Date() + " for " + _url);

	this.method = _method;
	this.url = _url;
	this.body = _body;
	this.status = null;
	this.inProgress = true;
	this.isComplete = false;

	this.log.debug("creating new XMLHttpRequest");
	// create new request
	this.req = this.internalNewRequest();

	this.log.info("created new request: " + this.req);

	this.log.debug("using method " + this.method + " to submit request");

	this.log.debug("initiating call (set callback and open); async = "
			+ this.async);
	if (this.async) {
		var _this = this;
		this.req.onreadystatechange = function() {
			_this.internalRequestComplete();
		};
	}
	this.req.open(this.method, this.url, this.async);

	// set headers necessary for post requests
	if (this.method == XMLRPCProvider.METHOD_POST) {
		this.log.debug("setting request header: Content-type");
		this.req.setRequestHeader("Content-type",
				"application/x-www-form-urlencoded");
		this.log.debug("setting request header: Content-length");
		this.req.setRequestHeader("Content-length", this.body.length);
		// this.log.debug("setting request header: Connection");
		// this.req.setRequestHeader("Connection", "close");
		this.log.debug("request headers for POST request set");
	}

	// branch for IE/Windows ActiveX version
	/*
	 * if (window.ActiveXObject) { this.log.debug("setting request headers for
	 * Internet Explorer (disable caching)");
	 * this.req.setrequestheader("Pragma","no-cache");
	 * this.req.setrequestheader("Cache-control","no-cache"); }
	 */

	this.req.send(this.body);
	this.log.info("submit complete");

	// if not async call request must be complete here
	if (!this.async) {
		this.log.info("syncronous call complete");
		this.log.debug("response headers: " + this.req.getAllResponseHeaders());
		if (this.onComplete) {
			this.log.info("calling onComplete callback method");
			this.onComplete(this.req.responseText, this.req.responseXML);
		}
	}

}

// call this function to abort current request
XMLRPCProvider.prototype.abort = function() {
	this.log.info("abort: " + this.url);

	if (!this.internalIsBusy()) {
		this.log.error("abort: error - no request submitted");
	}

	this.onComplete = null;
	this.req.abort();
}

// call this function to find out current url
XMLRPCProvider.prototype.getUrl = function() {
	return this.url;
}

// call this function to find out HTTP status code after response completes
XMLRPCProvider.prototype.getStatus = function() {
	return this.status;
}

// user can overrise this; this function is called when ready state of request
// changes
XMLRPCProvider.prototype.onProgress = function(progressState) {

}

// user can override this; this function is called when response is received
// without errors
XMLRPCProvider.prototype.onComplete = function(responseText, responseXML) {

}

/**
 */

/**
 * Constructor
 */
function XMLRPCPost() 
{
	this.log = LogFactory.getLog("XMLRPCPost");

	this.form = null;
	this.elements = new Array();
	this.eventSourceElement = null;
	
	this.url = null;
	
	this.responseText = null;
	this.responseXML = null;
	this.xmlrpc = null;
}

/**
 * Add an element whose data should be included in post body
 */
XMLRPCPost.prototype.addElement = function(_element)
{
	this.log.debug("adding element " + _element);
	this.elements.push(_element);
}

/**
 * Submit a form; the event source element may be specified to "simulate"
 * normal form post (if specified, other form submit buttons, etc. will be
 * excluded).
 */
XMLRPCPost.prototype.submit = function(_form, _sourceElement)
{
	this.form = _form;
	this.log.debug("form is " + this.form);
	if(!this.url)
	{
		this.url = this.form.action;
		this.log.debug("using form url: " + this.url);
	}
	this.eventSourceElement = _sourceElement;
	
	var _this = this;
	
	this.xmlrpc = new XMLRPCProvider();
	//this.xmlrpc.async = false;
	this.xmlrpc.onComplete = function(_responseText, _responseXML) { _this.internalCallback(_responseText, _responseXML); };
	
	var body = this.internalCreateBody();
	this.log.debug("body to post: " + body);
	
	this.xmlrpc.post(this.url, body);
}



/**
 * Creates the http post body using all form elements, and / or additionally 
 * defined elements.
 */
XMLRPCPost.prototype.internalCreateBody = function()
{
	// create array of all elements to include
	var includeElements = new Array();
	
	// if form is present, add all form elements
	if(this.form != null)
	{
		var frmElements = this.form.elements;
		for(var i = 0; i < frmElements.length; i++)
		{
			includeElements.push(frmElements[i]);
		}
		this.log.debug("adding " + frmElements.length + " form elements to encode; now contains " + includeElements.length + " elements");
		
	}
	
	// add array of elements
	if(this.elements != null && this.elements instanceof Array && this.elements.length > 0)
	{
		this.log.debug("adding " + this.elements.length + " form elements to the array");
		includeElements = includeElements.concat(this.elements);
	}
	
	// add event source element (some form elements are not present in the
	// array of elements, e.g. image submit; thus the event source element
	// has to be added to the elements)
	if(this.eventSourceElement != null)
	{
		this.log.debug("adding event source form element to the array");
		if(this.eventSourceElement.type == 'image')
		{
			includeElements.push(this.eventSourceElement);
		}
	}
	
	// create http post body
	var body = "";
	var elemCount = includeElements.length;
	this.log.info("Number of elements: " + elemCount);
	
	for(var i = 0; i < elemCount; i++)
	{
		var curElement = includeElements[i];
		var curType = curElement.type;
		// if event source element specified all other submit buttons should 
		// be excluded
		if(curType == "button" || curType == "submit" || curType == "image"
			|| curType == "reset")
		{
			// exclude if not event source element
			if(this.eventSourceElement != null 
				&& this.eventSourceElement != curElement)
			{
				continue;
			}
		}
		var encodedElement = this.internalEncodeElement(curElement);
		if(encodedElement != "")
		{
			this.log.debug("adding encoded element to body: " + encodedElement);
			if(body != "")
			{
				body += "&";
			}
			body += encodedElement;
		}
	}
	return body;
}

/**
 * Creates an URI encoded string representation of an element.
 */
XMLRPCPost.prototype.internalEncodeElement = function(_element)
{
	// encode element name and value
	var encodedName = encodeURIComponent(_element.name);
	var encodedValue = encodeURIComponent(_element.value);
	
	// do not create part for elements without name
	if(encodedName == "")
	{
		return "";
	}
	
	// handle hidden
	if(_element.type == "hidden")
	{
		return encodedName + "=" + encodedValue;
	}
	
	// handle checkboxes
	if(_element.type == "checkbox")
	{
		if(_element.checked)
		{
			return encodedName + "=" + encodedValue;
		}
		return "";
	}
	
	// handle radio button
	if(_element.type == "radio")
	{
		if(_element.checked)
		{
			return encodedName + "=" + encodedValue;
		}
		return "";
	}
	
	// handle select boxes
	if(_element.options)
	{
		var uriPart = "";
		var optionCount = _element.options.length;
		for(var i = 0; i < optionCount; i++)
		{
			var option = _element.options[i];
			if(option.selected)
			{
				if(uriPart != "")
				{
					uriPart += "&";
				}
				uriPart += encodedName + "=" + encodeURIComponent(option.value);
			}
		}
		return uriPart;
	}

	// handle image (coordinates submitted are always 0 / 0)
	if(_element.type == "image")
	{
		var uriPart = "";
		uriPart += encodedName + ".x=0&";
		uriPart += encodedName + ".y=0&";
		uriPart += encodedName + "=" + encodedValue;
		return uriPart;
	}
	
	// handle button
	if(_element.type == "button" || _element.type == "submit")
	{
		return encodedName + "=" + encodedValue;
	}
	
	// text fields
	if(_element.type == "text" || _element.type == "textarea")
	{
		return encodedName + "=" + encodedValue;
	}
	// fallback; just return empty string
	return "";
}

/**
 *
 */
XMLRPCPost.prototype.internalCallback = function(_responseText, _responseXML)
{
	this.log.info("internalCallback: request is complete");
	this.log.debug("responseText length: " + _responseText.length);
	this.log.debug("responseXML: " + _responseXML);
	this.responseText = _responseText;
	this.responseXML = _responseXML;
	this.onComplete(_responseText, _responseXML);
}

XMLRPCPost.prototype.onComplete = function(_responseText, _responseXML)
{
}

/**
 * DOJO/Tapestry Javascript Emulation
 */

var forms; //:{}

var dojo = function()
{
}


dojo.addOnLoad = function(obj, functionName) 
{
	if(arguments.length == 1)
	{
		obj();
	}
}

dojo.require = function()
{
}

dojo.event = function()
{
}

dojo.byId = function()
{
}

dojo.event.connect = function()
{
}

var tapestry = function()
{
}


tapestry.cleanConnect = function()
{
}

tapestry.form = function()
{
}

tapestry.form.registerForm = function(id, async, json)
{
	
	if(async)
	{
		var form=document.getElementById(id);
		if(null != form)
		{
			form.onsubmit =  function() { return submitAsync(this) };
			for (var i=0; i < form.elements.length; i++) 
			{
			   var element = form.elements[i];
			   if(element.type == 'submit')
			   {
				   element.onclick =  function() { return trackClick(this) };
			   }
			}
		}
	}
}

tapestry.linkOnClick = function(href,name,json)
{
	anchor = document.getElementById(name);
	var updateParts = getQueryVariable(href,'updateParts')
	href += "&beventtarget.id="+name+"&beventname=onClick";
	anchor.href=href;
	return submitLink(anchor,updateParts,json);	
}

function trackClick(submit)
{
	window.clicked = submit;
}

function submitAsync(form)
{
	submitName = null;
	if(null != window.clicked && window.clicked != 'undefined')
	{
		submitElement = window.clicked;
		window.clicked = null;
	}
	tapestry.form.submitAsync(form.id,null,submitElement,null);
	return false;
}

tapestry.form.focusField = function(fieldId)
{	
}

tapestry.form.submitAsync = function(formName, content, submitName, validate)
{
	var form = document.getElementById(formName);
	updatepartsField = form.elements["updateParts"];
	
	var updates = null;
	if(null != updatepartsField && "undefined" != typeof(updatepartsField))
	{
		updates = updatepartsField.value;	
	}
	
	return submitForm(form, updates , submitName ,null);
}



tapestry.form.submit = function(formName, submitName, parms){
    var form=document.getElementById(formName);
    
    if (!form) {
            dojo.raise("Form not found with id " + form);
            return;
    }
    if (submitName){
            form.submitname.value=submitName;
    }
    	form.submit();
        return false;

}


function getQueryVariable(url,variable) {
	  var parts = url.split("?");
	  var vars = parts[1].split("&");
	  for (var i=0;i<vars.length;i++) {
	    var pair = vars[i].split("=");
	    if (pair[0] == variable) {
	      return pair[1];
	    }
	  }
} 

