/*
 * Eeecore Client
 * 
 * E.Bootstrapper	Client Initialization
 * E.Log 			Logger, Firebug and HTML output
 * E.String 		String functions
 * E.Key 			Keyboard functions
 * E.Ext			Ext JS Improvements
 * E.UserManager	Current User Object, rendering
 * 
 */

if(!this.E) E = {};
E._id= 'Eeecore';

E.Bootstrapper = {
	runLevel : 0,
	modules : {},
	initialize : function(modules, namespace) {
		if (!modules) {
			modules = E;
			this.runLevel = 1; // Start the application
		}

		namespace = namespace ? namespace : E._id;

		E.Log.writeLn('Intializing namespace: "' + namespace + '"', 10);

		for (var i in modules) {
			var firstLetter = i[0];
			if (i == 'Bootstrapper' || firstLetter == '_')
				continue;
			var module = modules[i];
			if (!E.Bootstrapper.modules[namespace]) {
				E.Bootstrapper.modules[namespace] = []; // create namespace
			}
			// set the right id if non is set
			module._id = module._id ? module._id : i;
			module._runLevel = this.runLevel;

			E.Bootstrapper.modules[namespace].push(module);

			// call the initialize function in all single modules
			if (typeof module.initialize == 'function') {
				module.initialize.call(module);
				E.Log.writeLn(namespace + '.' + module._id + '.initialize function called', 10);
			}
		}
		// register domReady function
		jQuery(document).ready(E.Bootstrapper.domReady);
	},
	/**
	 * is calling every domReady function in each module in a namespace
	 */
	domReady : function() {
		for (var namespace in E.Bootstrapper.modules) {
			var modules = E.Bootstrapper.modules[namespace];
			for (var i in modules) {
				var module = modules[i];
				var id = module._id;
				var runLevel = module._runLevel;
				if (typeof module.domReady == 'function' && runLevel <= 1) {
					module.domReady.call(module);
					module._runLevel = 2;
					E.Log.writeLn(namespace + '.' + id + '.domReady function called', 10);
				}
			}
		}
		this.runLevel = 2; // set applications run level
	},

	register : function(module) {
		if (!module || typeof module != 'object' || !module._id) {
			E.Log.writeLn('Invalid module given, could not register. please provide at least an "_id" variable in the module.',1);
			return false;
		}
		this.initialize(module, module._id);
	},
	registerPlugin : function(module) {
		if (!module || typeof module != 'object' || !module._id) {
			E.Log.writeLn('Invalid module given, could not register. please provide at least an "_id" variable in the module.',1);
			return false;
		}
		this.initialize([module], module._id);
	}

};

E.Check = {
	_id: 'Check',
	isArray: function(value){
		if (!value || !value.constructor) return false;
		return (value.constructor.toString().indexOf("Array") != -1);
	},
	isInteger: function(value){
		return (value == +value);
		
	},
	isEmpty: function(ob){
		for(var i in ob){ return false;}
		return true;
	}
};


/**
 * Eeecore String Module
 */
E.String = {
	_id : 'String',
	initialize : function() {
		// TODO: check for loaded jQuery plugin
	},
	urlencode: function(str) {
		str = escape(str);
		str = str.replace('+', '%2B');
		str = str.replace('%20', '+');
		str = str.replace('*', '%2A');
		str = str.replace('/', '%2F');
		str = str.replace('@', '%40');
		return str;
	},
	urldecode: function(str){
		str = str.replace('+', ' ');
		str = unescape(str);
		return str;
	},
	htmlencode: function(domTarget, string){
		if (!string) {
			return jQuery(domTarget).each(function(){
				var me = jQuery(this);
				var html = me.html();
				me.html(html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'));
			});
		} else if (domTarget) {
			return domTarget.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
		}
		
		return domTarget;
	},
	htmldecode: function(domTarget, string){
		if (!string) {
			return jQuery(domTarget).each(function(){
				var me = jQuery(this);
				var html = me.html();
				me.html(html.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>'));
			});
		} else if (domTarget) {
			return domTarget.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
		}
		
		return domTarget;
	},
	htmlencoded: function(str){
		if (str.search(/&amp;/g) != -1 || str.search(/&lt;/g) != -1 || str.search(/&gt;/g) != -1) return true; 
		return false;
	},
	htmlencodeIfEncoded: function(domTarget){
		return jQuery(domTarget).each(function(){
			var me = jQuery(this);
			var html = me.html();
			if(E.String.htmlencoded(html))
				me.html(html.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>'));
			});
	},
	
	
	/**
	 * trim whitespace before the string and after
	 * 
	 * @param {String}
	 *         string
	 */
	trim : function(string) {
		return string.replace(/^\s+|\s+$/g, "");
	},

	/**
	 * remove whitespace on the beginning of the string
	 * 
	 * @param {string}
	 *            string
	 */
	ltrim : function(string) {
		return string.replace(/^\s+/, "");
	},
	rtrim : function(string) {
		return string.replace(/\s+$/, "");
	},

	/**
	 * retrieves a sub string of a given string, defined by start and length
	 * 
	 * @param {String}
	 *            string
	 * @param {Integer}
	 *            start
	 * @param {Integer}
	 *            length
	 */
	substr : function(string, start, length) {
		string += '';
		if (start < 0) {
			start += string.length;
		}

		if (length == undefined) {
			length = string.length;
		} else if (length < 0) {
			length += string.length;
		} else {
			length += start;
		}

		if (length < start) {
			length = start;
		}
		return string.substring(start, length);
	},

	/**
	 * Replace string
	 * 
	 * @param {Object}
	 *            search
	 * @param {Object}
	 *            replace
	 * @param {Object}
	 *            subject
	 */
	str_replace: function(search, replace, subject) {
		if (!subject) return '';
		return subject.split(search).join(replace);
	},

	
	/**
	 * Truncate the given string to given length and append "..." dots to make it visible
	 */
	truncate: function(value, length){
		if (!length || length <=0 ) return value;
		
		if(value && value.length > length) {
			value = value.substr(0,length) + '...';
		}
		return value;
	}

};

/* Eeecore Language Module */

E.Lang = {
	_id : 'Language',
	initialize : function() {
	},
	getKey: function() {
		if(!window.L) return false;
		
		var currentTarget = L;
		return currentTarget._key;
	},
	fallback: function(key) {
		E.Log.writeLn('Using fallback for the translation key "' + key + '"', 4);
		var target = key.split('.');
		
		if(target.length >= 3) {
			// if model, return field name as fallback
			
			if(target[0] == 'models') {
				if(L.globals && L.globals.fields && target[2] in L.globals.fields && L.globals.fields[target[2]][target[3]]) {
					return L.globals.fields[target[2]][target[3]];
				}
				else if(target[2] == '_name'){	// Model tables like "models.Modelname._name.header"
					return target[1];
				}
				return target[2];
			}
			
			// if routes, return controllername and action
			else if(target.length >= 4 && target[0] == 'routes') {
				return target[2]+' '+target[3];
			}
		}
		
		E.Log.writeLn('Could not find the translation key "' + key + '"', 1);
		return key;
	},
	// check if there is a translation for that key
	hasTranslation : function() {
		
		if (arguments.length <= 0)
			return false;

		var params = [];
		var key, translated;
		for ( var i = 0; i < arguments.length; i++) {
			if (i == 0) {
				key = arguments[i];
			} else {
				params.push(arguments[i]);
			}
		}
		translated = key;
		var target = key.split('.');

		if(!window.L) return false;
		
		var currentTarget = L;
		
		for ( var i = 0; i < target.length; i++) {
			var name = target[i];
			if (currentTarget[name]) {
				currentTarget = currentTarget[name];
				translated = currentTarget;
			} else {
				return false;
			}
		}
		
		return true;
	},
	// translate it
	translate : function() {

		if (arguments.length <= 0)
			return false;

		var params = [];
		var key, translated;
		for ( var i = 0; i < arguments.length; i++) {
			if (i == 0) {
				key = arguments[i];
			} else {
				params.push(arguments[i]);
			}
		}
		translated = key;
		var target = key.split('.');

		if(!window.L) return false;
		
		var currentTarget = L;
		
		for ( var i = 0; i < target.length; i++) {
			var name = target[i];
			if (currentTarget[name]) {
				currentTarget = currentTarget[name];
				translated = currentTarget;
			} else {
				translated = E.Lang.fallback(key);
				var fallbackUsed = true;
				break;
			}
		}
		
		if(!fallbackUsed) {
			translated = currentTarget;
			
			if (typeof currentTarget == 'object') {
				translated = key;
			}
		}
		
		var results = translated.match(/\[([^\[\]])*\]/g);
		if (results && results.length > 0) {
			var n = 1;

			for ( var j = 0; j < results.length; j++) {

				var result = results[j];
				var paramValue = params.shift(); // get the param
				var cleanedFound = E.String.trim(result);
				cleanedFound = E.String.substr(cleanedFound, 1);
				cleanedFound = E.String.substr(cleanedFound, 0, -1);
				var nth = cleanedFound.split('|');
				var singular = nth[0];
				var plural = nth[1];

				// check if it is singular or plural
				if (Math.abs(parseInt(paramValue)) <= 1 && Math.abs(parseInt(paramValue)) !== 0) {
					singular = E.String.str_replace('_' + n, paramValue,
							singular);
					translated = E.String.str_replace(result, singular,
							translated);
				} else {
					plural = E.String.str_replace('_' + n, paramValue, plural);
					translated = E.String.str_replace(result, plural, translated);
				}
				n++;
			}
		}

		return translated;
	}
};


/* Eeecore Exception */
E.Exception={
	_id : 'Exception',
	writeLn: function(e, invokerName){
		
		if (!invokerName){
			invokerName = e.fileName;
		}
		
		E.Log.writeLn('Exception "'+e.name+'"  with message "'+e.message+'" occured in :'+invokerName+'. Stacktrace:', 1);
		
		if (e.stack){
			var parts = e.stack.split('\n');
			var nr = parts.length;
			for (var i in parts){
				E.Log.writeLn(E.Exception._id+' ['+nr+']: '+parts[i],1);
				nr--;
			}
		}
		
	}
};


/* Eeecore Client Logger */

E.Log = {
	_id : 'Log',
	items : [],
	targetId : '#logger ul',
	getTimeString : function(date) {
		if (!date)
			date = new Date();
		return date.getDate() + '.' + date.getMonth() + '.'
				+ date.getFullYear() + ' ' + date.getHours() + ':'
				+ date.getMinutes() + ':' + date.getSeconds();
	},
	initialize : function() {
		for ( var i = 0; i < E.Log.items.length; ++i) {
			E.Log.writeLn(E.Log.items[i]);
			delete E.Log.items[i];
		}
	},
	domReady : function() {
		// write all texts from the puffered array
		var targetEl = jQuery(E.Log.targetId);
		if (!targetEl)
			return;
		if (E.Log.items.length > 0) {
			for ( var i = 0; i < E.Log.items.length; i++) {
				targetEl.prepend(E.Log.items[i]);
				delete E.Log.items[i];
			}
		}
	},
	add : function(item) {
		E.Log.items.push(item);
	},
	writeLn : function() {
		var level = 10;
		var args = [ this._id ];

		for ( var i = 0; i < arguments.length; i++) {
			if (i >= (arguments.length - 1)
					&& arguments[arguments.length - 1] >= 1
					&& arguments[arguments.length - 1] <= 11) {
				level = arguments[arguments.length - 1];
			} else {
				args.push(arguments[i]);
			}
		}
		var text = ''; // prefix
		for ( var i = 0; i < args.length; ++i) {
			text += args[i] + ', ';
		}


		

		if (!("console" in window && window.console.log && window.console.log.apply)) {
			
			/*
			var logClass = 'DEBUG';
			switch (level) {
			case 1:
				logClass = 'EMERG';
				break;
			case 2:
				logClass = 'ALERT';
				break;
			case 3:
				logClass = 'CRIT';
				break;
			case 4:
				logClass = 'ERR';
				break;
			case 5:
				logClass = 'WARN';
				break;
			case 6:
				logClass = 'NOTICE';
				break;
			case 7:
				logClass = 'EMERG';
				break;
			case 8:
				logClass = 'STATUS';
				break;
			case 9:
				logClass = 'DEBUG';
				break;
			case 10:
				logClass = 'INFO';
				break;
			case 11:
				logClass = 'PROFILER';
				break;
			}
			text = '<li class="' + logClass + '"><strong>'
					+ E.Log.getTimeString() + ' ' + text + '</strong></p>';
			var targetEl = jQuery(E.Log.targetId);
			if (targetEl) {
				targetEl.prepend(text);
			} else {
				E.Log.items.push(text); // push the rendered text
			}
			*/
		} else {// firebug console
			
			switch (level) {
			case 1:
			case 2:
			case 3:
				console.error(args);
				break;
			case 4:
			case 5:
			case 6:
				console.warn.apply(console, args);
				break;
			case 7:
			case 8:
			case 9:
			case 10:
				console.log.apply(console, args);
				break;
			case 11:
				console.timeStamp(args);
				break;
			}
		}
	},
	/* Email antispam */
	Rot13 : {
		map : null,
		convert : function(a) {
			Rot13.init();

			var s = "";
			for (var i = 0; i < a.length; i++) {
				var b = a.charAt(i);
				s += ((b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') ? Rot13.map[b]
						: b);
			}
			return s;
		},
		initialize : function() {
			if (Rot13.map != null)
				return;

			var map = new Array();
			var s = "abcdefghijklmnopqrstuvwxyz";

			for (var i = 0; i < s.length; i++)
				map[s.charAt(i)] = s.charAt((i + 13) % 26);
			for (var i = 0; i < s.length; i++)
				map[s.charAt(i).toUpperCase()] = s.charAt((i + 13) % 26)
						.toUpperCase();
			Rot13.map = map;
		},
		write : function(a) {
			document.write(Rot13.convert(a));
		}
	}

};


E.Bootstrapper.initialize();


Date.monthNames = [
   E.Lang.translate('globals.dates.months.january.full'),
   E.Lang.translate('globals.dates.months.february.full'),
   E.Lang.translate('globals.dates.months.march.full'),
   E.Lang.translate('globals.dates.months.april.full'),
   E.Lang.translate('globals.dates.months.may.full'),
   E.Lang.translate('globals.dates.months.june.full'),
   E.Lang.translate('globals.dates.months.july.full'),
   E.Lang.translate('globals.dates.months.august.full'),
   E.Lang.translate('globals.dates.months.september.full'),
   E.Lang.translate('globals.dates.months.october.full'),
   E.Lang.translate('globals.dates.months.november.full'),
   E.Lang.translate('globals.dates.months.december.full')
];

Date.dayNames = [
   E.Lang.translate('globals.dates.days.sunday.full'),
   E.Lang.translate('globals.dates.days.monday.full'),
   E.Lang.translate('globals.dates.days.tuesday.full'),
   E.Lang.translate('globals.dates.days.wednesday.full'),
   E.Lang.translate('globals.dates.days.thursday.full'),
   E.Lang.translate('globals.dates.days.friday.full'),
   E.Lang.translate('globals.dates.days.saturday.full')
];


