/**
 * Javascript framework for design patterns 
 * @fileoverview IAJS global namespace object
 * 
 * @author Internet Architects BVBA
 * @version 1.0RC
 * @copyight 2007
 */
 
if (typeof IAJS == "undefined") {
	var IAJS = {};
	IAJS.CONFIG = {
		debug: false,
		showDebugCategory: {error:true,warn:true,time:false,info:false,window:false}, // default debug categories.
		animateCE : true, 		// boolean animate collapse expand
		animateCESpeed : .2, 	// collapse expand animation speed (default .2)
		expandTextarea : true,
		controllerIdCounter : 0 // private counter to generate unique controllerId;
	};
	IAJS.CONFIG.dateFormat = { euro : 0, american : 1, iso : 2};
	IAJS.CONFIG.defaultDateFormat = IAJS.CONFIG.dateFormat.euro;
}
/**
 * Initialize
 */
IAJS.init = function(){}
/**
 * Provides controllers used by the library
 * @class IAJS.CONTROLLER
 * @member IAJS.CONTROLLER
 */
IAJS.CONTROLLER = function(){}
/**
 * Provides forms used 
 */
IAJS.controllerCollection = new Object;
/**
 * Provides validation used by the library
 * @member IAJS.VALIDATION
 */
IAJS.VALIDATION = function(){}
/**
 * log messages
 * @param {String} messgage the message to log
 * @param {String} the category of the message ("warn" "error" "info" "win")
 * @param {IAJS.CONTROLLER} the controller the log message is refuring to
 * @class IAJSs
 */
IAJS.log = function(message, category, controller){
	if (IAJS.CONFIG.debug){
		if(controller){
			//var ctrl =  (controller.getControllerId)? controller.getControllerId() : "unknown";
			var ctrl =  "unknown";
			var ctrlType =  controller.objectType || "unknown";
			YAHOO.log("(" + ctrl + "[" + ctrlType + "]): " + message, category);
		} else {
			YAHOO.log(message, category);
		}
	}
}
/**
 * @class IAJS.OBSERVER
 */
IAJS.OBSERVER = function(){
	showEvent: null;
}
/**
 * @base IAJS.OBSERVER
 */
IAJS.OBSERVER.getInstance = function(){
	if(!this.showEvent){
		this.showEvent = new YAHOO.util.CustomEvent("showEvent", this);
		this.showEvent.subscribe(function(){IAJS.log("IAJS.OBSERVER fired", "warn");});
	}
 	return this.showEvent;
}
/**
 * 
 */
IAJS.FORMS = function(){
	forms: null;
};
/**
 * 
 */
IAJS.FORMS.getInstance = function(){
	if(!this.forms){
		this.forms = new IAJS.CONTROLLER.Forms();
		this.forms.init();
	}
	return this.forms;
}
/**
 * @class Event
 */
IAJS.Event = function(){};
/**
 * @param {IAJS.CONTROLLER|id} ctl Controller or id that identifies the controller
 * @param {String} type The type of event 
 * @param {Function} fn The function the event will be evaluated
 * @param {Object}scope The execution scope of the execution event
 * @return {Boolean} True if successfull, false if unsucsessfull 
 * @base IAJS.Event
 */
IAJS.Event.On = function(ctl, type, fn, scope){
	if (! ctl || !type ) {
		IAJS.log("EVENT: invalid arguments (c: " + ctl + ", e: " + type + ")","error");
		return false;
	}
	/*
	 * check if controller exists & has events
	 */
	var ctl = (typeof(ctl) == "object")? ctl.getControllerId(): ctl; // get controller id if IAJS.CONTROLLER is passed
	
		
	if (!ctl || !IAJS.controllerCollection[ctl]) {S
		IAJS.log("EVENT: controller not found in collection (c: " + ctl + ", e: " + type + ")","error");
		return false;
	}
	if (!type || !IAJS.controllerCollection[ctl].getEvents()) {
		IAJS.log("EVENT: controller event not found (c: " + ctl + ", e: " + type + ")","error");
		return false;
	}
	/*
	 * check if event exists
	 */
	var events = IAJS.controllerCollection[ctl].getEvents();
	if (!events[type]) {
		IAJS.log("EVENT: controller event not found (c: " + ctl + ", e: " + type + ")","error");
		return false;
	}
	/*
	 * ad function to event 
	 */
	 if(scope){
	 	events[type].subscribe(fn, scope, true); 
	 } else {
	 	events[type].subscribe(fn);	
	 }
	return true;
}
/**
 * @class IAJS.ELATTR
 */
IAJS.ELATTR = {};
/**
 * Validate format and parse master elattr to object
 * elattr:master format:
 *	 	masterController , masterElement, action
 * 		masterController , masterElement 	(with default eventType)
 * 		masterElement 						(with default eventType, no masterController)
 * @param {IAJS.CONTROLLER} c The controller to get the master value from
 * @return {Object|Boolean} Object(controller:value, element:value, action:value) if succesfull otherwise false
 * @base IAJS.ELATTR 
 */
IAJS.ELATTR.parseMaster = function(c){
	if (c && c.elattr && c.elattr.master && c.elattr.master != ""){
		masterArr = c.elattr.master.split(",");
		if (!masterArr && masterArr.length < 2) return false;
		
		var masterController = (masterArr[1]) ? masterArr[0] : false;
		var masterElement = (masterArr[1]) ? masterArr[1] : masterArr[0];
		var masterAction = masterArr[2] || false;
		return {controller: masterController, element: masterElement, action: masterAction};
	} else {
		return false;
	}
}
/**
 * Parse master elattr part of controller and check presence of master controller in collection
 * @param {IAJS.CONTROLLER} c The controller to get the master value from
 * @return {Object|Boolean} Object(controller:value, element:value) if succesfull otherwise false
 * @base IAJS.ELATTR 
 */
IAJS.ELATTR.getMaster = function(c){
	var master = IAJS.ELATTR.parseMaster(c);
	if (master) {
		if (!IAJS.controllerCollection[master.controller || master.element]){
			IAJS.log("elattr:master found but not in controllerCollection","error", c);
			return false;
		}
	} else {
		return false;
	}
	return master;
}
/**
 * Parse subordinate elattr part of controller
 * @param {IAJS.CONTROLLER} c The controller to parse the subordinate value from
 * @return {Object|Boolean} Object(controller:value, element:value) if succesfull otherwise false
 * @base IAJS.ELATTR 
 */
IAJS.ELATTR.parseSubordinate = function(c){
	if (c && c.elattr && c.elattr.subordinate && c.elattr.subordinate != ""){
		subordinateArr = c.elattr.subordinate.split(",");
		if (!subordinateArr && subordinateArr.length < 2) return false;
		var subordinateController = (subordinateArr[1]) ? subordinateArr[0] : false;
		var subordinateElement = (subordinateArr[1]) ? subordinateArr[1] : subordinateArr[0];
	
		return {controller: subordinateController, element: subordinateElement};		
	} else {
		return false;
	}
}
/**
 * Parse subordinate elattr part of controller and check presence of subordinate controller in collection
 * @param {IAJS.CONTROLLER} c The controller to get the subordinate value from
 * @return {Object|Boolean} Object(controller:value, element:value) if succesfull otherwise false
 * @base IAJS.ELATTR 
 */
IAJS.ELATTR.getSubordinate = function(c){
	var subordinate = IAJS.ELATTR.parseSubordinate(c);
	if (subordinate) { 
		if (!IAJS.controllerCollection[subordinate.controller]){
			IAJS.log("elattr:subordinate found but not in controllerCollection","error", c);
			return false;
		}
	} else {
		return false;
	}
	return subordinate;
}
/**
 * Calculate date range based on date and offset
 * @param date
 * @param diff In forgiving format
 */
IAJS.ELATTR.calcDateDiff = function(date, diff){
	if (!date || !diff) return false;
	if ((/[^0-9|d|m|y]+/).test(diff)) return false; //there should only be legal characters in diff
	var date1 = date.toStructuredDateArray();
	IAJS.log("D1pp " + date1[2],"error");
	
	date1 = new Date(date1[2],date1[1],date1[0]); 		
	
	
	var date2 = new Date(date1.getTime());
	IAJS.log("CC " + date1.getDay() + " " +  date1.getMonth() +" " + date1.getYear(),"error");
	// parse diff string into usable numbers, null if not match
	var yearsDiff = diff.match(/(\d+)y/);
	var monthsDiff = diff.match(/(\d+)m/);
	var daysDiff = diff.match(/(\d+)d/);	
	IAJS.log("AA " + yearsDiff + " " +  monthsDiff +" " + daysDiff,"error");
	if (yearsDiff) date2.setFullYear(date1.getFullYear() + yearsDiff[1]);
	if (monthsDiff) {
		var newMonth = parseInt(date1.getMonth()) + parseInt(monthsDiff[1]);
		var years = 0;
		IAJS.log("BB " + newMonth,"error");
		if (newMonth < 0) {
			while (newMonth < 0) {
				newMonth += 12;
				years -= 1;
			}
		} else if (newMonth > 11) {
			while (newMonth > 11) {
				newMonth -= 12;
				years += 1;
			}
		}				
		date2.setMonth(newMonth);
		date2.setFullYear(date1.getFullYear() + years);		
	}
	if (daysDiff) {
		IAJS.log("daysDiff","error");
		date2.setDate(date1.getDate() + daysDiff[1]);
	}
	IAJS.log("CC " + date2.getDay() + " " +  date2.getMonth() +" " + date2.getYear(),"error");
	return date2;
}
