function addEvent(obj, evType, fn, useCapture){
	if (obj.addEventListener) {
		obj.addEventListener(evType, fn, useCapture);
		return true;
	} else if (obj.attachEvent) {
		var r = obj.attachEvent("on"+evType, fn);
		return r;
	} else {
		return false;
	}
}

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.prototype.extend = function(object) {
  return Object.extend.apply(this, [this, object]);
}

Object.prototype.clone = function (deep) {
  var objectClone = new this.constructor();
  for (var property in this)
    if (!deep)
      objectClone[property] = this[property];
    else if (typeof this[property] == 'object')
      objectClone[property] = this[property].clone(deep);
    else
      objectClone[property] = this[property];
  return objectClone;
}

var DateCompareToResult = {
	NOT_A_DATE: -1,
	EQUALS : 0,
	LESS_THAN : 1,
	GREATER_THAN : 2
}


Date.prototype.compareTo = function(toCompare){
	var result = 0;

	if(toCompare.constructor != Date){
		result = DateCompareToResult.NOT_A_DATE;
	}
	if (result >= 0){
		if(this < toCompare){ result = DateCompareToResult.LESS_THAN; }
		else if(this > toCompare) { result = DateCompareToResult.GREATER_THAN; }
		else { result = DateCompareToResult.EQUALS; }
	}
  return result;
}

Date.prototype.toInternationalDateString = function(){
	return this.getFullYear() + "-" + _leadZero(this.getMonth() + 1) + "-" + _leadZero(this.getDate());

	function _leadZero(v,length) {
		if (typeof(length) != "number") { length = 2; }
		v = new String(v);

		for (var i = v.length; i < length; i++){
			v = "0" + v;
		}
		return v;
	}
}

Number.prototype.isPositive = function(){
	return (this >= 0) ? true : false;
}

Number.prototype.isNegative = function(){
	return (this < 0) ? true : false;
}

Function.prototype.bind = function(object) {
  var __method = this;
  return function() {
    __method.apply(object, arguments);
  }
}













// TODO: This seeems to be based on prototype.js
// we can't replace it for now because we added a mechanism to handle a callback parameter
// see what can be done to avoid duplication


var SmartAjax = {
	version: "1.0"
}

SmartAjax.Request = Class.create();
SmartAjax.Request.Events = ["Uninitialized", "Loading", "Loaded", "Interactive", "Complete"];

SmartAjax.Request.prototype = {
    setOptions : function(options){
        this.options = {method : "post", asynchronous : true, parameters : ""}.extend(options || {});
    },

    responseIsSuccess: function() {
      return this.xmlHttp.status == undefined
          || this.xmlHttp.status == 0
          || (this.xmlHttp.status >= 200 && this.xmlHttp.status < 300);
    },

    responseIsFailure: function() {
      return !this.responseIsSuccess();
    },

    initialize: function(url, options, callBackObj) {
        this.xmlHttp = new XMLHttpRequest();
        this.callBackParam = callBackObj;
        this.setOptions(options);
        if (url.length > 0){ this.request(url); }
      },

    request : function (url){
      var parameters = this.options.parameters || "";
      if (parameters.length > 0) parameters += "&_=";

      try{
        if (this.options.method == "get"){
          url += "?" + parameters;
        }

        this.xmlHttp.open(this.options.method, url, this.options.asynchronous);

        if (this.options.asynchronous) {
          this.xmlHttp.onreadystatechange = this.onStateChange.bind(this);
          setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
        }

        this.setRequestHeaders();

        var body = this.options.postBody ? this.options.postBody : parameters;
        this.xmlHttp.send(this.options.method == "post" ? body : null);
      }
      catch(ee){}
    },

    setRequestHeaders: function() {
      var requestHeaders = [
        {key: "X-Requested-With", value: "XMLHttpRequest"},
        {key: "X-SmartAjax-Version", value : SmartAjax.version}];

      if (this.options.method == "post") {
        requestHeaders.push({key: "Content-type", value: "application/x-www-form-urlencoded"});

        /* Force "Connection: close" for Mozilla browsers to work around
         * a bug where XMLHttpReqeuest sends an incorrect Content-length
         * header. See Mozilla Bugzilla #246651.
         */
        if (this.xmlHttp.overrideMimeType){
          requestHeaders.push({key:"Connection", value:"close"});
        }
      }

      if (this.options.requestHeaders){
        requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
      }

      for (var i = 0; i < requestHeaders.length; i++){
        this.xmlHttp.setRequestHeader(requestHeaders[i].key, requestHeaders[i].value);
      }
    },

    onStateChange : function (){
      var readyState = this.xmlHttp.readyState;
      if (readyState != 1){
        this.respondToReadyState(this.xmlHttp.readyState);
      }
     },

    respondToReadyState : function (readyState){
      var event = SmartAjax.Request.Events[readyState];

      if (event == "Complete"){
        (this.options['on' + this.xmlHttp.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(this.xmlHttp, this.callBackParam);
      }

      (this.options['on' + event] || Prototype.emptyFunction)(this.xmlHttp, this.callBackParam);

      /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
      if (event == "Complete"){
        this.xmlHttp.onreadystatechange = Prototype.emptyFunction;
      }
    }
}





var SmartMessage = Class.create();
SmartMessage.defaultOptions = {
  messageTimeout : 5000,
  domId : "SmartMessage"
}

SmartMessage.extend({
  HTMLElement : null,
  timeout : null,
  display: function(message, options){
    var displayOptions = SmartMessage.defaultOptions.clone();
    displayOptions.extend(options || {});

    clearTimeout(this.timeout);

    if (this.HTMLElement){
      this.HTMLElement.innerHTML = message;
    }
    else {
      var div = document.createElement("div");
      div.id = displayOptions.domId;
      div.innerHTML = message;
      this.HTMLElement = document.body.appendChild(div);
    }

    if (displayOptions.messageTimeout > 0){
      this.timeout = setTimeout("SmartMessage.hide()", displayOptions.messageTimeout);
    }
  },

  hide : function(){
    clearTimeout(this.timeout);
    if(this.HTMLElement){
      document.body.removeChild(this.HTMLElement);
      this.HTMLElement = null;
    }
  }
})





/*************************************************
	Creation of cross-browser object
	 - window.showModalDialog for Gecko
	 - XMLHttpRequest object for Internet Explorer
**************************************************/

if (!Array.prototype.push) {
  Array.prototype.push = function() {
		var startLength = this.length;
		for (var i = 0; i < arguments.length; i++)
      this[startLength + i] = arguments[i];
	  return this.length;
  }
}

if(typeof(XMLHttpRequest) == 'undefined'){
 	var XMLHttpRequest = function(){
		var request = null;
		try{
			request = new ActiveXObject('Msxml2.XMLHTTP');
		}
		catch(e){
			try{
				request = new ActiveXObject('Microsoft.XMLHTTP');
			} catch(ee){}
		}
		return request;
	}
}

if (typeof(window.showModalDialog) == "undefined"){
	window.showModalDialog = function(url,arguments,features){
		return window.open(url, arguments, toOpenParam(features));
		function toOpenParam(features){
			var args = features.split(";");
			var optName = new Array();
			optName["dialogWidth"] = "width";
			optName["dialogHeight"] = "height";
			optName["dialogTop"] = "top";
			optName["dialogLeft"] = "left";
			optName["status"] = "status";
			optName["resizable"] = "resizable";
			optName["scroll"] = "scrollbars";
			var openParam = new Array();
			for(var i = 0; i < args.length; i++){
				var arg = args[i].split(":");
				if (optName[arg[0]] != null && optName[arg[0]] != "undefined"){
					openParam[i] = optName[arg[0]].concat("=", arg[1]);
				}
			}
			openParam[openParam.length] = "modal=yes";
			return openParam.join(",");
		}
	}
}

window.location.getParameter = function(key){
	var search = this.search.substring(1,this.search.length);
	var params = search.split("&");
	var value = new String("");
	for (var i = 0; i < params.length; i++){
		var param = params[i].split("=");
		if (param[0].toLowerCase() == key.toLowerCase()){
			value = param[1];
			break;
		}
	}
	return value;
}

window.location.searchWithoutKeys = function(keys){
	var search = this.search.substring(1,this.search.length);
	var params = search.split("&");
	var result = new Array();
	for(var i = 0; i < params.length; i++){
			var paramFound = false;

			for(var j = 0; j < keys.length; j++){
				if (params[i].search(keys[j])){
					paramFound = true;
					break;
				}
			}

			if(paramFound){
				result.push(params[i]);
			}
	}

	return "?" + result.join("&");
}

function getParentTag(object, tagName){
	var parentElement = object;
	do{
		parentElement = parentElement.parentNode;
	}while(tagName && parentElement.tagName.toLowerCase() != tagName.toLowerCase())

	return parentElement;
}