/*
 * Wildfire Spark
 * Copyright(c) 2003-2010, Wildfire Technology Limited
 * licensing@wildfire-it.com
 *
 * http://www.wildfire-it.com
 */

//Brighter Spark v.0.3

var Spark = {
	userAgent:navigator.userAgent.toLowerCase(),

	init:function() {
		var tb = this.browser;
		var ua = this.userAgent;

		tb.version = (ua.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1];
		tb.webkit = /webkit/.test(ua);
		tb.opera = /opera/.test(ua);
		tb.msie = /msie/.test(this.userAgent) && !/opera/.test(ua);
		tb.mozilla = /mozilla/.test(ua) && !/(compatible|webkit)/.test(ua);
		tb.msafari = /apple.*mobile.*safari/.test(ua);
		this.browserDetect.init(tb);
	},

	log: function(s) {
		httpRequest('/_/ServletEngine/log?msg=' + s);
	},

	load:function() {
		if (document.all) {
			HTMLDomElement = window.XMLHttpRequest ? HTMLElement || Element : HTMLElement;
		} else {
			HTMLDomElement = HTMLElement;
		}
		this.loadExtensions();
	},

	loadResource:function(url, type, cache) {
		var ref;

		if (!cache)
			url += (url.contains('?') ? '&' : '?') + 'ds=' + new Date().getTime();

		if (type == "js") {
			ref = document.createElement('script');
			ref.setAttribute("type", "text/javascript");
			ref.setAttribute("src", url)
		}
		else if (type == "css") {
			ref = document.createElement("link");
			ref.setAttribute("rel", "stylesheet");
			ref.setAttribute("type", "text/css");
			ref.setAttribute("href", url)
		}

		if (ref)
			document.getElementsByTagName("head")[0].appendChild(ref)
	},

	browser: {
		getViewportWidth:function() {
			return window.innerWidth;
		}
		,getViewportHeight:function() {
			return window.innerHeight;
		}
		,getViewportSize:function() {
			return [this.getViewportWidth(), this.getViewportHeight()];
		}
		,getOrientation:function() {
			var o = window.orientation;
			if (o == 90 || o == -90)
				return 'landscape';

			return 'portrait';
		}
	},

	extend: function() {
		function extend(ob, src) {
			for (var property in src) {
				ob[property] = src[property];
			}
		}

		if (arguments.length == 2) {
			extend(arguments[0], arguments[1]);
		} else {
			var l = arguments.length, src = arguments[l - 1], i = l - 1;
			while (i--) {
				extend(arguments[i], src);
			}
		}
	},

	eventManager:{
		add:function(el, n, fn) {
			if (typeof window.addEventListener != 'undefined')
				el.addEventListener(n.replace(/^on/i, ''), fn, false);
			else if (typeof window.attachEvent != 'undefined')
				el.attachEvent(n, fn);
			else if (window[n] != null) {
				var evt = window[n];
				window[n] = function(e) {
					evt(e);
					el[fn]();
				};
			} else
				el[n] = fn;
		}

		,onload:function(fn) {
			this.add(window, 'onload', fn);
		}
	},

	cookieManager:{
		get:function(name, decode) {
			if (arguments.length == 1)
				decode = true;

			var c = document.cookie;

			var s = null;

			if (c.length > 0) {
				var v;
				var n = name;
				var i = 1;
				while ((v = this.read(n))) {
					if (v) {
						if (!s)
							s = '';

						s += v;
					}

					n = name + '__' + i;
					i++;
				}

				if (s && decode)
					s = unescape(s);

				return s;
			}
			return null;
		},

		read:function(name) {
			var nameEQ = name + "=";
			var cookies = document.cookie.split(';');
			for (var i = 0; i < cookies.length; i++) {
				var c = cookies[i];
				while (c.charAt(0) == ' ')
					c = c.substring(1, c.length);

				if (c.indexOf(nameEQ) == 0) {
					//put('getting cookie: ' + name);
					var value = c.substring(nameEQ.length, c.length);

					//put(unescape(value));

					return value;
				}
			}
			return null;
		}

		,set:function(name, value, expires, path) {
			path = path || '/';

			var d = new Date();
			if (!expires)
				expires = null;
			else
				d.setDate(d.getDate() + expires);

			var values = [];

			value = escape(value);

			var len = 1024 * 3;

			if (value.length > len) {
				while (value.length > len) {
					values.push(value.slice(0, len));
					value = value.substring(len);
				}

				if (value)
					values.push(value);
			} else
				values.push(value);


			for (var i = 0; i < values.length; i++) {
				var n = i == 0 ? name : name + '__' + i;
				document.cookie = n + '=' + values[i] + ((expires == null) ? '' : '; expires=' + d.toGMTString()) + '; path=' + path;
			}


			//remove old cookies
			if (value) {
				var i = values.length;
				while (this.read(name + '__' + i)) {
					this.expire(name + '__' + i);
				}
			}
		}

		,expire:function(name, path) {
			this.set(name, '', -1, path);
		}
	},
	
	browserDetect:{
		init: function (t) {
			t.name = this.searchString(this.dataBrowser) || "An unknown browser";
			t.version = this.searchVersion(navigator.userAgent)
					|| this.searchVersion(navigator.appVersion)
					|| "an unknown version";
			t.OS = this.searchString(this.dataOS) || "an unknown OS";
		}
		,searchString: function (data) {
			for (var i = 0; i < data.length; i++) {
				var dataString = data[i].string;
				var dataProp = data[i].prop;
				this.versionSearchString = data[i].versionSearch || data[i].identity;
				if (dataString) {
					if (dataString.indexOf(data[i].subString) != -1)
						return data[i].identity;
				}
				else if (dataProp)
					return data[i].identity;
			}
		}
		,searchVersion: function (dataString) {
			var index = dataString.indexOf(this.versionSearchString);
			if (index == -1) return;
			return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
		}
		,dataBrowser: [
			{
				string: navigator.userAgent,
				subString: "Chrome",
				identity: "Chrome"
			},
			{
				string: navigator.userAgent,
				subString: "OmniWeb",
				versionSearch: "OmniWeb/",
				identity: "OmniWeb"
			},
			{
				string: navigator.vendor,
				subString: "Apple",
				identity: "Safari",
				versionSearch: "Version"
			},
			{
				prop: window.opera,
				identity: "Opera"
			},
			{
				string: navigator.vendor,
				subString: "iCab",
				identity: "iCab"
			},
			{
				string: navigator.vendor,
				subString: "KDE",
				identity: "Konqueror"
			},
			{
				string: navigator.userAgent,
				subString: "Firefox",
				identity: "Firefox"
			},
			{
				string: navigator.vendor,
				subString: "Camino",
				identity: "Camino"
			},
			{
				// for newer Netscapes (6+)
				string: navigator.userAgent,
				subString: "Netscape",
				identity: "Netscape"
			},
			{
				string: navigator.userAgent,
				subString: "MSIE",
				identity: "Explorer",
				versionSearch: "MSIE"
			},
			{
				string: navigator.userAgent,
				subString: "Gecko",
				identity: "Mozilla",
				versionSearch: "rv"
			},
			{
				string: navigator.userAgent,
				subString: "Mozilla",
				identity: "Netscape",
				versionSearch: "Mozilla"
			}
		],
		dataOS : [
			{
				string: navigator.platform,
				subString: "Win",
				identity: "Windows"
			},
			{
				string: navigator.platform,
				subString: "Mac",
				identity: "Mac"
			},
			{
				string: navigator.userAgent,
				subString: "iPhone",
				identity: "iPhone/iPod"
			},
			{
				string: navigator.platform,
				subString: "Linux",
				identity: "Linux"
			}
		]
	},

	extendStringMethods:function() {
		this.extend(String.prototype, {
			endsWith: function(s) {
				return new RegExp(s + '$').test(this);
			}

			,startsWith: function(s) {
				return new RegExp('^' + s).test(this);
			}

			,contains: function(s) {
				return this.indexOf(s) > -1;
			}

			,trim: function() {
				return this.replace(new RegExp('(^[\\s]+|[\\s]+$)', 'g'), '');
			}

			,capitalize: function() {
				return this.replace(/\b[a-z]/g, function(s) {
					return s.toUpperCase();
				});
			}
		});
	}
};


var HTMLDomElement = null;

function addElement(tag, cfg, html) {
	cfg = cfg || {};
	var el = document.createElement(tag);
	for (var k in cfg) {
		if (k == 'cls' || k == 'class')
			el.className = cfg[k];
		else
			el.setAttribute(k == 'cls' ? 'class' : k, cfg[k]);
	}

	if (html)
		el.innerHTML = html;

	return el;
}

/**
 * Returns the specified computed style on an object.
 * @param {HTMLObject} el HTML Object
 * @param {String} p Property name.
 * @return {Mixed} Computed style on object.
 */
function getStyle(el, p) {
	if (el.currentStyle)
		return el.currentStyle[p];
	else if (window.getComputedStyle)
		return document.defaultView.getComputedStyle(el, null).getPropertyValue(p);

	return '';
}

function addUnit(s, u) {
	u = u || 'px';
	s = ('' + s).replace(new RegExp(u + '$'), '');
	return s + (parseInt(s) ? u : '');
}

function httpRequest(u, cb) {
	new MicroAjax(u, {
		cb:cb
	});
}

function put(s, t) {
	if (window.console) {
		s = s || '';

		if (t)
			s += ' (@' + new Date().getTime() + ')';

		window.console.log(s);
	}
}

/**
 * Throughout, whitespace is defined as one of the characters
 *  "\t" TAB \u0009
 *  "\n" LF  \u000A
 *  "\r" CR  \u000D
 *  " "  SPC \u0020
 *
 * This does not use Javascript's "\s" because that includes non-breaking
 * spaces (and also some other characters).
 */

/**
 * Determine whether a node's text content is entirely whitespace.
 *
 * @param nod  A node implementing the |CharacterData| interface (i.e.,
 *			 a |Text|, |Comment|, or |CDATASection| node
 * @return	 True if all of the text content of |nod| is whitespace,
 *			 otherwise false.
 */
function isAllWS(nod) {
	// Use ECMA-262 Edition 3 String and RegExp features
	return !(/[^\t\n\r ]/.test(nod.data));
}

/**
 * Determine if a node should be ignored by the iterator functions.
 *
 * @param nod  An object implementing the DOM1 |Node| interface.
 * @return	 true if the node is:
 *				1) A |Text| node that is all whitespace
 *				2) A |Comment| node
 *			 and otherwise false.
 */

function isIgnorable(nod) {
	return (nod.nodeType == 8) || // A comment node
			((nod.nodeType == 3) && isAllWS(nod)); // a text node, all ws
}

/**
 * Version of |previousSibling| that skips nodes that are entirely
 * whitespace or comments.  (Normally |previousSibling| is a property
 * of all DOM nodes that gives the sibling node, the node that is
 * a child of the same parent, that occurs immediately before the
 * reference node.)
 *
 * @param sib  The reference node.
 * @return	 Either:
 *			   1) The closest previous sibling to |sib| that is not
 *				  ignorable according to |isIgnorable|, or
 *			   2) null if no such node exists.
 */
function previousSibling(sib) {
	while ((sib = sib.previousSibling)) {
		if (!isIgnorable(sib)) return sib;
	}
	return null;
}

/**
 * Version of |nextSibling| that skips nodes that are entirely
 * whitespace or comments.
 *
 * @param sib  The reference node.
 * @return	 Either:
 *			   1) The closest next sibling to |sib| that is not
 *				  ignorable according to |isIgnorable|, or
 *			   2) null if no such node exists.
 */
function nextSibling(sib) {
	while ((sib = sib.nextSibling)) {
		if (!isIgnorable(sib)) return sib;
	}
	return null;
}

/**
 * Version of |lastChild| that skips nodes that are entirely
 * whitespace or comments.  (Normally |lastChild| is a property
 * of all DOM nodes that gives the last of the nodes contained
 * directly in the reference node.)
 *
 * @param sib  The reference node.
 * @return	 Either:
 *			   1) The last child of |sib| that is not
 *				  ignorable according to |isIgnorable|, or
 *			   2) null if no such node exists.
 */
function lastChild(par) {
	var res = par.lastChild;
	while (res) {
		if (!isIgnorable(res)) return res;
		res = res.previousSibling;
	}
	return null;
}

/**
 * Version of |firstChild| that skips nodes that are entirely
 * whitespace and comments.
 *
 * @param sib  The reference node.
 * @return	 Either:
 *			   1) The first child of |sib| that is not
 *				  ignorable according to |isIgnorable|, or
 *			   2) null if no such node exists.
 */
function firstChild(el) {
	var c = el.firstChild;
	while (c) {
		if (!isIgnorable(c))
			return c;
		c = c.nextSibling;
	}
	return null;
}


/**
 * Version of |data| that doesn't include whitespace at the beginning
 * and end and normalizes all whitespace to a single space.  (Normally
 * |data| is a property of text nodes that gives the text of the node.)
 *
 * @param txt  The text node whose data should be returned
 * @return	 A string giving the contents of the text node with
 *			 whitespace collapsed.
 */
function dataOf(txt) {
	var data = txt.data;
	// Use ECMA-262 Edition 3 String and RegExp features
	data = data.replace(/[\t\n\r ]+/g, " ");
	if (data.charAt(0) == " ")
		data = data.substring(1, data.length);
	if (data.charAt(data.length - 1) == " ")
		data = data.substring(0, data.length - 1);
	return data;
}

function MicroAjax(A, B) {
	B = B || {};

	this.bindFunction = function(E, F) {
		return function() {
			return E.apply(F, [F])
		}
	};
	this.stateChange = function(E) {
		if (this.request.readyState == 4 && this.callbackFunction) {
			var response;
			var responseText = this.request.responseText;

			switch (B.responseType) {
				case 'xml':
				case 'html':
					response = this.request.responseXML;
					break;
				case 'raw':
					response = this.request;
					break;
				default:
					response = responseText;
					responseText = null;
			}
			this.callbackFunction(response, responseText);
		}
	};
	this.getRequest = function() {
		if (window.ActiveXObject) {
			return new ActiveXObject("Microsoft.XMLHTTP")
		} else {
			if (window.XMLHttpRequest) {
				return new XMLHttpRequest()
			}
		}
		return false
	};
	this.postBody = (B.postBody || "");

	if (B.cb)
		this.callbackFunction = B.cb;
	else if (B && typeof B == 'function')
		this.callbackFunction = B;

	this.url = A;
	this.request = this.getRequest();

	if (this.request) {
		var R = this.request;
		R.onreadystatechange = this.bindFunction(this.stateChange, this);
		if (this.postBody !== "") {
			R.open("POST", A, true);
			R.setRequestHeader("X-Requested-With", "XMLHttpRequest");
			R.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			//R.setRequestHeader("Connection", "close")
		} else {
			R.open("GET", A, true)
		}
		R.send(this.postBody)
	}
}

/**
 * Implements JSON stringify and parse functions
 * v1.0
 *
 * By Craig Buckler, Optimalworks.net
 *
 * As featured on SitePoint.com
 * Please use as you wish at your own risk.
 *
 * Usage:
 *
 * // serialize a JavaScript object to a JSON string
 * var str = JSON.stringify(object);
 *
 * // de-serialize a JSON string to a JavaScript object
 * var obj = JSON.parse(str);
 */

var JSON = JSON || {};

// implement JSON.stringify serialization
JSON.stringify = JSON.stringify || function (obj) {

	var t = typeof (obj);
	if (t != "object" || obj === null) {

		// simple data type
		if (t == "string") obj = '"' + obj + '"';
		return String(obj);

	}
	else {

		// recurse array or object
		var n, v, json = [], arr = (obj && obj.constructor == Array);

		for (n in obj) {
			v = obj[n];
			t = typeof(v);

			if (t == "string") v = '"' + v + '"';
			else if (t == "object" && v !== null) v = JSON.stringify(v);

			json.push((arr ? "" : '"' + n + '":') + String(v));
		}

		return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
	}
};

// implement JSON.parse de-serialization
JSON.parse = JSON.parse || function (str) {
	if (str === "") str = '""';
	eval("var p=" + str + ";");
	return p;
};

var SparkViewport = function() {
	var w;
	var h; // the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
	if (typeof window.innerWidth != 'undefined') {
		w = window.innerWidth;
		h = window.innerHeight;
	} // IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
	else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) {
		w = document.documentElement.clientWidth;
		h = document.documentElement.clientHeight;
	} // older versions of IE
	else {
		w = document.getElementsByTagName('body')[0].clientWidth;
		h = document.getElementsByTagName('body')[0].clientHeight;
	}

	this.width = w;
	this.height = h;
};

SparkViewport.prototype = {
	getWidth:function() {
		return this.width;
	}
	,getHeight:function() {
		return this.height;
	}
};

function actionScriptToJavaScript(s) {
	put(s);
}

var SparkHistoryManager = function(onChangeHandler) {
	this.listener = onChangeHandler || this.listener;
	unFocus.History.addEventListener('historyChange', this.listener);
	this.initHash = this.listener(unFocus.History.getCurrent());
};

SparkHistoryManager.prototype = {
	initHash:null

	,add:function(v) {
		if (v)
			unFocus.History.addHistory(v);
	}

	,listener:function(hash) {
		return hash;
	}
};

function sortObject(o) {
	var k, s = {}, a = [];
	for (k in o) {
		if (o[k])
			a.push(k);
	}
	a.sort();
	for (k = 0; k < a.length; k++) {
		s[a[k]] = o[a[k]];
	}
	return s;
}

var GoogleMap = function(el, latitude, longitude, options) {
	var t = this;
	if (typeof el == 'string')
		el = document.getElementById(el);

	t.element = el;

	options = options || {};
	options.zoom = options.zoom || 15;
	options.mapTypeId = options.mapTypeId || google.maps.MapTypeId.ROADMAP;

	t.options = options;

	if (t.options.directionsPanel)
		t.directionsPanel = document.getElementById(t.options.directionsPanel);

	t.setBox();

	t.options.center = new google.maps.LatLng(latitude, longitude);
};

GoogleMap.prototype = {
	showMap: function() {
		var t = this;
		return new google.maps.Map(t.element, t.options);
	}
	,showDirections: function(destination, origin) {
		var t = this;

		if (typeof origin == 'undefined') {
			t.getCurrentLocation(destination);
			return;
		}

		destination = destination || t.options.center;

		var map = t.showMap();

		t.directionsRenderer = new google.maps.DirectionsRenderer();
		t.directionsRenderer.setMap(map);

		if (!origin) {
			if (t.directionsPanel)
				t.directionsPanel.remove();

			var marker = new google.maps.Marker({
				position: destination,
				map: map
			});
			return;
		}

		if (t.directionsPanel)
			t.directionsRenderer.setPanel(t.directionsPanel);

		var request = {
			origin:origin,
			destination:destination,
			travelMode: google.maps.DirectionsTravelMode.DRIVING
		};

		t.directionsService = new google.maps.DirectionsService();
		t.directionsService.route(request, function(response, status) {
			if (status == google.maps.DirectionsStatus.OK) {
				t.directionsRenderer.setDirections(response);
			}
		});
	},
	setBox:function() {
		var el = this.element;

		if (el.className.length > 0)
			return;

		var hLock = false, vLock = false;

		while (el.parentNode) {
			el = el.parentNode;

			if (el.style) {

				if (el.className.contains('vLock'))
					vLock = true;

				el.style.width = '100%';

				if (!vLock)
					el.style.height = '100%';
			}
		}
	}
	,getCurrentLocation:function(destination) {
		var t = this;
		var geoLocation;
		try {
			geoLocation = JSON.parse(Spark.cookieManager.get('geocode'));
		} catch(e) {
			put(e);
		}

		if (!geoLocation || geoLocation.disabled) {
			if (t.directionsPanel)
				t.directionsPanel.remove();

			t.showDirections(destination, '');
			return;
		}

		var defaultPosition = new google.maps.LatLng(geoLocation.latitude, geoLocation.longitude);

		if (geoLocation.postcode && geoLocation.manual) {
			var geocoder = new google.maps.Geocoder();
			geocoder.geocode({ 'address': geoLocation.postcode}, function(results, status) {
				var postition;
				if (status == google.maps.GeocoderStatus.OK) {
					position = results[0].geometry.location;
				} else {
					position = defaultPosition;
				}

				t.showDirections(destination, position);
			});
		} else
			t.showDirections(destination, defaultPosition);
	}
};


//function initialize() {
//  localSearch = new GlocalSearch();
//  icon = new GIcon(G_DEFAULT_ICON);
//  addressMarkerOptions = { icon:icon , draggable: false};
//  map = new GMap2(document.getElementById("map"));
//  map.addControl(new GLargeMapControl());
//  map.addControl(new GMapTypeControl());
//  plotAddress("OX4 1FJ");
//}

/**
 * This takes either a postcode or an address string
 *
 */

/*
 var geocoder;
 var map;
 function initialize() {
 geocoder = new google.maps.Geocoder();
 var latlng = new google.maps.LatLng(-34.397, 150.644);
 var myOptions = {
 zoom: 8,
 center: latlng,
 mapTypeId: google.maps.MapTypeId.ROADMAP
 };

 //map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
 }
 */

function getRequest() {
	var request = {};
	var search = document.location.search;
	if (search) {
		search = search.replace(/^\?/, '').split('&');
		for (var i = 0; i < search.length; i++) {
			var tmp = search[i].split('=');
			request[tmp[0]] = tmp[1];
		}
	}
	return request;
}

var sparkIdIndex = 0;
function getSparkId(el) {

	var s = 'sparkAutoId';

	if (!el.id) {
		sparkIdIndex++;

		while (document.getElementById(s + sparkIdIndex))
			sparkIdIndex++;

		el.id = s + sparkIdIndex;
	}

	return el.id;
}

function zeroFill(i) {
	return i > 9 ? i : '0' + i;
}

Spark.eventManager.onload(function() {
	if (window.jQuery) {
		$('.spark-horizonal-container').each(function(x, el) {
			var h = 0;
			var c = $('#' + el.id + ' .spark-horizontal-component');
			c.each(function(x, el) {
				var _h = el.offsetHeight;
				if (_h > h)
					h = _h;
			});
			el.style.height = h + 'px';
			c.each(function(x, el) {
				el.style.height = h + 'px';
			});
		});
	}
});

Spark.extendStringMethods();
