var belanger = {
	init: function() {
		ub.a.append(this.events, ub.e.attach(window, 'load', function(e) {
			try {
				this.nodes.navTop = ub.$('navTop');
				this.nodes.navLeft = ub.$('navLeft');
				this.nodes.search = ub.$('search');
				this.nodes.searchForm = ub.$('searchForm');
				this.nodes.searchFormInput = ub.$('searchFormInput');
				this.nodes.SR = ub.$('SR');
				this.nodes.SRWrapper = ub.$('SRWrapper');
				this.nodes.SRClose = ub.$('SRClose');
				this.nodes.SRContainer = ub.$('SRContainer');
				this.nodes.tipContainer = ub.$('tip_container');
				this.nodes.tipContent = ub.$('tip_content');
				this.nodes.tipArrowTop = ub.$('tip_arrow_top');
				this.nodes.tipArrowRight = ub.$('tip_arrow_right');
				this.nodes.tipArrowBottom = ub.$('tip_arrow_bottom');
				this.nodes.tipArrowLeft = ub.$('tip_arrow_left');
				
				this.menuPrep();
				this.page.init();
				this.search.init();
				this.dialog.init();
				this.tip.init();
				//get a user session
				ub.json.async.post('session::get', [], function(json) {
					if(json.result == 'pass') {
						this.user.session = json.response;
						this.onsessionloaded(new ub.e.event('sessionloaded'));
						this.ping.interval = setInterval(function() {
							belanger.ping.send();
						}, 10000);
					}
				}, null, this);
				this.onbelangerloaded(new ub.e.event('belangerloaded'));
			} catch(e) { alert(e.message); }
		}, false, this));
		ub.a.append(this.events, ub.e.attach(ub, 'unload', function(e) {
			this.destruct();
		}, false, this));
	},
	destruct: function() {
		ub.a.each(this.events, function(event) {
			if(event.detach) event.detach();
		}, this);
		ub.a.clear(this.events);
		for(var p in this.nodes) {
			this.nodes[p] = null;
		}
		this.page.destruct();
		this.dialog.destruct();
	},
	events: [],
	nodes: {},
	ping: {
		interval: null,
		send: function() {
			ub.json.async.post('session::ping', [], function(json) { });
		}
	},
	menuTargets: [],
	menuPrep: function() {
		ub.a.each(this.menuMap, function(menuMap) {
			//get handles on all the dom nodes used in the menuMap
			this.nodes[menuMap.li] = ub.$(menuMap.li);
			this.nodes[menuMap.menu] = ub.$(menuMap.menu);
			//determine if the li is in the top or left nav gutters
			var position = (ub.n.contains(this.nodes.navTop, this.nodes[menuMap.li])) ? 'bottom' : 'right';
			ub.a.append(this.menuTargets, { node: this.nodes[menuMap.li], menu: this.nodes[menuMap.menu], position: position });
		}, this);
		ub.a.each(this.menuTargets, function(target) {
			ub.a.append(this.events, ub.e.attach(target.node, 'mouseover', function(e) {
				this.menuShow(target);
			}, false, this));
			if(target.menu) {
				ub.a.append(this.events, ub.e.attach(target.menu, 'mouseout', function(e) {
					if(!ub.n.contains(target.menu, e.relatedTarget)) {
						ub.n.removeClassName(target.node, 'navActive');
						target.menu.style['display'] = 'none';
					}
				}, false, this));
			}
		}, this);
	},
	menuShow: function(target) {
		ub.a.each(this.menuTargets, function(_target) {
			if(_target == target) {
				if(_target.menu) {
					belanger.tip.hide();
					var cOffset = ub.n.cumulativeOffset(_target.node);
					var dims = ub.n.getDims(_target.node);
					if(_target.position == 'bottom') {
						ub.n.setCoords(target.menu, [cOffset[0] - 8, cOffset[1] + dims[1] - 5]);
					}
					else if(_target.position == 'right') {
						ub.n.setCoords(target.menu, [cOffset[0] + dims[0] - 10, cOffset[1] - 8]);
					}
					_target.menu.style['display'] = 'block';
					ub.n.addClassName(_target.node, 'navActive');
				}
			}
			else {
				if(_target.menu) {
					_target.menu.style['display'] = 'none';
					ub.n.removeClassName(_target.node, 'navActive');
				}
			}
		}, this);
	},
	user: {
		session: null,
		login: function(credentials) {
			ub.json.async.post('session::login', [credentials], function(json) {
				if(json.result == 'pass') {
					this.session.user_id = json.response.user_id;
					belanger.onuserlogin(new ub.e.event('userlogin'), json);
				} else {
					belanger.onuserloginfail(new ub.e.event('userloginfail'), json);
				}
			}, null, this);
		},
		logout: function() {
			ub.json.async.post('session::logout', [], function(json) {
				if(json.result == 'pass') {
					this.session.user_id = 0;
					belanger.onuserlogout(new ub.e.event('userlogout'));
				} else {
					belanger.onuserlogoutfail(new ub.e.event('userlogoutfail'), json);
				}
			}, null, this);
		}
	},
	page: {
		init: function() {
			this.mask.init();
		},
		destruct: function() {
			this.mask.destruct();
		},
		mask: {
			init: function() {
				this.bg = document.createElement('div');
				this.bg.className = 'mask';
				ub.$('mainContainer').appendChild(this.bg);//ub.$('content_wrapper').appendChild(this.bg);
				var coords = [0,80];//$('content_wrapper').cumulativeOffset();
				//adjust the coords
				coords[0] += 10;
				ub.n.setCoords(this.bg, [0,0]);
				this.bg.style['display'] = 'none';
				this.fx = new ub.fx.opacity(this.bg, { maxOpacity: 0.8 });
				this.fx.hide();
			},
			destruct: function() {
				this.bg = null;
				this.fx.destruct();
				this.fx = null;
			},
			bg: null,
			fx: null,
			show: function() {
				this.position();
				this.fx.expose();
				this.bg.style['display'] = 'block';
				document.body.style['cursor'] = 'wait';
			},
			hide: function() {
				this.position();
				document.body.style['cursor'] = 'default';
				this.fx.conceal();
				setTimeout(function() {
					belanger.page.mask.bg.style['display'] = 'none';
				}, this.fx.options.duration + 10);
			},
			position: function() {
				ub.n.setCoords(this.bg, [0,0]);
				this.bg.style['width'] = ub.$('mainContent').clientWidth + 'px';//(ub.$('content_wrapper').clientWidth - 20) + 'px';
				this.bg.style['height'] = ub.$('mainContent').clientHeight + 'px';//ub.$('content_wrapper').clientHeight + 'px';
			}
		}
	},
	search: {
		init: function() {
			this.events = belanger.events;
			this.nodes = belanger.nodes;
			this.hide();
			ub.a.append(this.events, ub.e.attach(this.nodes.searchFormInput, 'blur', function(e) {
				if(!ub.s.trim(this.nodes.searchFormInput.value || '')) {
					this.nodes.searchFormInput.value = 'Search Here';
					ub.n.addClassName(this.nodes.searchFormInput, 'inputActive');
				}
			}, false, this));
			ub.a.append(this.events, ub.e.attach(this.nodes.searchFormInput, 'focus', function(e) {
				if(ub.s.trim(this.nodes.searchFormInput.value) == 'Search Here')
					this.nodes.searchFormInput.value = '';
				ub.n.removeClassName(this.nodes.searchFormInput, 'inputActive');
			}, false, this));
			ub.a.append(this.events, ub.e.attach(document, 'keyup', function(e) {
				if(e.keyCode == 27)
					this.hide();
			}, false, this));
			ub.a.append(this.events, ub.e.attach(this.nodes.searchFormInput, 'keyup', function(e) {
				if(e.keyCode != 27)
					this.handleKeyUp();
			}, false, this));
			ub.a.append(this.events, ub.e.attach(this.nodes.SRClose, 'click', function(e) {
				this.hide();
			}, false, this));
		},
		destruct: function() {
			
		},
		events: null,
		nodes: null,
		show: function() {
			this.nodes.SRWrapper.style['display'] = 'block';
		},
		hide: function() {
			this.nodes.SRWrapper.style['display'] = 'none';
		},
		id: 0,
		handleKeyUp: function() {
			var q = ub.s.trim(this.nodes.searchFormInput.value || '');
			if(q) {
				var id = ++this.id;
				ub.u.setTimeout(function() {
					if(id == this.id) {
						this.go(q);
					}
				}, 500, this);
			}
			else {
				this.hide();
			}
		},
		go: function(q) {
			ub.json.async.post('page_search::by_all', [q], function(json) {
				if(json.result == 'pass') {
					this.prepResults(json.response, q);
				}
				else alert(json.response);
			}, null, this);
		},
		prepResults: function(results, q) {
			try {
				ub.n.removeChildren(this.nodes.SRContainer);
				if(!results.length) {
					var notice = ub.n.addNode(this.nodes.SRContainer, 'div');
					notice.setAttribute('class', 'inline_tip');
					notice.appendChild(document.createTextNode('No results returned for \''+ q +'\''));
				}
				else {
					//first index is the best result
					var base_score = results[0].score;
					//calculate the modifier used to adjust the scoring
					var modifier = 1 - results[0].tokensMissing.length / results[0].tokensTotal;
					ub.a.each(results, function(result) {
						//create a new results container
						var container = ub.n.addNode(this.nodes.SRContainer, 'a');
						container.setAttribute('class', 'SRContainer');
						container.setAttribute('href', result.pageURI);
						//add the score/relevancy
						var score = ub.n.addNode(container, 'span');
						score.setAttribute('class', 'SRScore');
						score.setAttribute('style', 'background-color: #'+ this.get_color(base_score, Math.round(result.score), modifier) +';');
						score.appendChild(document.createTextNode(Math.round(result.score / base_score * 100 * modifier, 0) +'%'));
						//add the title
						var title = ub.n.addNode(container, 'span');
						title.setAttribute('class', 'SRTitle');
						title.setAttribute('href', result.pageURI);
						title.appendChild(document.createTextNode(result.mainTitle +' - '+ result.pageTitle));
						//add the content sample
						//var content = ub.n.addNode(container, 'div');
						//content.setAttribute('class', 'SRContent');
						//content.appendChild(document.createTextNode(result.mainContent));
						//add the uri
						var uri = ub.n.addNode(container, 'span');
						uri.setAttribute('class', 'SRURI');
						uri.setAttribute('href', result.pageURI);
						uri.appendChild(document.createTextNode(' '+ result.pageURI));
					}, this);
				}
				this.show();
			} catch(e) { alert(e.message); }
		},
		get_color: function(ceiling, value, modifier) {
			ceiling = parseInt(ceiling);
			value = parseInt(value);
			var percent = value / ceiling * modifier;
			var hex = (255 - Math.round(128 * percent)).toString(16);
			while(hex.length < 2) {
				hex = '0'+ hex;
			}
			return hex +'ff'+ hex;
		}
	},
	dialog: {
		init: function() {
			this.events = belanger.events;
			this.nodes = belanger.nodes;
			this.fxDialog = new ub.widget.dialog();
			//add some custom modifications to the dialog widget
			ub.a.each(['notice_top_left', 'notice_top', 'notice_top_right',
			 'notice_right', 'notice_bottom_right', 'notice_bottom',
			 'notice_bottom_left', 'notice_left'], function(id) {
				 var div = document.createElement('div');
				 this.fxDialog.messageOuter.insertBefore(div, this.fxDialog.message);
				 div.setAttribute('id', id);
				 div = null;
			 }, this);
		},
		destruct: function() {
			this.fxDialog.destruct();
			this.fxDialog = null;
		},
		events: null,
		nodes: null,
		fxDialog: null,
		show: function(node, buttons, callback, scope) {
			if(!scope) scope = this;
			if(ub.u.isString(node)) {
				var div = document.createElement('div');
				div.innerHTML = node;
				node = div;
				div = null;
			}
			if(!ub.u.isArray(buttons)) {
				buttons = [buttons];
			}
			this.fxDialog.opacity.halt();
			this.fxDialog.expose(node, buttons, callback, scope);
		}
	},
	tip: {
		init: function() {
			this.events = belanger.events;
			this.nodes = belanger.nodes;
		},
		destruct: function() {
			
		},
		events: null,
		nodes: null,
		show: function(node, coords, avoidCoords, placement) {
			ub.n.removeChildren(this.nodes.tipContent);
			this.nodes.tipContent.appendChild(node);
			this.position(coords, placement, avoidCoords);
		},
		offset: 41, //23px padding + 36px/2 offset
		placement: {
			leftArrowTop: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0], coords[1] - this.offset]);
				this.nodes.tipArrowLeft.style['display'] = 'block';
				this.nodes.tipArrowLeft.style['top'] = '23px';
				this.nodes.tipArrowLeft.style['bottom'] = 'auto';
			},
			leftArrowBottom: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0], coords[1] - dims[1] + this.offset]);
				this.nodes.tipArrowLeft.style['display'] = 'block';
				this.nodes.tipArrowLeft.style['top'] = 'auto';
				this.nodes.tipArrowLeft.style['bottom'] = '23px';
			},
			rightArrowTop: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0] - dims[0], coords[1] - this.offset]);
				this.nodes.tipArrowRight.style['display'] = 'block';
				this.nodes.tipArrowRight.style['top'] = '23px';
				this.nodes.tipArrowRight.style['bottom'] = 'auto';
			},
			rightArrowBottom: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0] - dims[0], coords[1] - dims[1] + this.offset]);
				this.nodes.tipArrowRight.style['display'] = 'block';
				this.nodes.tipArrowRight.style['top'] = 'auto';
				this.nodes.tipArrowRight.style['bottom'] = '23px';
			},
			topArrowLeft: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0] - this.offset, coords[1]]);
				this.nodes.tipArrowTop.style['display'] = 'block';
				this.nodes.tipArrowTop.style['left'] = '23px';
				this.nodes.tipArrowTop.style['right'] = 'auto';
			},
			topArrowRight: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0] - dims[0] + this.offset, coords[1]]);
				this.nodes.tipArrowTop.style['display'] = 'block';
				this.nodes.tipArrowTop.style['left'] = 'auto';
				this.nodes.tipArrowTop.style['right'] = '23px';
			},
			bottomArrowLeft: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0] - this.offset, coords[1] - dims[1]]);
				this.nodes.tipArrowBottom.style['display'] = 'block';
				this.nodes.tipArrowBottom.style['left'] = '23px';
				this.nodes.tipArrowBottom.style['right'] = 'auto';
			},
			bottomArrowRight: function(coords, dims) {
				ub.n.setCoords(this.nodes.tipContainer, [coords[0] - dims[0] + this.offset, coords[1] - dims[1]]);
				this.nodes.tipArrowBottom.style['display'] = 'block';
				this.nodes.tipArrowBottom.style['left'] = 'auto';
				this.nodes.tipArrowBottom.style['right'] = '23px';
			}
		},
		position: function(coords, placement, avoidCoords) {
			this.nodes.tipContainer.style['display'] = 'block';
			this.nodes.tipContainer.style['left'] = '0px';
			this.nodes.tipContainer.style['top'] = '0px';
			
			this.nodes.tipArrowTop.style['display'] = 'none';
			this.nodes.tipArrowRight.style['display'] = 'none';
			this.nodes.tipArrowBottom.style['display'] = 'none';
			this.nodes.tipArrowLeft.style['display'] = 'none';
			
			var viewport = ub.u.viewportDims();
			var dims = ub.n.getDims(this.nodes.tipContainer);
			
			if(placement) {
				placement.call(this, coords, dims);
			}
			else {
				//calculate our boundaries
				var bounds = {
					leftArrow: [coords[0], coords[0] + dims[0]],
					rightArrow: [coords[0] - dims[0], coords[0]],
					topArrow: [coords[1], coords[1] + dims[1]],
					bottomArrow: [coords[1] - dims[1], coords[1]],
					topPosition: [coords[1] - this.offset, coords[1] + dims[1] - this.offset],
					bottomPosition: [coords[1] - dims[1] + this.offset, coords[1] + this.offset],
					leftPosition: [coords[0] - this.offset, coords[0] + dims[0] - this.offset],
					rightPosition: [coords[0] - dims[0] + this.offset, coords[0] + this.offset]
				};
				
				if(this._isAllowed(bounds.leftArrow, bounds.topPosition, viewport, avoidCoords))
					this.placement.leftArrowTop.call(this, coords, dims);
				else if(this._isAllowed(bounds.leftArrow, bounds.bottomPosition, viewport, avoidCoords))
					this.placement.leftArrowBottom.call(this, coords, dims);
				else if(this._isAllowed(bounds.rightArrow, bounds.topPosition, viewport, avoidCoords))
					this.placement.rightArrowTop.call(this, coords, dims);
				else if(this._isAllowed(bounds.rightArrow, bounds.bottomPosition, viewport, avoidCoords))
					this.placement.rightArrowBottom.call(this, coords, dims);
				else if(this._isAllowed(bounds.leftPosition, bounds.topArrow, viewport, avoidCoords))
					this.placement.topArrowLeft.call(this, coords, dims);
				else if(this._isAllowed(bounds.rightPosition, bounds.topArrow, viewport, avoidCoords))
					this.placement.topArrowRight.call(this, coords, dims);
				else if(this._isAllowed(bounds.leftPosition, bounds.bottomArrow, viewport, avoidCoords))
					this.placement.bottomArrowLeft.call(this, coords, dims);
				else if(this._isAllowed(bounds.rightPosition, bounds.bottomArrow, viewport, avoidCoords))
					this.placement.bottomArrowRight.call(this, coords, dims);
			}
		},
		hide: function() {
			this.nodes.tipContainer.style['display'] = 'none';
		},
		_isAllowed: function(xBoundary, yBoundary, viewport, avoidCoords) {
			if(
				xBoundary[0] < 0 || xBoundary[1] > viewport[0]
				|| yBoundary[0] < 0 || yBoundary[1] > viewport[1]
			) return false;
			if(
				avoidCoords
				&& xBoundary[0] <= avoidCoords[0] && xBoundary[1] >= avoidCoords[0]
				&& yBoundary[0] <= avoidCoords[1] && yBoundary[1] >= avoidCoords[1]
			) return false;
			return true;
		}
	},
	onsessionloaded: function(e) {},
	onbelangerloaded: function(e) {},
	onuserlogin: function(e, json) {},
	onuserlogout: function(e, json) {},
	onuserloginfail: function(e, json) {},
	onuserlogoutfail: function(e, json) {}
}
belanger.init();

