window.addEvent('domready', function() {
	global_nav.init();
	notifications.init();
	notice_box.init();
});

Request.DEQQ = new Class({
	Extends: Request.JSON,
	
	success: function(text) {
		this.response.json = JSON.decode(text, this.options.secure);
		this.onSuccess(this.response.json);
	},
	
	failure: function() {
		var response = JSON.decode(this.xhr.responseText, true);
		
		if(response) {
			if(response.exception) {
				new ErrorOverlay(response.summary, response.message);
			}
		} else {
			if(this.xhr.status != 0) {
				var message = 'This action could not be completed. Try again in 5 min.';
				
				if(Cookie.read('DEBUG', {path: '/'})) {
					message = this.xhr.responseText
				}
				
				new ErrorOverlay('Fatal Error', message);
			}
		}
		
		this.fireEvent('complete').fireEvent('failure', response);
	},
	
	onException: function(key, value) {
		new ErrorOverlay('Fatal Error\nUnable to set header: "' + key + ': ' + value + '".');
		
		this.onFailure();
	}
});

Live_Text = new Class({
	Implements: [Options, Events],
	
	options: {
		/*
		onNothing: $empty,
		onInput: $empty,
		onSuccss: $empty,
		onFailure: $empty,
		*/
		
		timeout: 300,
		ignore: /^$/
	},
	
	timer: null,
	
	initialize: function(text_box, url, options) {
		this.setOptions(options);
		
		this.text_box = $(text_box);
		
		this.text_box.addEvent('keyup', this.change.bind(this));
		
		this.req = new Request.DEQQ({url: url, onSuccess: this.success.bind(this), onFailure: this.failure.bind(this)});
		
		this.old_value = this.text_box.value;
		this.change(true);
	},
	
	set: function(value) {
		this.text_box.value = value;
		this.change(true);
	},
	
	cancel: function() {
		this.text_box.removeClass('wait');
		$clear(this.timer);
		this.req.cancel();
	},
	
	change: function(e, supress_req) {
		var value = this.text_box.value;
		
		if(this.old_value !== value && !this.options.ignore.test(value)) {
			$clear(this.timer);
			this.req.cancel();
			
			if(value === '') {
				this.text_box.removeClass('wait');
				this.nothing();
				this.fireEvent('nothing');
			} else {
				if(supress_req !== true) {
					this.text_box.addClass('wait');
					this.timer = this.req.GET.delay(this.options.timeout, this.req, {'value': value});
				}
				this.fireEvent('input', [value]);
			}
			
			this.old_value = value;
		} else {
			this.fireEvent('input', [value]);
		}
	},
	
	nothing: function() {},
	
	success: function(response) {
		this.text_box.removeClass('wait');
		this.fireEvent('success', response);
	},
	
	failure: function() {
		this.text_box.removeClass('wait');
		this.fireEvent('failure');
	}
});

Suggest_Text = new Class({
	Extends: Live_Text,
	
	options: {
		/*
		onItemClick: $empty,
		*/
	},
	
	initialize: function(text_box, url, options) {
		this.setOptions(options);
		
		this.parent(text_box, url, options)
		
		this.text_box.addEvent('keypress', this.keyPress.bindWithEvent(this))
		
		this.results = new Element('div', {id: this.text_box.id + '-results', 'class': 'search-results hidden'});
		this.results.inject(this.text_box, 'after');
		
		this.dialog = new Overlay(this.results, {deadElements: [this.text_box]});
	},
	
	success: function(response) {
		if(response.html) {
			this.results.set('html', response.html);
			this.selected = this.results.getElement('ol > li::first-child');
			this.results.getElements('ol > li').each(function(el) {
				el.addEvent('mouseenter', this.mouseOver.bindWithEvent(this, el));
				el.addEvent('click', this.click.bindWithEvent(this));
			}, this);
			this.dialog.show();
		} else {
			this.nothing();
		}
		
		this.parent(response);
	},
	
	nothing: function() {
		this.results.set('html', '');
		this.dialog.hide();
	},
	
	mouseOver: function(e, el) {
		this.selected.removeClass('selected');
		el.addClass('selected');
		
		this.selected = el;
	},
	
	click: function(e) {
		this.dialog.hide();
		
		this.fireEvent('itemClick', [e]);
	},
	
	keyPress: function(e) {
		if(e.key == 'enter') {
			this.dialog.hide();
			
			this.fireEvent('enter');
		} else if(e.key == 'up' || e.key == 'down') {
			e.preventDefault();
			
			this.selected.removeClass('selected')
			
			if(e.key == 'up') {
				var prev = this.selected.getPrevious('li');
				if(prev === null) {
					this.selected = this.selected.getParent().getLast();
				} else {
					this.selected = prev;
				}
			} else {
				var next = this.selected.getNext('li');
				if(next === null) {
					this.selected = this.selected.getParent().getFirst();
				} else {
					this.selected = next;
				}
			}
			
			this.selected.addClass('selected');
		}
	}
});

Overlay = new Class({
	Implements: [Options, Events],
	
	options: {
		/*
		onShow: $empty,
		onHide: $empty,
		*/
		button: null,
		deadElements: []
	},
	
	initialize: function(element, options) {
		this.setOptions(options);
		
		this.element = $(element);
		this.button = null;
		
		if(this.options.button) {
			this.button = $(this.options.button);
			this.button.addEvent('mousedown', this.preventDefault.bindWithEvent(this));
			this.button.addEvent('click', this.buttonClick.bindWithEvent(this));
		}
		
		if(this.options.close) {
			this.close_button = $(this.options.close);
			this.close_button.addEvent('click', this.hide.bind(this));
		}
		
		this.bound = {
			'mousedown': this.mouseDown.bindWithEvent(this),
			'keydown': this.keyDown.bindWithEvent(this)
		};
	},
	
	preventDefault: function(e) {
		if($(e.target) === this.button) {
			e.preventDefault();
		}
	},
	
	buttonClick: function(e) {
		if($(e.target) === this.button) {
			if(this.element.hasClass('hidden')) {
				this.show();
			} else {
				this.hide();
			}
		}
	},
	
	show: function() {
		document.addEvent('mousedown', this.bound.mousedown);
		document.addEvent('keydown', this.bound.keydown);
		
		this.element.removeClass('hidden');
		
		this.fireEvent('show');
	},
	
	hide: function() {
		document.removeEvent('mousedown', this.bound.mousedown);
		document.removeEvent('keydown', this.bound.keydown);
		
		this.element.addClass('hidden');
		
		this.fireEvent('hide');
	},
	
	mouseDown: function(e) {
		if(!e.rightClick && !this.cameThroughElement(e.target)) {
			this.hide();
		}
	},
	
	keyDown: function(e) {
		if(e.key === 'esc') {
			this.hide();
		}
	},
	
	cameThroughElement: function(target) {
		var t = $(target);
		
		do {
			if(t === this.element || t === this.button || this.options.deadElements.contains(t)) {
				return true;
			}
			
			t = t.parentNode;
		} while(t !== null && t !== document);
		
		return false;
	}
});

ShadowOverlay = new Class({
	Extends: Overlay,
	
	show: function() {
		this.buildShadow();
		this.parent();
	},
	
	buildShadow: function() {
		if(!this.isbuilt) {
			this.content = new Element('div', {'class': 'content'}).inject(this.element);
			
			new Element('div', {'class': 'shadow top'}).inject(this.element);
			new Element('div', {'class': 'shadow right'}).inject(this.element);
			new Element('div', {'class': 'shadow bottom'}).inject(this.element);
			new Element('div', {'class': 'shadow left'}).inject(this.element);
			new Element('div', {'class': 'shadow bottom-right'}).inject(this.element);
			new Element('div', {'class': 'shadow bottom-left'}).inject(this.element);
			new Element('div', {'class': 'shadow top-right'}).inject(this.element);
			new Element('div', {'class': 'shadow top-left'}).inject(this.element);
			
			this.isbuilt = true;
		}
	}
})

ErrorOverlay = new Class({
	Extends: ShadowOverlay,
	
	options: {
		is_html: false
	},
	
	initialize: function(summary, message, options) {
		this.setOptions(options);
		
		this.message_box = new Element('div', {'class': 'error-message overlay', styles: {visibility: 'hidden'}});
		var close = new Element('span', {'class': 'close'});
		
		this.parent(this.message_box, {'close': close})
		this.buildShadow();
		
		close.inject(this.content);
		
		var html = this.options.is_html === true ? 'html' : 'text';
		
		var msg = $defined(message) ? message : summary;
		
		var body = new Element('div', {'class': 'body ' + html}).set(html, msg).inject(this.content);
		
		if($defined(message)) {
			new Element('h3').set('text', summary).inject(this.content, 'top');
		}
		
		this.message_box.inject(document.body);
		
		this.show();
		
		this.message_box.setStyles({
			marginLeft: -this.message_box.offsetWidth / 2,
			marginTop: -this.message_box.offsetHeight / 2,
			visibility: 'visible'
		});
	},
	
	hide: function() {
		this.message_box.dispose();
		
		this.parent();
	}
});

Alert = new Class({
	Extends: ShadowOverlay,
	
	options: {
		container: null
	},
	
	initialize: function(message, options) {
		this.setOptions(options);
		var container = $defined(this.options.container) ? this.options.container : document.body
		
		var form_html = '<fieldset><h3>' + message + '</h3><input type="button" class="confirm-button" name="ok" value="Ok"></fieldset>';
		this.form = new Element('form', {'class': 'confirm-form overlay'});
		this.form.inject(container);
		this.parent(this.form, options);
		
		this.buildShadow();
		this.content.set('html', form_html);
		$(this.form.elements['ok']).addEvent('click', this.ok.bind(this));
		
		this.content.getElement('input[name=ok]').focus();
		this.show();
	},
	
	ok: function(ev) {
		this.hide();
	}
});

Confirm = new Class({
	Extends: ShadowOverlay,
	
	options: {
		/*
		onOk: $empty,
		onCancel: $empty
		*/
		container: null,
		okdefault: false
	},
	
	initialize: function(message, ok_label, cancel_label, options) {
		this.setOptions(options);
		
		var container = $defined(this.options.container) ? this.options.container : document.body
		
		var form_html = '<fieldset><h3>' + message + '</h3><input type="button" class="confirm-button" name="ok" value="' + ok_label + '"><input type="button" class="cancel-button" name="cancel" value="' + cancel_label + '"></fieldset>';
		
		this.form = new Element('form', {'class': 'confirm-form overlay'});
		
		this.form.inject(container);
		
		this.parent(this.form, options);
		
		this.buildShadow();
		
		this.content.set('html', form_html);
		
		if(this.options.okdefault) {
			this.content.getElement('input[name=ok]').focus();
		} else {
			this.content.getElement('input[name=cancel]').focus();
		}
		
		$(this.form.elements['ok']).addEvent('click', this.ok.bind(this));
		$(this.form.elements['cancel']).addEvent('click', this.cancel.bind(this));
		
		this.show();
	},
	
	ok: function() {
		this.hide();
		this.fireEvent('ok');
	},
	
	cancel: function() {
		this.hide();
		this.fireEvent('cancel');
	},
	
	hide: function() {
		this.parent();
		
		this.form.dispose();
	}
});

modal_dialog = {
	show: function(id) {
		this.bound = {
			mouseDown: this.keyPress.bindWithEvent(this)
		}
		
		document.addEvent('keypress', this.bound.mouseDown);
		
		$('modal-dialog').setStyle('visibility', 'hidden');
		$('modal-pane').removeClass('hidden');
		
		$$('#modal-dialog > div.content > *').addClass('hidden');
		$(id).removeClass('hidden');
		
		var width = $('modal-dialog').offsetWidth;
		var height = $('modal-dialog').offsetHeight;
		
		$('modal-dialog').setStyles({'margin-left': -width / 2, 'margin-top': -height / 2, visibility: 'visible'});
	},
	
	keyPress: function(e) {
		if(e.key == 'esc') {
			this.hide();
		}
	},
	
	hide: function() {
		if(this.bound.mouseDown) {
			document.addEvent('keypress', this.bound.mouseDown);
			this.bound.mouseDown = null;
		}
		
		$('modal-pane').addClass('hidden');
	}
};

global_nav = {
	init: function() {
		if($('search')) {
			$('search').addEvent('submit', this.cancelSubmit.bindWithEvent(this));
			
			$('search-box').addEvents({
				focus: function() {
					this.setStyles({
						color: '#ccc',
						backgroundColor: 'rgba(0,0,0,0.8)',
						border: '1px solid rgba(255,255,255,0.4)'
					});
					if (this.defaultValue==this.value) this.value = "";
				},
				blur: function() {
					this.setStyles({
						color: '#999',
						backgroundColor: 'rgba(0,0,0,0.4)',
						border: '1px solid rgba(255,255,255,0.2)'
					});
					if (this.value=="") this.value = this.defaultValue;
				}
			});
			
			this.search_box = new Suggest_Text('search-box', '/search', {
				onNothing: this.onNothing.bind(this),
				onSuccess: this.onSuccess.bind(this),
				onEnter: this.onEnter.bind(this)
			});
			
			this.items = [];
		}
		
		if($('community-switcher')) {
			this.oneTimeLoad = true;
			community_dialog = new Element('div', {id: 'nav-communities-dialog', 'class': 'overlay hidden'}).inject(document.body);
			
			this.communities = new ShadowOverlay(community_dialog, {button: 'community-switcher', onShow: this.loadCommunities.bind(this)});
		}
	},
	
	cancelSubmit: function(e) {
		e.stop();
	},
	
	onSuccess: function(results) {
		this.items = results.items;
	},
	
	onNothing: function() {
		this.items = [];
	},
	
	onEnter: function() {
		if(this.items.length > 0) {
			var index = this.search_box.selected.getParent().getChildren().indexOf(this.search_box.selected);
			location = '/' + this.items[index].type + '/' + this.items[index].handle;
		}
	},
	
	loadCommunities: function() {
		if(this.oneTimeLoad) {
			this.oneTimeLoad = false;
			$('nav-communities-dialog').addClass('loading');
			new Request.DEQQ({url: '/community', onSuccess: this.showCommunities.bind(this)}).GET();
		}
	},
	
	showCommunities: function(response) {
		this.communities.element.removeClass('loading');
		this.communities.content.set('html', response.html);
		this.communities.element.getElement('span.close').addEvent('click', this.hideCommunities.bind(this))
	},
	
	hideCommunities: function() {
		this.communities.hide();
	}
}

notice_box = {
	init: function() {
		var init_title = Cookie.read('notice_title', {path: '/'});
		var init_message = Cookie.read('notice_message', {path: '/'});
		
		if((init_message !== null) && (init_message !== null)) {
			new ErrorOverlay(init_title, init_message);
		}

		if(init_message !== null) {
			Cookie.dispose('notice_message', {path: '/'});
		}
		if(init_title !== null) {
			Cookie.dispose('notice_title', {path: '/'});
		}
	}
}

notifications = {
	init: function() {
		this.el = new Element('div', {id: 'notifications'}).inject(document.body);
		
		this.el.set('tween', {transition: Fx.Transitions.Expo.easeOut});
		
		var init_message = Cookie.read('message', {path: '/'});
		
		if(init_message !== null) {
			this.add.delay(250, this, init_message);
		}
		
		if(navigator.userAgent.toLowerCase().indexOf('msie 6') != -1 && navigator.userAgent.toLowerCase().indexOf('msie 7') == -1) {
			this.warning = new Element('div', {'class': 'error message'}).inject($('page-message'));
			this.warning.set('html', 'Internet Explorer 6 is not supported by DEQQ. Please upgrade to the latest version of <a href="http://www.getfirefox.com" title="Download the latest version of Firefox">Firefox</a> or <a href="http://www.microsoft.com/ie/" title="Download the latest version of Internet Explorer">Internet Explorer</a>.');
		}
		
	},
	
	add: function(message) {
		if(message === null) {
			return;
		}
		
		this.el.set('text', message);
		
		this.size = this.el.getSize();
		
		this.el.setStyle('margin-left', Math.floor(-this.size.x / 2));
		
		if(this.timer) {
			this.el.highlight();
		} else {
			this.el.tween('bottom', -8);
		}
		
		$clear(this.timer);
		
		Cookie.dispose('message', {path: '/'});
		
		this.timer = this._hide.delay(10000, this);
	},
	
	_hide: function() {
		this.el.tween('bottom', (-this.size.y-10));
		this.timer = null;
	}
}

function getHandleFromElement(el, type) {
	var re = RegExp('\\b' + type + '-([\\w-]{1,32})\\b');
	
	var matches = el.className.match(re);
	
	if(matches !== null) {
		return matches[1];
	} else {
		return null;
	}
}

function getDataFromId(el) {
	parts = el.id.split('-');
	delete parts[0];
	return parts.clean().join('-');
}
