NEO = {
	Pop: function(src) {
		var width = arguments[1] || 600;	
		var height = arguments[2] || 400;	
		
		var o = $H({
			width: width,
			height: height,
			left: Math.floor((screen.width-width)/2),
			top: Math.floor((screen.height-height)/2),
			resizable: 'yes',
			scrollbars: 'yes'
		});
		
		var options = o.collect(function(pair) {
			return pair.join('=');
		}).join(',');
		
		openPopWindow(src, options, 'neopop');		
	},
	
	Send: function(form) {
		var f = $(form);
		var params 	= f.serialize(true);
		var error = f.down('tr.error');
		var success = f.down('tr.success');
		new Ajax.Request(_INDEX + '/ajax/email_friend', {
			parameters: params,
			onComplete: function(t) {
				if (t.status == 200 && t.responseText.isJSON()) {
					var r = t.responseText.evalJSON();
					if (r.error) {
						error.show();
						success.hide();
					} else {
						error.hide();
						success.down('span').update(r.email);
						success.show();
						$('rname').value='';
						$('remail').value='';
						$('smessage').value='';
					}
				}
				else {
					error.show();
					success.hide();
				}
			} 
		});
	}
}

NEO.Errors = Class.create({}, {
	initialize: function(errors) {
		this.options = Object.extend({
			prefix: '',
			focusFirst: false
	    }, arguments[1] || { });
		
		this.focused = false;
		
		$H(errors).each(this.apply.bind(this));		
	},
	
	apply: function(pair) {
		if (typeof pair.value == 'object') {
			var o = Object.clone(this.options);
			o.prefix+= pair.key + '_';
			return new NEO.Errors(pair.value, o);
		}
		
		var name 	= this.options.prefix + pair.key;
		var el 		= $(name);
		var l		= $$('label[for="' + name +'"]').first();
		var l2		= $$('.' + name)

		if (el)
			el.addClassName('error');
		
		if (l)
			l.addClassName('error');
		else if (l2)
			l2.invoke('addClassName','error');
		
		if (this.options.focusFirst && !this.focused && (l || el)) {
			if (el.focus) el.focus();
			if (l.scrollTo) l.scrollTo();
			this.focused = true;
		}

		var errors = $(this.options.prefix + 'errors');
		if (!errors) errors = $('errors');
		if (errors) errors.insert('<p class="error">' + pair.value + '</p>');
	}
});

NEO.Block = Class.create({}, {
	initialize: function(el, type) {
	this.options = Object.extend({
			expanded: 			false,
			expandedSelector: 	'.show_expanded',
			collapsedSelector: 	'.show_collapsed',
			handleSelector: 	'.box_control',
			classExpand:		'open',
			classCollapse:		'close',
			classClosed:		'closed',
			classExpand2:		'open2',
			classCollapse2:		'close2',
			txtExpand2:			_MESSAGES.EXPAND,
			txtCollapse2:		_MESSAGES.COLLAPSE
	    }, arguments[1] || {});
		
		this.el 		= $(el);
		this.type		= type ? type : '';
		if (this.type=='calendar')
			this.obj = arguments[2];
		this.handle		= this.el.down(this.options.handleSelector); 
		if (!this.handle) return;
		this.handle.observe('click', this.toggle.bindAsEventListener(this))
		this.display();
		this.el.show();
	},
	
	toggle: function(e) {
		e.stop();
		this.options.expanded = !this.options.expanded;
		this.display();
	},
	
	expand: function() {
		this.options.expanded = true;
		this.display();
	},
	
	collapse: function() {
		this.options.expanded = false;
		this.display();
	},
	
	display: function() {
		this.el.select(this.options.expandedSelector).each(this.options.expanded ? Element.show : Element.hide);
		this.el.select(this.options.collapsedSelector).each(this.options.expanded ? Element.hide : Element.show);
		switch(this.type){
		case '2':
			if (this.options.expanded){
				this.handle.removeClassName(this.options.classExpand2).addClassName(this.options.classCollapse2);
				this.handle.update(this.options.txtCollapse2);
			} else {
				this.handle.removeClassName(this.options.classCollapse2).addClassName(this.options.classExpand2);
				this.handle.update(this.options.txtExpand2);
			}
			break;
		default:
			if (this.options.expanded){
				this.handle.removeClassName(this.options.classExpand).addClassName(this.options.classCollapse);
				this.el.removeClassName(this.options.classClosed);
				if (this.type=='calendar')
					this.obj.loadCalendar();
			} else {
				this.handle.removeClassName(this.options.classCollapse).addClassName(this.options.classExpand);
				this.el.addClassName(this.options.classClosed);
			}
		}
	} 
});

// based on http://code.google.com/p/js-uri/
NEO.URI = Class.create({}, {
	initialize: function(str) {
		if (!str) str = "";
	    // Based on the regex in RFC2396 Appendix B.
	    var parser = /^(?:([^:\/?\#]+):)?(?:\/\/([^\/?\#]*))?([^?\#]*)(?:\?([^\#]*))?(?:\#(.*))?/;
	    var result = str.match(parser);
	    this.scheme    = result[1] || null;
	    this.authority = result[2] || null;
	    this.path      = result[3] || null;
	    this.query     = result[4] || null;
	    this.fragment  = result[5] || null;
		
		this.options = Object.extend({
			queryElements: {}
	    }, arguments[1] || { });	
	},
	
	addQueryElement: function(name, el) {
		this.options.queryElements[name] = el;
	},
	
	getQuery: function() {
		var query = this.query || "";
		var params = $H();
		
		$H(this.options.queryElements).each(function(pair) {
			params.set(pair.key, $F(pair.value));
		});
		
		return query + '&' + params.toQueryString();
	},
	
	toString: function() {
		var str = "";
		var query = this.getQuery();
		
	    this.scheme 	&& (str += this.scheme + ":");
	    this.authority	&& (str += "//" + this.authority);
	    this.path		&& (str += this.path);
	    query			&& (str += "?" + query);
	    this.fragment	&& (str += "#" + this.fragment);
	    return str;
	}
});

NEO.Ajax = {};

NEO.Ajax.Select = Class.create({}, {
	initialize: function(name, url) {
		this.input			= $(name);
		this.choices 		= $(name + '_choices');
		this.loader 		= $(name + '_loader');
		this.url			= new NEO.URI(url);
		
		this.parentValues 	= $H();
		
		this.options = Object.extend({
			belongsTo: {},
			deferLoad: false,
			allowOther: false,
			otherKey: 'OTHER',
			otherValue: _MESSAGES.SELECT_OTHER
	    }, arguments[2] || { });
		
		var o = this;
		
		$H(this.options.belongsTo).each(function(pair) {
			o.url.addQueryElement(pair.key, pair.value);
			
			$(pair.value).observe('change', o.checkParent.bindAsEventListener(o, pair.key));
			$(pair.value).observe('neo:change', o.checkParent.bindAsEventListener(o, pair.key));
			$(pair.value).observe('neo:load', o.checkParent.bindAsEventListener(o, pair.key));
		});

		this.choices.observe('change', this.choicesListener.bindAsEventListener(this));
		
		this.checkChoice();
		
		if (!this.options.deferLoad)
			this.load();
	},
	
	load: function(){
		this.update()
	},
	
	checkParent: function(e, key) {
		var value 	= $F(e.element());
		var old 	= this.parentValues.get(key);
		
		if (old != value) {
			if (old != undefined && this.options.allowOther)
				this.input.value = '';
			
			this.parentValues.set(key, value);
			this.load();
		}
	},
	
	update: function() {
		this.choices.hide();
		this.loader.show();
		var o = this;		
		new Ajax.Request(this.url.toString(), { onSuccess: o.build.bindAsEventListener(o) });
	},
	
	build: function(t) {
		var o = this.choices;
		o.update('');
		
		var rs = t.responseText.evalJSON();
		
		if (rs.length != undefined)
			rs.each(function(val) { o.options.add(new Option(val, val)); });
		else
			$H(rs).each(function(pair) { o.options.add(new Option(pair.value, pair.key)); });
			
		if (this.options.allowOther)
			o.options.add(new Option(this.options.otherValue, this.options.otherKey));
		
		this.checkChoice();
		
		this.loader.hide();
		this.choices.show();		
		this.choices.fire('neo:load');
	},
	
	checkChoice: function() {
		var value 	= $F(this.input);
		var old		= $F(this.choices);
		
		this.choices.value = value;
		
		if ($F(this.choices) != value) {
			if (value && this.options.allowOther)
				this.choices.value = this.options.otherKey;
			else if (this.choices.options.length > 0) {
				this.choices.selectedIndex = 0;
				this.input.value = $F(this.choices);
			} 				
		}
		
		if (this.options.allowOther && $F(this.choices) == this.options.otherKey) {
			if ($F(this.input) == this.options.otherKey)
				this.input.value = '';
				
			this.input.show();
		}
		else
			this.input.hide();
			
		if (old != $F(this.choices))
			this.choices.fire('neo:change');	
	},
	
	choicesListener: function() {
		this.input.value = $F(this.choices);
		this.checkChoice();
	}
});


