/**
 * An event. What happens, when the event occurs, depends on which functions have been
 * registered with the event. 
 * 
 * usage:
 * 
 * // create a new Event
 * var eventAfterMapRequest = new MapbenderEvent(); 
 * 
 * // register a function with that event
 * eventAfterMapRequest.register(function () {
 * 	...
 * })
 * 
 * // trigger the event
 * eventAfterMapRequest.trigger();
 * 
 */
var MapbenderEvent = function () {
	
	// public methods
	/**
	 * A function that needs to be executed, when the event occurs, has to be 
	 * registered via this function.
	 */
	this.register = function(aFunction) {
		var mpbnFunction = new MapbenderFunction(aFunction);
		functionArray.push(mpbnFunction);
	};

	/**
	 * Exclude a previously registered function from the event
	 */
	this.unregister = function(aFunction) {
		for (var i = 0, len = functionArray.length; i < len; i++) {
			if (functionArray[i].getFunction() === aFunction) {
				for (var j = i + 1; j < len; j++) {
					functionArray[j-1] = functionArray[j];
				}
				delete functionArray[len - 1];
				len = len - 1;
			}
		}
		functionArray.length = len;
	};

	/**
	 * Checks if a function is already registered with this event
	 */
	this.isRegistered = function (aFunction) {
		for (var i = 0, len = functionArray.length; i < len; i++) {
			if (functionArray[i].getFunction() === aFunction) {
				return true;
			}
		}
		return false;
	};
	
	/**
	 * This function triggers the event
	 */
	this.trigger = function(properties, booleanOperator) {
		if (!(functionArray.length > 0)) {
			return true;
		}
		//
		// check arguments
		//
		// properties
		if (typeof(properties) != "object") {
			// maybe properties is missing, and so 
			// properties represents booleanOperator
			if (typeof(booleanOperator) == "undefined") {
				booleanOperator = properties;
				properties = undefined;
			}
			else {
//				var e = new Mb_exception("MapbenderEvent.trigger: invalid properties: %s", properties);
			}
		}		

		// booleanOperator
		if (typeof(booleanOperator) == "string") {
			if (booleanOperator != "AND" && booleanOperator != "OR") {
//				var e = new Mb_exception("MapbenderEvent.trigger: invalid booleanOperator: %s", booleanOperator);
			}
		}		
		else if (typeof(booleanOperator) != "undefined") {
//			var e = new Mb_exception("MapbenderEvent.trigger: invalid booleanOperator, must be a string, but is %s", typeof(booleanOperator));
		}
		
		var result;

		// the optional boolean operator allows to combine the return values of the functions
		// into a single result value.
		switch (booleanOperator) {
			case "AND":
				result = true;
				break;
			case "OR":
				result = false;
				break;
			default:
				result = true;
				break;
		}

		if (log) {
			var e = new Mb_notice("functions (after sort): " + functionArray.join(","));
		}

		for (var i = 0; i < functionArray.length; i++) {
			// executes the function at position i
			// and determines the return value based on the (optional) boolean operator
			switch (booleanOperator) {
				case "AND":
					result = result && functionArray[i].execute(properties);
					break;
				case "OR":
					result = result || functionArray[i].execute(properties);
					break;
				default:
					result = functionArray[i].execute(properties);
					break;
			}
		}
		return result;
	};	
	
	this.getProperties = function () {
		return propertiesObj;
	};

	// private
	/**
	 * these functions will be executed once the event is triggered
	 */
	var functionArray = [];
	
	var propertiesObj;
	var log = false;
};

/**
 * A MapbenderFunction is a function with a priority.
 */
var MapbenderFunction = function (aFunction) {
	
	// public
	/**
	 * Returns the function itself
	 */
	this.getFunction = function () {
		return func;
	};
	
	/**
	 * Executes the function
	 */
	this.execute = function (argumentObj) {
		if (typeof(aFunction) == "function") {
			return func(argumentObj);
		}

		// this branch is for backwards compatibility with the 
		// pre-2.5 event system that is based on strings.
		else {
			var argumentNames = [];
			var argumentValues = [];
			for (var i in argumentObj) {
				if (typeof(argumentObj[i]) == "number" || typeof(argumentObj[i]) == "boolean") {
					argumentNames.push(i);
					argumentValues.push(argumentObj[i]);
				}
				else if (typeof(argumentObj[i]) == "string") {
					argumentNames.push(i);
					argumentValues.push("'" + argumentObj[i] + "'");
				}
			}
			var str = "";
			str += "(function (" + argumentNames.join(", ") + ") {";
			str += "return " + aFunction;
			str += "}";
			str += "(" + argumentValues.join(", ") + "));";
			var returnValue = eval(str);
			return returnValue;
		}	
	};
	
	// private
	var func = aFunction;
};
var currentWmcExtensionData = {};
var restoredWmcExtensionData = {};

//var mb_MapRequestSubFunctions = [];
//var mb_MapRequestPreFunctions = [];
//var mb_MapObjectSubFunctions = [];
//var mb_GetScalePreFunctions = [];
//var mb_FeatureInfoPreFunctions = [];
//var mb_loadWmsSubFunctions = [];
//var mb_InitFunctions = [];
var mb_WfsReadSubFunctions = [];
var mb_WfsWriteSubFunctions = [];
var mb_l10nFunctions = [];

/**
 * Triggered after a map is requested.
 */
var eventAfterMapRequest = new MapbenderEvent();

/**
 * Triggered before a map is requested.
 */
var eventBeforeMapRequest = new MapbenderEvent();

/**
 * Triggered before the scale is calculated.
 */
var eventBeforeGetScale = new MapbenderEvent();

/**
 * Triggered before a feature info is requested.
 */
var eventBeforeFeatureInfo = new MapbenderEvent();

/**
 * Triggered after a WMS has been loaded.
 */
var eventAfterLoadWMS = new MapbenderEvent();

/**
 * Triggered when Mapbender is loaded and after the map object has been initialised.
 */
var eventInit = new MapbenderEvent();

/**
 * Initializes the map object. Triggered when Mapbender is loaded. 
 */
var eventInitMap = new MapbenderEvent();

/**
 * Switches the locale. Triggered by module switch_locale or onload(?) 
 */
var eventLocalize = new MapbenderEvent();

/**
 * Triggered after the map object has been created. 
 */
var eventAfterMapObjectConstruction = new MapbenderEvent(); // possibly obsolete!

/**
 * Triggered after the map has been resized
 */
var eventResizeMap = new MapbenderEvent();

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerInitFunctions(stringFunction){
//	mb_InitFunctions[mb_InitFunctions.length] = stringFunction;
	eventInit.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerPreFunctions(stringFunction){
//	mb_MapRequestPreFunctions[mb_MapRequestPreFunctions.length] = stringFunction;
	eventBeforeMapRequest.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerFeatureInfoPreFunctions(stringFunction){
//	mb_FeatureInfoPreFunctions[mb_FeatureInfoPreFunctions.length] = stringFunction;
	eventBeforeFeatureInfo.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerSubFunctions(stringFunction){
//	mb_MapRequestSubFunctions[mb_MapRequestSubFunctions.length] = stringFunction;
	eventAfterMapRequest.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerMapObjectSubFunctions(stringFunction){
//	mb_MapObjectSubFunctions[mb_MapObjectSubFunctions.length] = stringFunction;
	eventAfterMapObjectConstruction.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerGetScalePreFunctions(stringFunction){
//	mb_GetScalePreFunctions[mb_GetScalePreFunctions.length] = stringFunction;
	eventBeforeGetScale.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerloadWmsSubFunctions(stringFunction){
//	mb_loadWmsSubFunctions[mb_loadWmsSubFunctions.length] = stringFunction;
	eventAfterLoadWMS.register(stringFunction);
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerWfsReadSubFunctions(stringFunction){
	mb_WfsReadSubFunctions[mb_WfsReadSubFunctions.length] = stringFunction;
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerWfsWriteSubFunctions(stringFunction){
	mb_WfsWriteSubFunctions[mb_WfsWriteSubFunctions.length] = stringFunction;
}

/**
 * deprecated wrapped function
 * @deprecated
 */
function mb_registerL10nFunctions(stringFunction) {
	eventLocalize.register(stringFunction)
//	mb_l10nFunctions[mb_l10nFunctions.length] = stringFunction;
}

var mb_PanSubElements = [];
function mb_registerPanSubElement(elName){
	var ind = mb_PanSubElements.length;
	mb_PanSubElements[ind] = elName;
}

var mb_vendorSpecific = [];
function mb_registerVendorSpecific(stringFunction){
	mb_vendorSpecific[mb_vendorSpecific.length] = stringFunction;
}

/**
 * deprecated function for writing content within a tag via innerHTML
 * @deprecated
 */
function writeTag(frameName, elName, tagSource) {
  if(frameName && frameName !== ""){
     window.frames[frameName].document.getElementById(elName).innerHTML = tagSource;
  }
  else if(!frameName || frameName === ""){
       document.getElementById(elName).innerHTML = tagSource;
  }
}
