/*
Â© Tesco.com 2007. All rights reserved.
*/

//	global TESCO and main namespaces
//	add only to these namespaces, don't create more directly under TESCO
var TESCO = {
	"NAME" : "TESCO",
	"sites" : {},
	"system" : {},
	"UI" : {},
	"locale" : {}
}

/*
	Example:
	
	TESCO.$("UI.Tooltip").loader = {}
*/
TESCO.$ = function(namespace) {
	///	<summary>create empty objects under the TESCO global object, or return them if they already exist</summary>
	///	<param name="namespace">string</param>
	///	<returns>object</returns>
	if(namespace) {
		var obj = this;
		var parts = namespace.split(".");
		for(var i = 0; i < parts.length; i++) {
			if(!obj[parts[i]]) {
				obj[parts[i]] = {};
			}
			obj = obj[parts[i]];
		}
		return obj;
	} else {
		throw new TESCO.system.Exception("TESCO.$: parameter 'namespace' must be defined");
	}
}

function $(id) {
	///	<summary>Deprecated, use full document.getElementById instead. getElementById shortcut</summary>
	///	<param name="id">string</param>
	///	<returns>object</returns>	
	return document.getElementById(id);
}

/*
	Example:
	
	if (!TESCO.system.browser.legacy) {
		//
	}
*/
TESCO.system.browser = new function() {
	///	<summary>IMPORTANT: Only use this object as a last resort, does not account for unreleased browsers</summary>
	this.NAME = "TESCO.system.browser";
	this.agent = navigator.userAgent;
	//	old versions of safari have a bug preventing default on click events, see event.js
	this.clickBug = (/safari/gi).test(this.agent) && !(/chrome/gi).test(this.agent) && !(/version/gi).test(this.agent);
	this.opera = (/opera/gi).test(this.agent);
	this.ie = /*@cc_on!@*/0;
	this.legacy = false;
	this.ie6 = (this.ie && (/msie 6/gi).test(this.agent));
	this.px = this.ie ? 0 : "px";
	this.opacity = (function(css) {
	    var _key = false;
	    if (typeof(css.opacity) !== "undefined") {
	        _key = "opacity";
	    } else if (typeof(css.MozOpacity) !== "undefined") {
	        _key = "MozOpacity";
	    } else if (typeof(css.KhtmlOpacity) !== "undefined") {
	        _key = "KhtmlOpacity";
	    } else if (typeof(css.filter) !== "undefined") {
	        _key = "filter";
	    } 
	    return _key;
	})(document.createElement("div").style);
}

/*
	Example:
	
	TESCO.sites.Configuration.merge({ "animation" : false });
	TESCO.sites.Configuration.activeBasket = new TESCO.sites.UI.Basket();
*/
TESCO.sites.Configuration = (function() {
	
	var _configuration;

	function _constructor() {
		///	<summary>global configuration object</summary>
		return this;
	}

	_constructor.prototype.NAME = "TESCO.sites.Configuration";

	_constructor.prototype.application = {
		"path": "/" + document.location.pathname.split("/")[1]
	}

	_constructor.prototype.merge = function(o) {
		///	<summary>merge an object into TESCO.sites.Configuration</summary>
		///	<param name="o">object</param>
		for (var key in o) {
			if (o.hasOwnProperty(key)) {
				if (!this[key]) {
					this[key] = o[key];
				}
				if (typeof o[key] === "object") {
					_configuration.merge.call(this[key], o[key]);
				}
			}
		}
	}

	return (_configuration = new _constructor());
})();

/*	augment objects	*/

/* array prototypes */
Array.prototype.ISARRAY = true;

Array.prototype.each = function(callback) {	
	//	todo: add break method
	for (var i = 0; i < this.length; ++i) {
		callback.call(this[i], i);
	}
}

Array.prototype.diff = function() {
    var a1 = this;
    var a = a2 = null;
    var n = 0;
    while(n < arguments.length) {
        a = [];
        a2 = arguments[n];
        var l = a1.length;
        var l2 = a2.length;
        var diff = true;
        for(var i=0; i<l; i++) {
            for(var j=0; j<l2; j++) {
                if (a1[i] === a2[j]) {
                    diff = false;
                    break;
                }
            }
            diff ? a.push(a1[i]) : diff = true;
        }
        a1 = a;
        n++;
    }
    return a.unique();
}

Array.prototype.unique = function() {
    var a = [];
    var l = this.length;
    for(var i=0; i<l; i++) {
        for(var j=i+1; j<l; j++) {
            // If this[i] is found later in the array
            if (this[i] === this[j]) {
                j = ++i;
            }
        }
        a.push(this[i]);
    }
    return a;
}

/* object prototypes */
Object.prototype.containsValue = function(name) {
	for(var i in this) {
		if(this[i] === name) {
			return true;
		}
	}
	return false;
}

Object.prototype.size = function() {
    var size = 0, key;
    for (key in this) {
        if (this.hasOwnProperty(key)) size++;
    }
    return size;
}

Object.prototype.toValueString = function(pairSeperator, valueSeperator, urlEncode) {
	if(!pairSeperator) {
		pairSeperator = "=";
	}
	if(!valueSeperator) {
		valueSeperator= "&";
	}

	var sValue = _toValueString(this, pairSeperator, valueSeperator, null, "");
	if(sValue && sValue.lastIndexOf(valueSeperator) != -1) {
		sValue = sValue.substr(0, sValue.length - 1);
	}

	function _toValueString(o, pairSeperator, valueSeperator, _values, name) {
		if(!_values) {
			_values = {values : ""};
		}

		if(o) {
			for(var i in o) {
				if(typeof o[i] == "object") {
					_toValueString(o[i], pairSeperator, valueSeperator, _values, (o.ISARRAY ? name : name + i + "."));
				} else if(i.substr(0, 1) != "_" && o[i] != null && i != "ISARRAY" && typeof o[i] != "function") {
					valuename = name + i;
					value = o[i];
					if(urlEncode) {
						valuename = valuename.URLEncode();
						if(!value.URLEncode) {
							value = new String(value);
						}
						value = value.URLEncode();
					}
					_values.values += (valuename + pairSeperator + value + valueSeperator);
				}
			}
		}
		return _values.values;
	}

	return sValue;
}

/*
	Example: 

	baseObject.extend(derivedObject);
*/
Object.prototype.extend = function(derived) {
	///	<summary>derive base object</summary>
	///	<param name="derived">object</param>
    function _F() { }
    _F.prototype = this;
    derived.prototype = new _F();
    derived.prototype.constructor = derived;
    derived.base = this;
}

/*
	Example: 

	derivedConstructor.extend(baseConstructor);
*/
Function.prototype.extend = function(base) {
	///	<summary>derive from base class</summary>
	///	<param name="base">object</param>
    base.prototype.extend(this);
    if (base.prototype.constructor == Object.prototype.constructor) {
        base.prototype.constructor = base;
    }
}

/**/
Math.isNull = function( value, defaultVal) {
	return (value == null) ? defaultVal: value;
}

/*	augment primitive types	*/
/* string prototypes */
String.prototype.format = function() {
	var _str = this;
	for (var i = arguments.length; i >= 0; i--) {
	    _str = _str.replace(new RegExp("\\{" + i + "\\}", "gm"), arguments[i]);	   
	}
	return _str;
}

if (!"".trimRight) {
    String.prototype.trimRight = function() {
        return this.replace(/\s*$/, "");
    }
}

if (!"".trimLeft) {
    String.prototype.trimLeft = function() {
        return this.replace(/^\s*/, "");
    } 
}

if (!"".trim) {
    String.prototype.trim = function() {
        return this.trimLeft().trimRight();
    }
}

String.prototype.endsWith = function(s) {
	return (this.substr(this.length - s.length) == s)
}

String.prototype.getValueFromQuery = function(n) {
	var results = new RegExp("[\\?&]" + n + "=([^&#]*)").exec(this);
	return (results == null) ? "" : results[1];
}

String.prototype.removeURLParameter = function(name) {
    var _nameValueregExp = new RegExp(name + "=[^&$]*&?");
    return this.replace(_nameValueregExp, "").replace(/&?$/, "");
}

String.prototype.URLEncode = function() {
	var SAFECHARS = "0123456789" +
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
		"abcdefghijklmnopqrstuvwxyz" +
		"-_.!~*'()";
	var HEX = "0123456789ABCDEF";

	function gethex(decimal) {
		return "%" + HEX.charAt(decimal >> 4) + HEX.charAt(decimal & 0xF);
	}

	var encoded = "";
	for (var i = 0; i < this.length; i++ ) {
		var ch = this.charAt(i);
		if(ch == " ") {
			encoded += "+";								// x-www-urlencoded, rather than %20
		} else if(SAFECHARS.indexOf(ch) != -1) {
			encoded += ch;
		} else {
			var charCode = ch.charCodeAt(0);

			if(charCode < 128) {
				encoded = encoded + gethex(charCode);
			} else if(charCode > 127 && charCode < 2048) {
				encoded = encoded + gethex((charCode >> 6) | 0xC0);
				encoded = encoded + gethex((charCode & 0x3F) | 0x80);
			} else if(charCode > 2047 && charCode < 65536) {
				encoded = encoded + gethex((charCode >> 12) | 0xE0);
				encoded = encoded + gethex(((charCode >> 6) & 0x3F) | 0x80);
				encoded = encoded + gethex((charCode & 0x3F) | 0x80);
			} else if(charCode > 65535) {
				encoded = encoded + gethex((charCode >> 18) | 0xF0);
				encoded = encoded + gethex(((charCode >> 12) & 0x3F) | 0x80);
				encoded = encoded + gethex(((charCode >> 6) & 0x3F) | 0x80);
				encoded = encoded + gethex((charCode & 0x3F) | 0x80);
			}
		}
	}

	return encoded;
}

String.prototype.stripCR = function() {
    return this.replace(/\r/g, '');
}

/* number prototypes */
Number.prototype.range = function(min, max) {
	return ((this < min) ? min : (this > max) ? max : this);
}

Number.prototype.toDecimal = function(dec) {
	var p = Math.pow(10,dec);
	return Math.round(this * p) / p;
}

Number.prototype.decimalPlaces = function() {
	var v = String(this);
	var p = v.indexOf(".");
	return (p > -1) ? v.length - p - 1 : 0;
}

// IE doesn't send the referer header for navigation through javascript location.href assignment
if (TESCO.system.browser.ie) {
	TESCO.system.redirect = function(url) {
        var link = document.createElement('a');
        link.href = url;
        document.body.appendChild(link);
        TESCO.system.event.attach(link, "click", 
			function(e) {
				//	some click handlers contain TESCO.system.redirect so 
				//	prevent propagation so they don't get triggered and 
				//	create an infinite loop
				e.stop();	
			}
		);
        link.click();
    }
} else {
    TESCO.system.redirect = function(url) {
        document.location.href = url;
    }
}