/**
 * App application wide Javascript namespace
 * 
 */
var App = {};

App.init = function (){
	
	for (var prop in this) {
		if (typeof this[prop].init == 'function') {
			App.initModule(prop);
		}
	}
	var searchForm = document.getElementById("BookSearchForm");
	if(searchForm != null){
		App.searchLocation = searchForm.action;
		$('#search_area').bind('change', function() {
			if ($('#search_area').is(':checked')) {
				searchForm.action = '/books/index';
			} else {
				searchForm.action = App.searchLocation;
			}
		}).change();
	}
};
App.initModule = function (module) {
	if (this[module].require != undefined) {
		var classes = this[module].require.slice();
		classes.push(this[module].init.bind(this[module]));
		App.use.apply(window, classes);
	} else {
		this[module].init();
	}
};

//
// Load any number of class objects from the classes dir 
// loads files asynchronously.
//
// Appends script tags to the document head.
//
// Example. App.use('MultiForm', 'Template', function () { .. });
// This will load MultiForm and Template classes and when they are done run the callback.
//
//
App.use = function () {
	function _appendScript(filename, callback) {
		var head = document.getElementsByTagName("head")[0];
		var script = document.createElement("script");
		script.src = filename;
		var done = false;
      
		script.onload = script.onreadystatechange = function () {
			if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") ) {
				done = true;
				callback();
			}
		}
		head.appendChild(script);
	}

	var compressorPath = window.basePath + 'asset_compress/js_files/join/';

	var classDir = window.basePath + 'js/classes/';
	var args = jQuery.makeArray(arguments);
	var readyCallback = Class.empty;

	if (typeof args[args.length -1] == 'function') {
		readyCallback = args.pop();
	}

	var filename = compressorPath + args.join('/');
	//console.log(filename);
	_appendScript(filename, readyCallback);
};


/**
 * i18n Object for JS translations
 *
 */
App.i18n = (function() {
	var _i18nDict = {};
	var i18n = {
	/**
	 * get a translated string from the translations dictionary
	 * @param [string] stringName name of string you want.
	 * @returns [string] Value of translated string
	 */
		get : function(stringName) {
			if (_i18nDict[stringName]) {
				return _i18nDict[stringName];
			}
			return stringName;
		},
	/**
	 * Set a value(s) to the dictionary.
	 * 
	 * @param [mixed] stringName either the stringname or a dictionary (object literal) to append
	 * @param [string] value Value of the stringname being added.
	 */
		set : function(stringName, value) {
			if (typeof(stringName) === 'string') {
				_i18nDict[stringName] = value;
			} else if (value === undefined) {
				for (var key in stringName) {
					_i18nDict[key] = stringName[key];
				} 
			}
		}
	}
	return i18n;
})();

var __ = App.i18n.get;

App.Templates = {};


/**
 * Create a basic prototypal inheritance Class.
 * 
 * Create new classes with Class.create({prototype object});
 * Extend a class with Class.extend({prototype object});
 * Tape on new methods to all existing instances with Class.implement({object});
 * 
 * Classes can have an init() function which acts as a constructor for the prototype
 */
function Class (features) {
	var klass = function (noStart) {
		if (typeof this.init == 'function' && noStart != 'noInit') {
			return this.init.apply(this, arguments);
		}
		return this;
	};
	for (var key in this) {
		klass[key] = this[key];
	}
	klass.prototype = features;
	return klass;
};

Class.prototype.extend = function (features) {
	var oldProto, oldFunc, newFunc, func;
	oldProto = new this('noInit');

	var makeParent = function(parent, current) {
		return function () {
			this.parent = parent;
			return current.apply(this, arguments);
		};
	};

	for (var key in features) {
		oldFunc = oldProto[key];
		newFunc = features[key];
		if (typeof oldFunc != 'function' || typeof newFunc != 'function') {
			func = newFunc;
		} else {
			func = makeParent(oldFunc, newFunc);
		}
		oldProto[key] = func;
	}
	return new Class(oldProto);
};

Class.prototype.implement = function (features) {
	for (var key in features) {
		this.prototype[key] = features[key];
	}
};

/**
 * Empty function good for comparing to empty functions
 */
Class.empty = function () { };



/**
 * Add bind function to all functions.
 *
 * lets change 'this' in any function.
 */
if (typeof Function.bind != 'function') {
	Function.prototype.bind = function (obj) {
		var method = this;
		return function() {
			return method.apply(obj, arguments);
		};
	}
}

// Convert CamelCase string to camel_case string.
if (typeof String.underscore != 'function') {
	String.prototype.underscore = function () {
		var underscored = this.replace(/([A-Z])/g, '_$1').toLowerCase();
		if (underscored.substr(0, 1) == '_') {
			return underscored.substring(1);
		}
		return underscored;
	}
}


App.alerts = {
	init : function() {
		if ($.fn.jqm == undefined) {
			return;
		}
		$('#alert').jqm({overlay: 40, modal : true, trigger : false});
		$('#confirm').jqm({overlay: 40, modal : true, trigger : false});
	}
};

App.alert = function (msg, content) {
	$('#alert').jqmShow()
		.removeClass('error')
		.find('h2').html(msg)
		.end()
		.find('p').html(content);
};

App.error = function (msg, content) {
	$('#alert').jqmShow()
		.addClass('error')
		.find('h2').html('<span>' + msg + '</span>')
		.end()
		.find('p').html(content);
};

App.confirm = function (msg, callback, options) {
	if (options.yesValue) {
		$('#confirm .confirm-yes input').val(options.yesValue);
	}
	if (options.noValue) {
		$('#confirm .confirm-no input').val(options.noValue);
	}

	$('#confirm')
		.jqmShow()
		.find('p.message').html(msg)
		.end()
		.find(':submit:visible').unbind('click').bind('click', function (event) {
			if (this.value == $('#confirm .confirm-yes input').val()) {
				if (typeof callback == 'string') {
					window.location.href = callback;
				} else {
					callback();
				}
			}
			$('#confirm').jqmHide();
			return false;
		});
};


var Validation = {
	notEmpty: function (value) {
		if (!value.length || value.length == 0) {
			return __('Must not be empty');
		}
		return true;
	},
	date: function (value) {
		if (!value.match(/(19|20)\d\d[- \/.](0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])/)) {
			return __('Must be a valid date');
		}
		return true;
	},
	url: function (value) {
		//from CakePHP Validation::url()
		var pattern = /^(?:(?:https?|ftps?|file|news|gopher):\/\/)?(?:(?:(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])|(?:[a-z0-9][-a-z0-9]*\.)*(?:[a-z0-9][-a-z0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,4}|museum|travel))(?::[1-9][0-9]{0,3})?(?:\/?|\/([\!\"\$\&\\\'\(\)\*\+\,\-\.\@\_\:\;\=\/0-9a-z]|(%[0-9a-f]{2}))*)?(?:\?([\!\"\$\&\\\'\(\)\*\+\,\-\.\@\_\:\;\=\/0-9a-z]|(%[0-9a-f]{2}))*)?(?:#([\!\"\$\&\\\'\(\)\*\+\,\-\.\@\_\:\;\=\/0-9a-z]|(%[0-9a-f]{2}))*)?$/i;
		if (!value.match(pattern)) {
			return __('Must be a valid url');
		}
		return true;
	}
};


if (console === undefined) {
	var console = {
		log: function () {},
		error: function () {},
		trace: function () {}
	};
}
