/*
minikit :: widget
a bag of javascript tricks, transparently compatible with mochikit.
json by dojo, Academic Free License version 2.1 or above OR the modified BSD license.
cookies by http://www.quirksmode.org/js/cookies.html
*/
if (typeof(minikit) == "undefined") {
	throw new Error("minikit.widget depends on minikit");
}
if (typeof(minikit.widget) == "undefined") {
	minikit.widget = {};
}
/*
global exports. this is the public html-hackers interface.
*/
var __EXPORT__ = function(self) {
	/** table [, height] */
	self.scrollTable = minikit.scrollTable;

	/** el, args [, options] */
	self.contextMessage = minikit.contextMessage;

	/** el, args [, options] */
	self.datePicker = minikit.datePicker;

	/** el, args [, options] */
	self.permissions = minikit.permissions;

	/** el, values [, options] */
	self.comboBox = minikit.comboBox;
}

minikit.json = {
	__m : {
		'\b': '\\b',
		'\t': '\\t',
		'\n': '\\n',
		'\f': '\\f',
		'\r': '\\r',
		'"' : '\\"',
		'\\': '\\\\'
	},

	unserialize: function(/* jsonString */ json) {
		// FIXME: should this accept mozilla's optional second arg?
		try {
			return eval("(" + json + ")");
		} catch (ex) {
			return null;
		}
	},

	serialize: function(x) {
		if (x instanceof Array) {
			return minikit.json.array(x);
		}
		f = minikit.json[typeof(x)];
		if (f) {
			return f(x);
		}
		return 'null';
	},

	'array': function(x) {
		var a = ['['], b, f, i, l = x.length, v;
		for (i = 0; i < l; i += 1) {
		    v = x[i];
		    f = minikit.json[typeof(v)];
		    if (f) {
			v = f(v);
			if (typeof(v) == 'string') {
			    if (b) {
				a[a.length] = ',';
			    }
			    a[a.length] = v;
			    b = true;
			}
		    }
		}
		a[a.length] = ']';
		return a.join('');
	},

	'object': function(x) {
		if (x) {
			if (x instanceof Array) {
				return minikit.json.array(x);
			}
			var a = ['{'], b, f, i, v;
			for (i in x) {
				v = x[i];
				f = minikit.json[typeof(v)];
				if (f) {
					v = f(v);
					if (typeof(v) == 'string') {
						if (b) {
							a[a.length] = ',';
						}
						a.push(minikit.json.string(i), ':', v);
						b = true;
					}
				}
			}
			a[a.length] = '}';
			return a.join('');
		}
		return 'null';
	},

	'boolean': function(x) {
		return String(x);
	},

	'null': function(x) {
		return "null";
	},

	'number': function(x) {
		return isFinite(x) ? String(x) : 'null';
	},

	'string': function(x) {
		if (/["\\\x00-\x1f]/.test(x)) {
			x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
				var c = minikit.json.__m[b];
				if (c) {
					return c;
				}
				c = b.charCodeAt();
				return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
			});
		}
		return '"' + x + '"';
	}

}

/**
  * A namespace for cookies
  */
minikit.Cookie = function(name, serializer /* optional */) {
	this.serializer = serializer || minikit.json;
	this.name = name;
	this._data = this.serializer.unserialize(minikit.cookies.get(this.name));
	if (this._data == null) {
		this._data = {};
	}
}
minikit.Cookie.prototype.get = function(key) {
	if (typeof(this._data[key]) == "undefined") {
		return null;
	}
	return this._data[key];
}
minikit.Cookie.prototype.set = function(key, value) {
	this._data[key] = value;
	minikit.cookies.set(this.name, this.serializer.serialize(this._data));
}

/**
  * Abstract baseclass for widgets
  */
minikit.widget.Base = function(args) {
	this.view = {};
	this._signalCache = [];
}
/**
  * Attach the controller to a HTMLElement in the DOM.
  */
minikit.widget.Base.prototype.attach = function(element) {
	throw new Error("minikit.widget.Base.prototype.attach is abstract");
}
/**
  * Remove the widget from the DOM.
  */
minikit.widget.Base.prototype.detach = function() {
	for (var i = 0, l = this._signalCache.length; i < l; ++i) {
		try {
			disconnect(this._signalCache[i]);
		} catch (ex) { /* squelch */ }
	}
	delete(this._signalCache);
}
/**
  * Attaches an event. Use this method to ensure cleanup through detach
  */
minikit.widget.Base.prototype.connect = function(src, sig, slot) {
	this._signalCache.push(connect(src, sig, slot));
}

/**
  * Copyright (c) 2004,2005,2006 Troels Knak-Nielsen
  *
  * License: public domain
  *
  * Combobox widget
  */
minikit.widget.ComboBox = function(values, options) {
	this.superconstructor.apply(this, arguments);
	this.values = values || [];
	// would be real nice to have a way to figure this out
	this.buttonWidth = 19;
	if (options && options.buttonWidth) {
		this.buttonWidth = options.buttonWidth;
	}
}
minikit.extend(minikit.widget.ComboBox, minikit.widget.Base);

minikit.comboBox = function(el, values, options) {
	var f = function() {
		var widget = new minikit.widget.ComboBox(values, options);
		widget.attach($(el));
	}
	if (options && options.delay) {
		callLater(1, f);
	} else {
		f();
	}
}

minikit.widget.ComboBox.prototype.attach = function(elm) {
	this.view = {};
	this.view.textfield = elm;
	elm.setAttribute("autocomplete", "off");

	this.connect(elm, "onkeyup", bind("completeTyping", this));
	this.connect(elm, "onkeydown", bind("txtKeyDown", this));
	elm.style.marginRight = (this.buttonWidth + 1) + "px";

	var select = createDOM("select");
	this.view.select = select;
	this.connect(select, "onchange", bind("takeValueFromPopup", this));
	select.tabIndex = -1;
	select.style.visibility = "hidden";
	select.style.position = "absolute";
	forEach(this.values,
		function(value) {
			var option = createDOM("option");
			option.value = value;
			option.appendChild(document.createTextNode(value));
			select.appendChild(option);
		}
	);
	elm.parentNode.appendChild(select);
	this.takeValueFromTextfield();

	select.style.width = (minikit.getElementDimensions(elm).w + this.buttonWidth) + "px";
	var dims = minikit.getElementDimensions(select);
	select.style.clip = 'rect(0px ' + dims.w + 'px ' + dims.h + 'px ' + (dims.w - this.buttonWidth) + 'px)';
	select.style.visibility = 'visible';
	this.positionSelect();

}

minikit.widget.ComboBox.prototype.detach = function() {
	this.supertype.detach.apply(this, arguments);
	this.view.select.parentNode.removeChild(this.view.select);
}

minikit.widget.ComboBox.prototype.positionSelect = function() {
	var s = this.view.select;

	var dims = minikit.getElementDimensions(this.view.select);
	var dimt = minikit.getElementDimensions(this.view.textfield);
	var post = minikit.getElementPosition(this.view.textfield);

	s.style.top = post.y + "px";
	s.style.left = ((post.x + dimt.w) - (dims.w - this.buttonWidth) - 1) + "px";

	callLater(1, bind("positionSelect", this));
}

minikit.widget.ComboBox.prototype.takeValueFromPopup = function() {
	this.view.textfield.value = this.view.select.value;

	// Matt's mod ***************************************************** //
	// We limit albums to 30 chars, so only a hash would reach 32
	if (this.view.textfield.name.length == 32) // if it's named a hash, do the ajax update
		update(this.view.textfield.name,this.view.select,'album');
	// **************************************************************** //
}

minikit.widget.ComboBox.prototype.takeValueFromTextfield = function() {
	var t = this.view.textfield;
	var s = this.view.select;
	for (var idx=0; idx < s.options.length; idx++) {
		if (s.options[idx].text == t.value) {
			s.selectedIndex = idx;
			return;
		}
	}
	s.selectedIndex=-1;
}

minikit.widget.ComboBox.prototype.completeTyping = function(e) {
	var code = e.key().code;
	//window.status="key = "+code;
	if (code < 0x2f && code != 32) {
		return;
	}
	var t = this.view.textfield;
	var s = this.view.select;

	var text = t.value;
	var options = s.options;
	var i;
	var utext = text.toUpperCase();
	for (i=0;i<options.length;i++) {
		var newtxt = options[i].text;
		var uopt = newtxt.toUpperCase();
		if (uopt != utext && 0 == uopt.indexOf(utext)) {
			t.value = text + newtxt.substr(text.length);
			if (document.selection && document.selection.createRange) { // ie
				var txtrange = t.createTextRange();
				txtrange.moveStart("character", text.length);
				txtrange.select();
			} else {
				t.selectionStart = text.length;
				t.selectionEnd = newtxt.length;
			}
			this.takeValueFromTextfield();
			break;
		}
	}
}

minikit.widget.ComboBox.prototype.txtKeyDown = function(e) {
	var code = e.key().code;
	// Down Arrow
	if (code == 40) {
		var s = this.view.select;
		if (s.selectedIndex < s.options.length-1) {
			s.selectedIndex += 1;
		}
		this.takeValueFromPopup();
	}
	// Up Arrow
	if (code == 38) {
		var s = this.view.select;
		if (s.selectedIndex > 0) {
			s.selectedIndex -= 1;
		} else if (s.selectedIndex == -1) {
			s.selectedIndex = s.options.length-1;
		}
		this.takeValueFromPopup();
	}
}

__EXPORT__(window);