/**
 * Application object
 *
 */
var app;

/**
 * Application core class
 *
 */
var App = function(){};

App.prototype = {
	version: '1.0.0',
	modules: [],
	functions: [
		{name: 'getOption', fn: 'this.getOption'}
	],
	/**
	 * Initialize
	 *
	 * @return void
	 */
	initialize: function() {
	},

	/**
	 * Register module
	 *
	 * @param module object
	 * @return void
	 */
	registerModule: function(module) {
		try {
			if (isObject(module) && isString(module.name) && module.name) {
				/**
				 * Set module options
				 * 
				 */
				this.setModuleOptions(module);

				var options = this.getOption('module', module);
				
				if (isObject(options)) {
					/**
					 * Extend module
					 *
					 */
					if (isDefined(options.extend) && options.extend) {
						for (var i=0; i<options.extend.length; i++) {
							this.extendModule(module, options.extend[i]);
						}
					}
					
					/**
					 * Implement modules
					 *
					 */
					if (isDefined(options.implement) && isArray(options.implement)) {
						for (var i=0; i<options.implement.length; i++) {
							this.implementModule(module, options.implement[i]);
						}
					}

					/**
					 * Append common functions
					 * 
					 */
					this.appendCommonFunctions(module);

					if (isDefined(options.append) && options.append) {
						/**
						 * Append module to core object
						 *
						 */
						this.appendModule(module);

						if (this.checkModule(module.name) && isFunction(this[module.name].initialize)) {
							this[module.name].initialize();
						}
					}
				} else {
					throw 'Invalid module options: '+module.name;
				}
			} else {
				throw 'Invalid module: '+module.toString();
			}
		} catch (e) {
			if (this.checkModule('debug')) {
				this.debug.error(e);
			}
		}
	},

	/**
	 * Append module
	 *
	 * @param module object
	 * @return void
	 */
	appendModule: function(module) {
		if (isUndefined(this[module.name])) {
			this[module.name] = module;
			/*
			this[module.name].parent = this;
			*/

			this.modules.push(module.name);
		} else {
			throw 'Error appending module: '+module.name.toString();
		}
	},

	/**
	 * Append common functions
	 *
	 * @param module object
	 * @return void
	 */
	appendCommonFunctions: function(module) {
		if (isArray(this.functions) && this.functions.length) {
			for (var i=0; i<this.functions.length; i++) {
				if (isObject(this.functions[i])) {
					var name = this.functions[i].name;
					var func = eval(this.functions[i].fn);
					
					if (isFunction(func) && isUndefined(module[name])) {
						module[name] = func;
					} else {
						if (this.debug) {
							/*this.debug.warn('Error appending common function '+name+' to '+module.name);*/
						}
					}
				} else {
					throw 'Invalid common function '+this.functions[i].toString();
				}
			}
		}
	},

	/**
	 * Implement module
	 *
	 * @param module object
	 * @param name string
	 * @return void
	 */
	implementModule: function(module, name) {
		if (this.checkModule(name) && isObject(module)) {
			if (isUndefined(module[name])) {
				module[name] = this[name];
			} else {
				if (this.debug) {
					this.debug.warn('Error implementing module: '+name+' to '+module.name);
				}
			}
		} else {
			throw 'Error implementing module: '+name+' to '+module.name;
		}
	},

	/**
	 * Extend module
	 *
	 * @param module object
	 * @param name string
	 * @return void
	 */
	extendModule: function(module, name) {
		if (this.checkModule(name) && isObject(module)) {
			if (isUndefined(module[name])) {
				for (var prop in this[name]) {
					if (isUndefined(module[prop]) && prop.match(/^[^_]/)) {
						module[prop] = this[name][prop];
					}
				}
			} else {
				if (this.debug) {
					this.debug.warn('Error extending module: '+module.name+' with '+name);
				}
			}
		} else {
			throw 'Error extending module: '+module.name+' with '+name;
		}
	},

	/**
	 * Set module options
	 *
	 * @param module string
	 * @return void
	 */
	setModuleOptions: function(module) {
		if (isObject(AppOptions) && isObject(AppOptions[module.name]) && isObject(module.options)) {
			mergeObjects(module.options, AppOptions[module.name]);
		}
	},

	/**
	 * Check module
	 *
	 * @param name string
	 * @return void
	 */
	checkModule: function(name) {
		if (name && inArray(name, this.modules) && isObject(this[name])) {
			return true;
		}
		return false;
	},

	/**
	 * Get module object
	 *
	 * @param name
	 * @return object
	 */
	getModule: function(name) {
		if (this.checkModule(name)) {
			return this[name];
		}
		return false;
	},

	/**
	 * Unregister module
	 *
	 * @param name string
	 * @return void
	 */
	unRegisterModule: function(name) {
		try {
			if (this.checkModule(name)) {
				this[name] = null;
			} else {
				throw 'Invalid module: '+name.toString();
			}
		} catch (e) {
			if (this.checkModule('debug')) {
				this.debug.error(e);
			}
		}
	},

	/**
	 * Get object option
	 *
	 * @param path string
	 * @param obj object
	 * @return mixed
	 */
	getOption: function(path, obj) {
		var option = null;

		if (isUndefined(obj) && isObject(this)) {
			obj = this;
		}
		
		if (isString(path) && isObject(obj.options)) {
			option = obj.options;
			var keys = path.split('/');

			if (keys instanceof Array) {
				$.each(keys, function(key, value) {
					if (isObject(option) && option.hasOwnProperty(value)) {
						option = option[value];
					} else {
						option = null;
					}
				});
				
			}
		}
		return option;
	}
};

/**
 * Create application core object
 *
 */
function startApp() {
	app = new App();
	app.initialize();
}

addOnLoadListener(startApp, {});

/**
 * Application module loader class
 *
 */
var AppLoader = {
	/**
	 * Default modules
	 * 
	 */
	modules: [
		{name: 'debug', path: 'auto'},
		{name: 'browser', path: 'auto'},
		{name: 'cookie', path: 'auto'},
		{name: 'panel', path: 'auto'},
		{name: 'overlay', path: 'auto'},
		{name: 'ajax', path: 'auto'},
		{name: 'core', path: 'auto'},
		{name: 'dictionary', path: 'auto'},
		{name: 'site', path: 'auto'}
	],
	registeredModules: 0,

	/**
	 * Load JavaScript file
	 *
	 * @param module string
	 * @return void
	 */
	loadScript: function(file) {
		document.write('<script type="text/javascript" src="'+file+'"><\/script>');
	},

	/**
	 * Load library
	 *
	 * @return void
	 */
	loadLibrary: function() {
		var modulePath;
		var localePath;
		var isMinify = (isDefined(AppOptions) && isDefined(AppOptions.isMinify)) ? AppOptions.isMinify : false;
		var minScripts = [];
		
		/**
		 * Path
		 *
		 */
		if (isDefined(AppOptions) && isObject(AppOptions) && isDefined(AppOptions.basePath) && AppOptions.basePath) {
			modulePath = AppOptions.basePath+"/module/";
			localePath = AppOptions.basePath+"/locale/";
		} else {
			$('head > script[src$="app.js"]').each(function(index, js) {
				modulePath = js.src.replace("app.js", 'module/');
				//alert(modulePath);
				localePath = js.src.replace("app.js", 'locale/');
				//alert(localePath);
			});
		}

		if (modulePath==undefined) {
			modulePath = '/js/lib/app/module/';
		}
		if (localePath==undefined) {
			localePath = '/js/lib/app/locale/';
		}
		
		/**
		 * Translation
		 *
		 */
		if (isDefined(LOCALE)) {
			if (isDefined(AppOptions) && isObject(AppOptions) && isString(AppOptions.locale)) {
				LOCALE = AppOptions.locale;
			}
			if (isMinify) {
				minScripts.push(localePath+LOCALE+'/translation.js');
			} else {
				AppLoader.loadScript(localePath+LOCALE+'/translation.js');
			}
		}

		/**
		 * Modules
		 *
		 */
		if (isDefined(AppOptions) && isObject(AppOptions) && isObject(AppOptions.modules)) {
			$.each(AppOptions.modules, function(index, module) {
				AppLoader.modules.push(module);
			});
		}

		$.each(this.modules, function(index, module) {
			if (!isDefined(module.path) || !module.path || module.path == 'auto') {
				if (isMinify) {
					minScripts.push(modulePath+module.name+'.js');
				} else {
					AppLoader.loadScript(modulePath+module.name+'.js'+(module.rand || ''));
				}
			} else {
				if (isMinify) {
					minScripts.push(module.path+module.name+'.js');
				} else {
					AppLoader.loadScript(module.path+module.name+'.js'+(module.rand || ''));
				}
			}
		});
		
		if (isMinify && minScripts.length) {
			var basePath = modulePath.replace('/module', '').replace(/^\/*/, '').replace(/\/*$/, '');
			
			for (var i=0; i < minScripts.length; i++) {
				minScripts[i] = minScripts[i].replace(basePath, '').replace(/^\/*/, '');
			}
			var minScript = '/min/?b=' + basePath + '&f=' + minScripts.join(',');
			AppLoader.loadScript(minScript);
		}
	},

	/**
	 * Register module
	 *
	 * @param module object
	 * @return void
	 */
	registerModule: function(module) {
		try {
			app.registerModule(module);
		} catch (e) {
			alert(e.message);
		}
		AppLoader.registeredModules++;
		
		if (AppLoader.registeredModules == AppLoader.modules.length) {
			runOnAppLoadListeners();
		}
	}
}

/**
 * Load Application modules
 * 
 */
AppLoader.loadLibrary();

