//Place at the bottom of page only please
if (!CBC) var CBC = {};

CBC.UTIL = {
	utc_days: ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
	utc_months: ["January","February","March","April","May","June","July","August","September","October","November","December"],
	gmt_offset: cbcutil_getGMTOffset(),
	createCookie: function(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	},
	readCookie: function(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for (var i=0; i<ca.length; i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	},
	eraseCookie: function(name) {
		this.createCookie(name,"",-1);
	},
	debug: function(str) {
		if (typeof console != 'undefined') console.log(str);
	},
	print: function(str) {
		if (typeof console != 'undefined') console.log(str); else alert(str);
	},
	ucfirst: function(str) {
		var first_letter = str.toString().substr(0,1).toUpperCase();
		return first_letter + str.substr(1);
	},
	concatArray: function(arr) {
		var ret_arr = [];
		for (var i=0; i<arr.length; i++) {
			ret_arr = ret_arr.concat(arr[i]);
		}
		return ret_arr;
	},
	getElementsById: function() {
		try {
			var els = new Array();
			for (var i=0; i<arguments.length; i++) {
				var el = arguments[i];
				if (typeof el == 'string') el = document.getElementById(el);
				if (arguments.length == 1) return el;
				els.push(el);
			}
			return els;
		} catch(e) {
			this.debug(e);
			return null;
		}
	},
	getElementsByClassName: function(classname, parent_el, tag) {
		try {
			if (typeof parent_el == 'string') parent_el = document.getElementById(parent_el);
			if (!!document.evaluate) {
				var q = ".//*[contains(concat(' ', @class, ' '), ' " + classname + " ')]";
				return this.getElementsByXPath(q, parent_el);
			} else {
				var class_els = new Array();
				if (parent_el == null) parent_el = document;
				if (tag == null) tag = '*';
				var els = parent_el.getElementsByTagName(tag);
				var pattern = new RegExp("(^|\\s)"+classname+"(\\s|$)");
				for (i=0,j=0; i<els.length; i++) {
					if (pattern.test(els[i].className) ) {
						class_els[j] = els[i];
						j++;
					}
				}
				return class_els;
			}
		} catch(e) {
			this.debug(e);
			return null;
		}
	},
	getElementsByXPath: function(expression, parent_el) {
		if (typeof parent_el == 'string') parent_el = document.getElementById(parent_el);
	  var results = [];
	  var query = document.evaluate(expression, parent_el || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
	  for (var i = 0, _length = query.snapshotLength; i < _length; i++) {
	  	results.push(query.snapshotItem(i));
	  }
	  return results;
	},
	makeRequest: function(url,events,o) {
		try {
			var XMLHttpFactories = [
				function() {return new XMLHttpRequest();},
				function() {return new ActiveXObject("Msxml2.XMLHTTP");},
				function() {return new ActiveXObject("Msxml3.XMLHTTP");},
				function() {return new ActiveXObject("Microsoft.XMLHTTP");}
			];
			var createReqObj = function() {
				var xmlhttp = false;
				for (var i=0; i<XMLHttpFactories.length; i++) {
					try {
						xmlhttp = XMLHttpFactories[i]();
					} catch(e) {
						continue;
					}
					break;
				}
				return xmlhttp;
			};

			var req = createReqObj();
			if (!req) return;

			var _method = (o.postData) ? "POST" : "GET";

			req.open(_method,url,true);
			req.setRequestHeader('User-Agent','XMLHTTP/1.0');
			req.setRequestHeader('If-Modified-Since','Wed, 15 Nov 1995 00:00:00 GMT');
			if (o.postData) req.setRequestHeader('Content-type','application/x-www-form-urlencoded');

			req.onreadystatechange = function () {
				if (req.readyState != 4) return;
				if (req.status != 200 && req.status != 304) {
					events.failure.call(events.context,[req,o.params]);
					return;
				}
				events.success.call(events.context,[req,o.params]);
			};
			if (req.readyState == 4) return;
			req.send(o.postData);
		} catch(e) {
			this.debug(e);
		}
	},
	Template: function(str) {
		this.sourceString = str;
		this.evaluate = function(valueset,valuelogic) {
			var s = this.sourceString;
			//trying to avoid eval!
			try {
				if (valuelogic) {
					for (var key in valuelogic) {
						var regex = new RegExp("\\["+key+": \\{(.*?)\\}\\]","i");
						var set = regex.exec(s);

						if (!set) continue;

						var fullset = set[0];
						var replaceStr = set[1].split('||');
						var strArr = [];
						for (var i=0; i<replaceStr.length; i++) {
							if (replaceStr[i].match(valuelogic[key]+':')) {
								s = s.replace('#'+fullset,replaceStr[i].substr(replaceStr[i].indexOf(':')+1,replaceStr[i].length));
							}
						}
					}
				}
				if (valueset != null) {
					for (var key in valueset) {
						var pattern = '#\{('+key+')\}';
						var regex = new RegExp(pattern,'gm');
						s = s.replace(regex,valueset[key]);
					}
				}
				return s;
			} catch(e) {
				CBC.UTIL.debug(e);
				return '';
			}
		};
	},

	truncate: function(str,len) {
		return ( (str.length < len) ? str : str.substring(0,len-1)+'...' );
	},

	getTimeDifference: function(date) {
		try {
			var d = new Date();
			var offset = this.gmt_offset;
			var local_time = d.getTime();
			var local_offset = d.getTimezoneOffset() * (60*1000);
			var utc = local_time + local_offset;
			var et = utc + (3600000*offset);
			date = new Date(date);

			var diff = ( Date.parse(new Date(et).toUTCString()) - Date.parse(date.toUTCString()) ) / 1000;

			if (diff/(60*60*24*30.4368499*12) > 1) {
				diff = diff/(60*60*24*30.4368499*12);
				_split = diff.toString().split(".");
				diff = _split[0] + ( (_split[1].substring(0,1) == "0") ? "" : "." + _split[1].substring(0,1) );
				diff += (diff > 1) ? " years" : " year";
			} else if (diff/(60*60*24*30.4368499) > 1) {
				diff = Math.round(diff/(60*60*24*30.4368499));
				diff += (diff > 1) ? " months" : " month";
			} else if (diff/60 > 60) {
				diff = Math.round(diff/(60*60));
				if (diff > 23) {
					diff = Math.round(diff/24);
					diff += (diff > 1) ? " days" : " day";
				} else {
					diff += (diff > 1) ? " hours" : " hour";
				}
			} else if (diff > 60) {
				diff = Math.round(diff/60);
				diff += (diff > 1) ? " minutes" : " minute";
			} else {
				diff = Math.round(diff);
				diff += (diff > 1) ? " seconds" : " second";
			}
			return diff;

		} catch(e) {
			this.debug(e);
			return "";
		}
	},

	getPaginatorHtml: function(paginator, tpls) {
		try {
			var tpl_paginator_li = tpls.li;
			var tpl_paginator_li_attrib = tpls.li_attrib;
			var tpl_paginator_li_prev_on = tpls.li_prev_on;
			var tpl_paginator_li_prev_attrib = tpls.li_prev_attrib;
			var tpl_paginator_li_prev_off = tpls.li_prev_off;
			var tpl_paginator_li_next_on = tpls.li_next_on;
			var tpl_paginator_li_next_attrib = tpls.li_next_attrib;
			var tpl_paginator_li_next_off = tpls.li_next_off;
			var tpl_paginator_li_first = tpls.li_first;
			var tpl_paginator_li_first_attrib = tpls.li_first_attrib;
			var tpl_paginator_li_first_off = tpls.li_first_off;
			var tpl_paginator_li_last = tpls.li_last;
			var tpl_paginator_li_last_attrib = tpls.li_last_attrib;
			var tpl_paginator_li_last_off = tpls.li_last_off;
			var pages = Math.ceil(paginator.number_of_items / paginator.number_per_page);
			if (pages == 1) return "";
			var lis_html = '';

			var page_tpl_data = {};
			page_tpl_data.itemKey = paginator.itemKey;
			//page_tpl_data.sort = paginator.sort;
			page_tpl_data.anchor = paginator.anchor;

			page_tpl_data.prevPage = (paginator.current_page > 1) ? paginator.current_page-1 : paginator.current_page;
			page_tpl_data.nextPage = (paginator.current_page < pages) ? paginator.current_page+1 : paginator.current_page;
			page_tpl_data.firstPage = 1;
			page_tpl_data.lastPage = pages;
			page_tpl_data.attrib = tpl_paginator_li_attrib.evaluate(page_tpl_data);

			var page_start = paginator.current_page-5;
			var page_end = paginator.current_page+4;
			while (page_end > pages) { page_end--; page_start--; }
			while (page_start < 1) { page_start++; page_end++; }
			if (page_end > pages) page_end = pages;

			for (var i=page_start; i<=page_end; i++) {
				page_tpl_data.pageNumber = i;
				page_tpl_data.activeClass	= (i == paginator.current_page) ? 'active' : '';
				lis_html += tpl_paginator_li.evaluate(page_tpl_data);
			}

			//prev & next
			page_tpl_data.attrib = tpl_paginator_li_prev_attrib.evaluate(page_tpl_data);
			var li_prev_html = (paginator.current_page > 1) ? tpl_paginator_li_prev_on.evaluate(page_tpl_data) : tpl_paginator_li_prev_off.evaluate(page_tpl_data);
			page_tpl_data.attrib = tpl_paginator_li_next_attrib.evaluate(page_tpl_data);
			var li_next_html = (paginator.current_page < pages) ? tpl_paginator_li_next_on.evaluate(page_tpl_data) : tpl_paginator_li_next_off.evaluate(page_tpl_data);

			//first & last
			page_tpl_data.attrib = tpl_paginator_li_first_attrib.evaluate(page_tpl_data);
			var li_first_html = (paginator.current_page > 1) ? tpl_paginator_li_first.evaluate(page_tpl_data) : tpl_paginator_li_first_off.evaluate(page_tpl_data);;
			page_tpl_data.attrib = tpl_paginator_li_last_attrib.evaluate(page_tpl_data);
			var li_last_html = (paginator.current_page < pages) ? tpl_paginator_li_last.evaluate(page_tpl_data) : tpl_paginator_li_last_off.evaluate(page_tpl_data);;
			if (paginator.number_of_pages < 11) {
				li_first_html = li_last_html = "";
			}
			return '<ul class="paginator">' + li_first_html + li_prev_html + lis_html + li_next_html + li_last_html + '</ul>';

		} catch(e) {
			this.debug(e);
			return "";
		}

	},

	setMask: function(mode, settings) { //mode - 0: clear fog, 1: show fog, 2: show loading || settings - y1: top element, y2: bottom element
		try {
			if (!this.getElementsById('fog')) {
				var div = document.createElement("div");
				div.id = "fog";
				document.body.appendChild(div);
			}

			this.getElementsById('fog').removeAttribute("style");
			CBC.DOM.setStyle('fog',"height",CBC.DOM.getDocumentHeight()+'px');
			CBC.DOM.removeClass('fog',"loading");
			switch (mode) {
				case 0:
					var display = "none";
					break;
				case 1:
					var display = "block";
					break;
				case 2:
					var display = "block";
					var y1 = settings.y1;
					var y2 = settings.y2;
					var vpheight = CBC.DOM.getViewportHeight();
					var pfheight = CBC.DOM.getY(y2) - CBC.DOM.getY(y1);
					if (pfheight < vpheight) { //full canvas in view
						var y = pfheight/2 + CBC.DOM.getY(y1) - 25;
					} else { //canvas cut off
						var y = vpheight/2 + CBC.DOM.getY(y1);
					}
					CBC.DOM.setStyle('fog',"backgroundPosition",'center ' + y + 'px');
					CBC.DOM.addClass('fog',"loading");
					break;
				default:
					var display = "none";
					break;
			}
			CBC.DOM.setStyle('fog',"display",display);
		} catch(e) { this.debug(e); }
	},

	// reports the size of an object (best for objects used as associative arrays)
	objSize: function(obj) {
		var size = 0;
		for(key in obj) {
			if(obj.hasOwnProperty(key)) size++;
		}

		return size;
	},

	//cookies & query strings
	getObjectFromCookie: function(cookiename) {
		var pair;
		var obj = {};
		var str = this.readCookie(cookiename);
		if (!str) return null;
		str = str.split("&");
		for (var i=0; i<str.length;i++) {
			pair = str[i].split("=");
			pair[0] = pair[0].replace(/\s/,"");
			obj[pair[0]] = pair[1];
		}
		return obj;
	},
	queryStringToObj: function(qs) {
		var pairs = qs.split(/[;&]/);
		var obj = new Object();
		for (var i=0; i<pairs.length; i++) {
			var pair = pairs[i].split('=');
			var key = unescape(pair[0].toLowerCase());
			var val = unescape(pair[1]).replace(/\+/g, ' ');
			if (key.length > 0 && val.length > 0) {
				obj[key] = val;
			}
		}
		return obj;
	},
	objToQueryString: function(obj) {
		var qs = "";
		var i = 0;
		for (var key in obj) {
			if (i>0) qs+="&";
			qs+= (key+"="+obj[key]);
			i++;
		}
		return qs;
	},

	//forms
	trim: function(str) {
		return str.replace(/^\s+|\s+$/g,"");
	},
	getSelectOptionsHTML: function(_start,_end) {
		var _res = "";
		if (_start > _end) {
			for (var i=_start; i>_end-1; i--) {
				_res += '<option value="' + i + '">' + i + '</option>';
			}
		} else {
			for (var i=_start; i<_end+1; i++) {
				_res += '<option value="' + i + '">' + i + '</option>';
			}
		}
		return _res;
	},
	getCheckedInputRadio: function(els) {
		for (var i=0; i<els.length; i++) {
			if (els[i].checked) return els[i];
		}
		return null;
	},
	setCheckedInputRadio: function(els,val) {
		for (var i=0; i<els.length; i++) {
			if (els[i].value == val) els[i].checked = true;
		}
	},
	validateField: function(_el,val) {
		if (this.trim(_el.value) == val) {
			_el.className += " error";
			_el.focus();
			return true;
		}
		return false;
	},
	validateRadioField: function(els,parent_el) {
		for (var i=0; i<els.length; i++) {
			if (els[i].checked) {
				return false;
			}
		}
		parent_el.className += " error";
		return true;
	},
	validateSelectField: function(_el,val) {
		if (_el.selectedIndex == val) {
			_el.className += " error";
			return true;
		}
		return false;
	},
	resetFields: function(els,classname) {
		for (var i=0; i<els.length; i++) {
			var _regex = new RegExp(classname,"g");
			els[i].className = els[i].className.replace(_regex,"");
		}
	}
};

if (!CBC.SETTINGS) {
CBC.SETTINGS = function() {
	var $config = [];
	return {
		getVal: function(name) {
			return $config[name];
		},
		setVal: function(name,val) {
			$config[name] = val;
		}
	};
}();
}

if (!CBC.APP) CBC.APP = {};
CBC.DOM = YAHOO.util.Dom;
CBC.EVENT = YAHOO.util.Event;

CBC.register = function(o) {
	if (o._nameSpace[o._name]) return;
	o._nameSpace[o._name] = new o._class();
	if (o._nameSpace[o._name].init) o._nameSpace[o._name].init(o._params);
};

CBC.loadAssets = function(o) {
	var head = document.getElementsByTagName('head')[0];
	var script = document.createElement('script');
	if (o._id) script.id = o._id;
	script.type = 'text/javascript';
	script.src = o._src;
	head.appendChild(script);
};

function cbcutil_getGMTOffset() { //http://en.wikipedia.org/wiki/Daylight_saving_time_around_the_world#Canada
	var d = new Date();
	var current_year = d.getFullYear();
	var days_delta = Math.floor(1+current_year*5/4)%7;
	var daylight = new Date(current_year+"/03/"+(14-days_delta)+" 01:59"); //second sunday in march (daylight savings time)
	var standard = new Date(current_year+"/11/"+(7-days_delta)+" 01:59"); //first sunday in november (standard time)
	return (d > daylight && d < standard) ? -4 : -5;
}
