/*
 *	adenin.core.js
 *	Core adenin JS framework
 *	2009-01-20 fk
 */

(function($){

	$.adenin = $.adenin || {};
	$at = $.adenin;

	$.extend($at,
	{
		/*
			Inherits a subClass from a superClass.
			Usage:
			var SubClass = $at.extend(SuperClass,
			{
				constructor: function()
				{
					// SubClass constructor code ...
				},
				method1: function(arg, ...)
				{
					// SubClass code for method1 ...
				}
			});
		*/
		extend: function(subClass, superClass, overrides)
		{
			if (typeof superClass == 'object')
			{
				// Actually called as extend(superClass, overrides):
				overrides = superClass;
				superClass = subClass;
				// Create subClass: Use a constructor if provided in overrides;
				// otherwise create one which simply calls the constructor of superClass.
				subClass = overrides.constructor == Object.prototype.constructor ?
						function(){superClass.apply(this, arguments);} :
						overrides.constructor;
			}

			if (superClass)
			{
				// Create an empty class M with the prototype of superClass.
				var M = function(){};
				M.prototype = superClass.prototype;

				// Create an M instance and make it the prototype of subClass.
				subClass.prototype = new M();

				subClass.prototype.superclass = superClass.prototype;
			}

			subClass.prototype.constructor = subClass;

			// Apply member overrides
			$at.override(subClass, overrides);

			// Add members to subClass directly:
			subClass.superclass = superClass.prototype;
			subClass.extend = function(o){return $at.extend(subClass, o);};
			subClass.override = function(o){$at.override(subClass, o);};

			return subClass;
		},

		/*
			Adds or overrides methods in the protype of targetClass.
			targetClass: The class to override.
			overrides: An object literal containing one or more methods to add to targetClass.
		*/
		override: function(targetClass, overrides)
		{
			if (overrides)
			{
				$.extend(targetClass.prototype, overrides);
				if ($.browser.msie && overrides.hasOwnProperty('toString'))
				{
					targetClass.prototype.toString = overrides.toString;
				}
			}
		}
	});

	$.extend($at,
	{
		Class: $at.extend(function(){}, {})
	});

	var Culture = $at.Class.extend(
	{
		constructor: function(options)
		{
			$.extend(this,
			{
				language: 'en',
				decimalSeparator: '.',
				negativeSign: '-',
				groupSize: 3,
				groupSeparator: ','
			}, options);
			this.decimalCode = this.decimalSeparator.charCodeAt(0);
			this.minusCode = this.negativeSign.charCodeAt(0);
			this.groupCode = this.groupSeparator.charCodeAt(0);
			this.reDecimalSeparator = new RegExp('\\' + this.decimalSeparator, 'g');
			this.reNonNumChars = new RegExp('[^\\d\\' + this.decimalSeparator + ']', 'g');
			this.reDecimal = new RegExp('(\\d*)(?:\\' + this.decimalSeparator + '(\\d*))?');
		},
		isNumericKey: function(k)
		{
			return (k > 47 && k < 58)
				|| k == null || k == 0 || k == 8 || k == 9 || k == 13 || k == 27
				|| k == this.decimalCode || k == this.minusCode || k == this.groupCode;
		},
		parseDecimal: function(n, p)
		{
			if (typeof(n) !== 'string')
				n = n.toString();

			var neg = (n.indexOf(this.negativeSign) >= 0);

			// Remove everything except digits and decimal separator
			n = n.replace(this.reNonNumChars, '');

			var m = n.match(this.reDecimal);
			if (!m) return 0;

			var f = m[1];

			if (neg)
				f = '-' + f;

			if (m.length >= 3 && typeof(m[2]) !== 'undefined' && m[2] !== '')
			{
				var d = m[2];
				if (d.length > p)
					d = d.substr(0, p)
				f += '.' + d;
			}
			return new Number(f);
		},
		formatDecimal: function(f, p)
		{
			f = new Number(f);

			if (isNaN(f))
				f = new Number(0);

			var w = (new Number(f)).toFixed(p);
			var neg;

			if (w.substr(0, 1) === '-')
			{
				neg = true;
				w = w.substr(1);
			}

			var l = w.length - this.groupSize;

			if (p > 0)
			{
				w = w.substr(0, w.length - p - 1) + this.decimalSeparator + w.substr(w.length - p);
				l -= (p + 1);
			}

			while (l > 0)
			{
				w = w.substr(0, l) + this.groupSeparator + w.substr(l);
				l -= this.groupSize;
			}

			if (neg)
				w = this.negativeSign + w;

			return w;
		}
	});

	var Page = function()
	{
		var par = { sitePath: '', boWrapper: 'portal.aspx' };

		this.init = function(options)
		{
			par = $.extend(par, options);
			if (typeof(par.mvcRoot) === 'undefined')
				par.mvcRoot = par.sitePath + 'Portal.mvc/';
			// Global legacy variables
			PortalURL = par.sitePath;
			HomePage = par.boWrapper;
			HomeURL = par.sitePath + par.boWrapper;
		};
		this.getSitePath = function()
		{
			return par.sitePath;
		};
		this.mvcUrl = function(mvcPath)
		{
			return (typeof(mvcPath) === 'undefined') ? par.mvcRoot : par.mvcRoot + mvcPath;
		};
		this.boUrl = function(bo, args)
		{
			var url = par.sitePath + par.boWrapper + '?bo=' + bo;
			if (typeof args === 'string')
			{
				url += '&' + args;
			}
			else
			{
				$.each(args, function(key, val){
					url += '&' + key + '=' + encodeURIComponent(val);
				});
			}
			return url;
		};
		this.setCulture = function(options)
		{
			var culture = this.culture = new Culture(options);
			window.EnsureNumeric = function(e)
			{
				return culture.isNumericKey(getKeyCode(e));
			};
			window.DecimalToNumber = function(n, p, hf)
			{
			};
		};
		this.getCultureName = function() { return par.culture || par.language || 'en-US'; };
		this.getLanguage = function() { return par.language || 'en'; };
		this.ready = function(id, fn, opts)
		{
			if (!this.ready.done)
				this.ready.done = {};
			if (!this.ready.done[id])
			{
				var me = this;
				$(function() { fn.apply(me); });
				this.ready.done[id] = true;
			}
		};
	};
	$at.page = new Page();

	$at.require = function(jsLibs, options)
	{
		if (!$at.require.loadedLibs) $at.require.loadedLibs = {};
		if (typeof jsLibs === 'string')
		{
			if (jsLibs == 'atGadgets')
				jsLibs = ['gadgets/files/container/atGadgets.js'];
			else
				jsLibs = new Array(jsLibs);
		}
		var opts = $.extend({
			callback: function(){},
			cache: true
		}, options);
		$.each(jsLibs, function()
		{
			var lib = this;
			var css = false;
			if (lib.match(/\.css$/))
			{
				css = true;
				if (lib.indexOf('/') >= 0)
					lib = $at.page.getSitePath() + 'portal/' + lib;
				else
					lib = $at.page.getSitePath() + 'stylesheets/' + lib;
			}
			else
			{
				if (lib.indexOf('/') != 0)
					lib = $at.page.getSitePath() + 'portal/' + lib;
				if (!lib.match(/\.js$/))
					lib += '.js';
			}
			var indent = '          '.substr(0, ($at.require.depth++ || ($at.require.depth = 1, 0)) * 2);
			if (!$at.require.loadedLibs[lib])
			{
				if (css)
				{
					$at.log(indent + 'Loading stylesheet ' + lib + '...');
					$(function()
					{
						$('head').append('<link type="text/css" rel="stylesheet" href="' + lib + '" />');
					});
				}
				else
				{
					$at.log(indent + 'Loading JS library ' + lib + '...');
					$.ajax({
						type: 'GET',
						url: lib,
						complete: function(req, status)
						{
							$at.log(indent + lib + ': ' + status);
						},
						success: opts.callback,
						error: function(req, msg, e)
						{
							$at.log(indent + lib + ': ' + msg);
						},
						dataType: 'script',
						cache: opts.cache,
						async: false
					});
				}
				$at.require.loadedLibs[lib] = true;
			}
			else
				$at.log(indent + 'Library ' + lib + ' is already loaded.');
			$at.require.depth--;
		});
	};

	$at.date = function()
	{
		$at.require([
			'jquery.calendars/smoothness.calendars.picker.css',
			'jquery.calendars/jquery.calendars.js',
			'jquery.calendars/jquery.calendars.plus.js',
			'jquery.calendars/jquery.calendars.picker.js'
		]);
		var availableCultures = ['af', 'ar', 'az', 'bg', 'bs', 'ca', 'cs',
			'da', 'de', 'de-CH', 'el', 'en-GB', 'eo', 'es', 'es-AR', 'et', 'eu',
			'fa', 'fi', 'fo', 'fr', 'fr-CH', 'gl', 'gu', 'he', 'hr', 'hu', 'hy',
			'id', 'is', 'it', 'ja', 'ko', 'lt', 'lv', 'ms', 'nl', 'nl-BE', 'no',
			'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'sq', 'sr', 'sr-SR', 'sv',
			'ta', 'th', 'tr', 'uk', 'ur', 'vi', 'zh-CN', 'zh-HK', 'zh-TW'];
		var calendarType = 'gregorian';
		var cultureName = $at.page.getCultureName();
		if ($.inArray(cultureName, availableCultures) < 0)
		{
			var p = cultureName.indexOf('-');
			if (p > 0)
			{
				cultureName = cultureName.substr(0, p);
			}
			if ($.inArray(cultureName, availableCultures) < 0)
			{
				cultureName = 'en';
			}
		}
		if (cultureName != 'en')
		{
			$at.require([
				'jquery.calendars/jquery.calendars-' + cultureName + '.js',
				'jquery.calendars/jquery.calendars.picker-' + cultureName + '.js'
			]);
		}
		$at.date.cal = $.calendars.instance(calendarType, cultureName);
		$('input.atDate').calendarsPicker($.extend(
				{
					calendar: $at.date.cal,
					renderer: $.extend({}, $.calendars.picker.defaultRenderer, 
									{ picker: $.calendars.picker.defaultRenderer.picker.replace(/\{link:clear\}/, '') }),
					selectDefaultDate: true
				},
				$.calendars.picker.regional[cultureName]
			)
		);
	};


	/*
		Reads the value of a calendar picker field and an optional time entry field and returns a JS Date object.
	*/
	$at.date.getDate = function(calPickerField, timeField)
	{
		var d = calPickerField.calendarsPicker('getDate');
		if ($.isArray(d) && d.length == 1)
		{
			d = d[0].toJSDate();
		}
		else
		{
			d = new Date(); // no date selected
		}
		var date = new Date(d);
		if (timeField)
		{
			var t = timeField.timeEntry('getTime');
			date.setHours(t.getHours());
			date.setMinutes(t.getMinutes());
		}
		return date;
	};

	/*
		Changes the value of a calendar picker field.
	*/
	$at.date.setDate = function(calPickerField, jsDate)
	{
		calPickerField.calendarsPicker('setDate', $at.date.cal.fromJSDate(jsDate));
	};

	/*
		Changes the value of a time entry field.
	*/
	$at.date.setTime = function(timeField, time)
	{
		timeField.timeEntry('setTime', time);
	};

	/*
		Formats a date.
	*/
	$at.date.formatDate = function(jsDate)
	{
		var cd = $at.date.cal.fromJSDate(jsDate);
		return cd.formatDate();
	};


	/*
		Compares two dates.
	*/
	$at.date.compare = function(calPicker1, calPicker2)
	{
		var d1 = $at.date.getDate(calPicker1).getTime();
		var d2 = $at.date.getDate(calPicker2).getTime();
		if (d1 == d2)
			return 0;
		if (d1 < d2)
			return -1;
		return 1;
	};


	$at.time = function()
	{
		$at.require([
			'jquery.timeentry/jquery.timeentry.css',
			'jquery.timeentry/jquery.timeentry.js'
		]);
		var language = $at.page.getLanguage();
		if (language != 'en')
		{
			$at.require([
				'jquery.timeentry/jquery.timeentry-' + language + '.js'
			]);
		}
		$('input.atTime').timeEntry($.extend( 
				{
					timeSteps: [1, 5, 0],
					spinnerImage: $at.page.getSitePath() + 'portal/jquery.timeentry/spinnerDefault.png'
				}
			)
		);
	};

	$at.log = (typeof window.console === 'object' && window.console.log && $.isFunction(window.console.log)) ? 
		function(){ window.console.log.apply(window.console, arguments); } :
		function(msg){};

	if (false)
	{
		$at.require('jquery.profile');
		$(function()
		{
			$(window).load(function()
			{
				$.displayProfile();
			});
		});
	}

})(jQuery);
