var DDRegister=function() {
	var inputs=$$('select.DropDown');
	for(i=0; i<inputs.length; ++i) {
		new DropDown(inputs[i]);
	}
};

// params is a structure with the following keys:
// *id - string with unique id of the menu
// *ULbody - id or HTML node of the UL element which contains menu options
// src - url to Effi DataList method which returns list of menu options
// onSelect(index, isSelected) - callback function to be invoked when menu
//		item is (un)selected. Integer index is menu item index,
//		Boolean isSelected - specifies whether menu item is selected or unselected
// onClose() - callback function to be invoked before menu hiding
// value - array of selected items. The same as in SetValue params
var ContextMenu = Class.create({
initialize: function(params) {
	this.id=params.id;
	this.optionUL=$(params.ULbody);
	this.items = new Array();
	this.selected = params.onSelect;
	this.closed = params.onClose;

	this.liMouseOverCallback=this.onLIMouseOver.bind(this);
	this.ulMouseOutCallback=this.onULMouseOut.bind(this);
	this.ulMouseUpCallback=this.onULMouseUp.bind(this);
	this.ulMouseDownCallback=this.onULMouseDown.bind(this);
	this.keyDownCallback=this.onKeyDown.bind(this);
	this.stopEventCallback=(function(evt){evt.stop();});

	if(params.src) {
		var thisobj = this;
		new ServerCall(params.src, undefined, {
			onSuccess: this.setupDynamicLI,
			onException: function(){
				thisobj.setWidth(40);
				thisobj.element.setStyle({"visibility": "inherit"});
			},
			thisObject: this
		});
	}
	else {
		this.setupStaticLI();
	}
	if(params.value instanceof Array) this.SetValue(params.value);

	this.optionUL.observe('mousedown', this.ulMouseDownCallback);
	this.optionUL.observe('mouseup', this.ulMouseUpCallback);
	this.optionUL.observe('contextmenu', this.stopEventCallback);
	this.optionUL.observe('mouseout', this.ulMouseOutCallback);
	BindKeyDown(this.optionUL, this.keyDownCallback);
},
Show: function(x, y) {
// (x, y) is absolute viewport coordinates of left-top point of the UL
	var bSetPos=false;
	var positionedParent=null;
	if(typeof(x)!='undefined' && typeof(y)!='undefined' && x!==null && y!==null) {
		positionedParent=this.optionUL.getOffsetParent();
		var pvo=positionedParent.viewportOffset();
		y-=pvo.top;
		x-=pvo.left;
		this.optionUL.setStyle({position: 'absolute', visibility: 'hidden', left: '-1000px', top: '-1000px'});
		bSetPos=true;
	}
	this.optionUL.setStyle({display: '', visibility: '', position: 'absolute', display: 'block'});
	if(Prototype.Browser.IE && !this.rendered) {
		var objWidth=this.optionUL.offsetWidth-30;
		for(var i=0; i<this.items.length; ++i) {
			this.items[i].setStyle({width: objWidth});
		}
		this.rendered=true;
	}
	if (bSetPos) {
		var dx=positionedParent.offsetWidth-(x+this.optionUL.offsetWidth);
		if (dx<0) x+=dx; // horizontal correction
		this.optionUL.setStyle({left: x+'px', top: y+'px'});
	}
	this.optionUL.tabIndex=1;
	this.optionUL.focus();
},
Hide: function() {
	this.optionUL.setStyle({display: 'none'});
},

setupDynamicLI: function(oPacket) {
	var data = oPacket.Data();
	if (!data.length > 0) return;
	var header = data[0];
	var key = this.optionUL.readAttribute('key-column');
	if(!key) key = this.optionUL.readAttribute('key');
	var show = this.optionUL.readAttribute('show');
	var keyIdx = 0;
	var showIdx = 1;
	for(var c = 0; c < header.length; ++c) {
		if (header[c] == key) keyIdx = c;
		if (header[c] == show) showIdx = c;
	}

	this.optionUL.update();
	this.items.length = 0;
	for(var i = 1; i < data.length; ++i) {
//		var li = new Element("li").update(data[i][showIdx]);
//		li.appendChild(new Element('span', {class: 'ContextMenuStatus'}));

		var li=new Element('li').update('<span class="ContextMenuStatus"> </span>'+data[i][showIdx]);
		this.items.push(li);
		this.optionUL.appendChild(li);
		li.writeAttribute( 'value', String(data[i][keyIdx].Value()) );
		li.writeAttribute('index', i - 1);
		li.observe('mouseover', this.liMouseOverCallback);
	}
},

setupStaticLI: function() {
	var thisobj = this;
	$A(this.optionUL.childNodes).each(function(element){
		if (element.nodeName.toLowerCase() != "li") return;
		element = $(element);
		var myIndex = thisobj.items.length;
		thisobj.items.push(element);
		element.writeAttribute('index', myIndex);
		element.observe('mouseover', thisobj.liMouseOverCallback);
	});
},
onKeyDown: function(evt) {
	var key=$(evt).which || evt.keyCode;
	var index=this.highlightIndex;
	if(key==38) { // up arrow
		if(index>0) --index;
		else index=this.items.length-1;
		this.highlight(index);
	}
	else if(key==40) { // down arrow
		if(index<this.items.length-1) ++index;
		else index=0;
		this.highlight(index);
	}
	else if(key==32) { // space
		this.selectItem(index);
	}
	else if(key==13) { // enter
		this.selectItem(index);
		if(!evt.ctrlKey) {
			if(this.closed) this.closed();
			this.Hide();
		}
	}
	else if(key==27) { // escape
		if(this.closed) this.closed();
		this.Hide();
	}
	else return;
	evt.stop();
},
onULMouseDown: function(event) {
	event.stop();
},
onULMouseUp: function(event) {
	var li=Event.element(event);
	if(li.nodeName.toLowerCase() != "li") li=li.up('li');
	if(li==undefined) return;
	this.selectItem(parseInt(li.readAttribute('index')));

	if(!(event.ctrlKey || event.isRightClick())) {
		if(this.closed) this.closed();
		this.Hide();
	}
},
selectItem: function(index) {
	if(!(index>=0 && index<this.items.length)) return;
	var li=this.items[index];

	if(li.hasClassName('Selected')) {
		li.removeClassName('Selected');
		if(this.selected) this.selected(index, false);
	}
	else {
		li.addClassName('Selected');
		if(this.selected) this.selected(index, true);
	}
},
onLIMouseOver: function(event) {
	var element = Event.element(event);
	if(element.nodeName.toLowerCase() != "li") return;
	this.highlight(parseInt(element.readAttribute("index")));
},
onULMouseOut: function(event) {
	if(Event.element(event).up('ul')==this.optionUL) return;
	this.highlight();
},
highlight: function(index) {
	if(this.highlightIndex!=undefined && this.highlightIndex != index) {
		this.items[this.highlightIndex].removeClassName('Active');
		this.highlightIndex=undefined;
	}
	if (!this.items[index]) return;
	this.items[index].addClassName('Active');
	this.highlightIndex = index;
},
SetValue: function(value) {
	if(!(value instanceof Array)) return;
	for(var vi=0; vi<value.length; ++vi) {
		for(var li=0; li<this.items.length; ++li) {
			if(value[vi]==this.items[li].readAttribute('value')) {
				this.items[li].addClassName('Selected');
			}
		}
	}
},
Value: function() {
	var res=[];
	var index=0;
	for(var i=0; i<this.items.length; ++i) {
		if(!this.items[i].hasClassName('Selected')) continue;
		res[index]=this.items[i].readAttribute('value');
		++index;
	}
	return res;
},
ID: function(){ return this.id; }
});

var MenuButton = Class.create({
initialize: function(element) {
	this.element = $(element);
	this.optionUL = $(element+"_UL");
	this.element.JSControl = this;
	this.ID_ = this.element.readAttribute('id');
	this.alignTo=this.optionUL.getAttribute('align-to');
	this.shiftX=parseInt(this.optionUL.getAttribute('shift-x'), 10);
	this.shiftY=parseInt(this.optionUL.getAttribute('shift-y'), 10);

	this.buttonMouseDownCallback=this.OnButtonMouseDown.bind(this);
	this.documentMouseDownCallback=this.OnDocumentMouseDown.bind(this);

	this.menuObj=new ContextMenu({
		id: this.ID(),
		ULbody: this.optionUL,
		onSelect: this.OnChange.bind(this),
		onClose: undefined,
		src: this.optionUL.readAttribute('src')
	});

	this.element.observe('mousedown', this.buttonMouseDownCallback);
},
OnButtonMouseDown: function(event) {
	var element = Event.element(event);
	if (this.alignTo=='bottom') {
		var y=getAbsoluteOffset(this.element, "offsetTop")+this.element.offsetHeight;
		if (!isNaN(this.shiftY)) y+=this.shiftY;
		var x=getAbsoluteOffset(this.element, "offsetLeft");
		if (!isNaN(this.shiftX)) x+=this.shiftX;
		this.menuObj.Show(x, y);
	} else {
		this.menuObj.Show(event.pointerX(), event.pointerY());
	}
	event.stop();
	Event.observe(document, "mousedown", this.documentMouseDownCallback);
},
OnDocumentMouseDown: function(event) {
	this.menuObj.Hide();
	Event.stopObserving(document, "mousedown", this.documentMouseDownCallback);
},
OnChange: function(evt) {
	new AEvent("CHANGE", {}, this);
	new AEvent("CLICK", {}, this);
},
SetValue: function(value) {
	this.menuObj.SetValue(value);
},
Value: function() {
	return this.menuObj.Value();
},
ID: function() { return this.ID_; }
});

var MultiSelect = Class.create({
initialize: function(element) {
	this.element = $(element);
	this.optionUL = this.element.down("ul");
	this.element.JSControl = this;
	this.ID_ = this.element.readAttribute('id');
	this.items = new Array();

	this.onMouseDownCallback=this.OnMouseDown.bind(this);
	this.onMouseOverCallback=this.OnMouseOver.bind(this);
	this.onDragFinishCallback=this.OnDragFinish.bind(this);
	this.onMouseMoveCallback=this.OnMouseMove.bind(this);
	this.onFocusCallback=this.OnFocus.bind(this);
	this.onBlurCallback=this.OnBlur.bind(this);
	this.onKeyDownCallback=this.OnKeyDown.bind(this);
	this.stopEventCallback=(function(evt){evt.stop();});

	this.visibility=this.optionUL.readAttribute('visibility');
	if(!this.visibility) this.visibility='yes';
	var src=this.optionUL.readAttribute('src');
	if(src) {
		var thisobj=this;
		new ServerCall(src, undefined, {
			onSuccess: this.SetupDynamicLI,
			onException: function() {
				thisobj.element.setStyle({visibility: 'inherit'});
			},
			thisObject: this
		});
	}
	else {
		this.SetupStaticLI();
	}
},
enable: function() {
	this.optionUL.observe('focus', this.onFocusCallback);
	this.optionUL.observe('blur', this.onBlurCallback);
	BindKeyDown(this.optionUL, this.onKeyDownCallback);
	this.optionUL.observe('contextmenu', this.stopEventCallback);
	this.optionUL.observe('selectstart', this.stopEventCallback);

	for(var i=0; i<this.items.length; ++i) {
		this.items[i].observe('mousedown', this.onMouseDownCallback);
	}
},
disable: function() {
	this.optionUL.stopObserving('focus', this.onFocusCallback);
	this.optionUL.stopObserving('blur', this.onBlurCallback);
	UnbindKeyDown(this.optionUL, this.onKeyDownCallback);
	this.optionUL.stopObserving('contextmenu', this.stopEventCallback);
	this.optionUL.stopObserving('selectstart', this.stopEventCallback);

	for(var i=0; i<this.items.length; ++i) {
		this.items[i].stopObserving('mousedown', this.onMouseDownCallback);
	}
},
SetupDynamicLI: function(oPacket) {
	var data = oPacket.Data();
	if (!data.length > 0) return;
	var header = data[0];
	var key = this.element.readAttribute('key-column');
	if(!key) key = this.element.readAttribute('key');
	var show = this.element.readAttribute('show');
	var keyIdx = 0;
	var showIdx = 1;
	for(var c = 0; c < header.length; ++c) {
		if (header[c] == key) keyIdx = c;
		if (header[c] == show) showIdx = c;
	}

	this.optionUL.update();
	this.items.length = 0;
	for(var i = 1; i < data.length; ++i) {
		var li = new Element("li").update(data[i][showIdx]);
		this.items.push(li);
		this.optionUL.appendChild(li);
		li.writeAttribute( 'value', String(data[i][keyIdx].Value()) );
		li.writeAttribute('index', i - 1);
	}
	var objWidth=this.optionUL.offsetWidth;
	for(var i=0; i<this.items.length; ++i) {
		this.items[i].setStyle({width: objWidth});
	}

	this.lastFocusElement=this.items[0];
	if(this.visibility=='yes') this.enable();
},
SetupStaticLI: function() {
	var thisobj = this;
	var objWidth=this.optionUL.offsetWidth;
	$A(this.optionUL.childNodes).each(function(element){
		if (element.nodeName.toLowerCase() != "li") return;
		element = $(element);
		var myIndex = thisobj.items.length;
		thisobj.items.push(element);
		element.setStyle({width: objWidth});
		element.writeAttribute('index', myIndex);
//		element.observe('mousedown', thisobj.onMouseDownCallback);
	});
	this.lastFocusElement=this.items[0];
	if(this.visibility=='yes') this.enable();
},
OnKeyDown: function(evt) {
	var key=$(evt).which || evt.keyCode;
	if(!this.lastFocusElement) this.lastFocusElement=this.items[0];
	var index=parseInt(this.lastFocusElement.readAttribute("index"));
	if(key==38) { // up arrow
		if(index>0) --index;
		this.lastFocusElement.removeClassName('Active');
		if(evt.shiftKey) this.lastFocusElement.addClassName('Selected');
		this.items[index].addClassName('Active');
		this.lastFocusElement=this.items[index];
		if(this.lastFocusElement.offsetTop-this.lastFocusElement.clientTop<this.optionUL.scrollTop) {
			this.optionUL.scrollTop=this.lastFocusElement.offsetTop-this.lastFocusElement.clientTop;
		}
		if(evt.shiftKey) this.lastFocusElement.addClassName('Selected');
	}
	else if(key==40) { // down arrow
		if(index<this.optionUL.childNodes.length-1) ++index;
		this.lastFocusElement.removeClassName('Active');
		if(evt.shiftKey) this.lastFocusElement.addClassName('Selected');
		this.items[index].addClassName('Active');
		this.lastFocusElement=this.items[index];
		if( this.lastFocusElement.offsetTop+this.lastFocusElement.offsetHeight+this.lastFocusElement.clientTop>
		    this.optionUL.scrollTop+this.optionUL.offsetHeight ) {
			this.optionUL.scrollTop=this.lastFocusElement.offsetTop+this.lastFocusElement.offsetHeight+this.lastFocusElement.clientTop-this.optionUL.offsetHeight;
		}
		if(evt.shiftKey) this.lastFocusElement.addClassName('Selected');
	}
	else if(key==32) { // space
		if(this.lastFocusElement.hasClassName('Selected')) {
			this.lastFocusElement.removeClassName('Selected');
		}
		else this.lastFocusElement.addClassName('Selected');
	}
	else if(key==13) { // enter
		for(var i=0; i<this.items.length; ++i) {
			var item=this.items[i];
			if(item!==this.lastFocusElement) item.removeClassName('Selected');
		}
		this.lastFocusElement.addClassName('Selected');
	}
	else return;
	evt.stop();
},
OnFocus: function(event) {
	if(this.lastFocusElement==undefined) this.lastFocusElement=this.items[0];
	this.lastFocusElement.addClassName('Active');
},
OnBlur: function(event) {
	if(this.lastFocusElement) this.lastFocusElement.removeClassName('Active');
},
OnMouseDown: function(event) {
//LogL("OnMouseDown");
	var element = Event.element(event);

	var eleIdx;;
	var lastIdx;
	if(event.shiftKey) {
		eleIdx=parseInt(element.readAttribute("index"));
		lastIdx=parseInt(this.lastFocusElement.readAttribute("index"));
	}

	var ctrl=(event.ctrlKey || event.isRightClick());
	for(var i=0; i<this.items.length; ++i) {
		var item=this.items[i];
		item.observe('mouseover', this.onMouseOverCallback);
		item.removeClassName('Active');
		if(element===item) {
			if(ctrl) {
				if(item.hasClassName('Selected')) item.removeClassName('Selected');
				else item.addClassName('Selected');
			}
			else item.addClassName('Selected');
		}
		else if(event.shiftKey) {
			if((i>=eleIdx && i<=lastIdx) ||
			   (i<=eleIdx && i>=lastIdx)) {
				item.addClassName('Selected');
			}
		}
		else if(!ctrl) item.removeClassName('Selected');
	}
	$(document).observe('mouseup', this.onDragFinishCallback);
	$(document).observe('mousemove', this.onMouseMoveCallback);

	element.addClassName('Active');
	this.lastFocusElement=element;
	this.optionUL.focus();
	event.stop();
},
OnMouseOver: function(event) {
	var element = Event.element(event);
	var index = parseInt(element.readAttribute("index"));
//LogL("OnMouseOver "+index);
	if (!this.items[index]) return;
	if(this.items[index].hasClassName('Selected') && !event.ctrlKey &&
	   this.lastFocusElement!==this.items[index]) {
		this.items[index].removeClassName('Selected');
	}
	else {
		this.items[index].addClassName('Selected');
//		this.lastFocusElement=this.items[index];
	}
},
OnMouseMove: function(event) {
	var eleTop=getAbsoluteOffset(this.element, "offsetTop")-getAbsoluteOffset(this.element, "scrollTop");
	var eleBottom=eleTop+this.element.offsetHeight;
	var mouseY=event.pointerY();
	if(mouseY>eleBottom) this.StartScroll(mouseY-eleBottom);
	else if(mouseY<eleTop) this.StartScroll(mouseY-eleTop);
	else this.ScrollDelta=0;
},
StartScroll: function(delta) {
	this.ScrollDelta=delta;
	if(this.scroller==undefined) this.scroller=new PeriodicalExecuter(this.ScrollStep.bind(this), .05);
},
ScrollStep: function() {
	//LogL("Scroll "+this.ScrollDelta);

	for(var i=0; i<this.items.length; ++i) {
		var item=this.items[i];
		if(this.ScrollDelta>0) { // scroll down
			var scrollBottom=this.optionUL.scrollTop+this.optionUL.offsetHeight;
			//LogL("  ScrollBottom="+scrollBottom+", LIBot="+(item.offsetTop+item.offsetHeight));
			if( item.offsetTop+item.offsetHeight>scrollBottom &&
			    item.offsetTop+item.offsetHeight<=scrollBottom+this.ScrollDelta) {
				var index;
				for(index=i; index>=0; --index) {
					if(this.items[index].hasClassName('Selected')) break;
					this.items[index].addClassName('Selected');
				}
				index=parseInt(this.lastFocusElement.readAttribute("index"));
				for(--index; index >=0; --index) {
					if(!this.items[index].hasClassName('Selected')) break;
					this.items[index].removeClassName('Selected');
				}
			}
		}
		else if(this.ScrollDelta<0) { // scroll up
			if( item.offsetTop<this.optionUL.scrollTop &&
			    item.offsetTop>=this.optionUL.scrollTop+this.ScrollDelta) {
				var index;
				for(index=i; index<this.items.length; ++index) {
					if(this.items[index].hasClassName('Selected')) break;
					this.items[index].addClassName('Selected');
				}
				index=parseInt(this.lastFocusElement.readAttribute("index"));
				for(++index; index<this.items.length; ++index) {
					if(!this.items[index].hasClassName('Selected')) break;
					this.items[index].removeClassName('Selected');
				}
			}
		}
	}

	this.optionUL.scrollTop+=this.ScrollDelta;
},
OnDragFinish: function(event) {
//LogL("OnDragFinish");
	if(this.scroller!=undefined) {
		this.scroller.stop();
		this.scroller=undefined;
	}
	var thisobj = this;
	$A(this.optionUL.childNodes).each(function(item){
		if (item.nodeName.toLowerCase() != "li") return;
		item.stopObserving('mouseover', thisobj.onMouseOverCallback);
	});
	$(document).stopObserving('mouseup', this.onDragFinishCallback);
	$(document).stopObserving('mousemove', this.onMouseMoveCallback);
	this.OnChange();
},
SetTabOrder: function(nTabBase) {
	this.nTabBase = nTabBase;
	this.optionUL.tabIndex = nTabBase;
	return ++nTabBase;
},
OnChange: function(evt) {
	new AEvent("CHANGE", {}, this);
},
SetValue: function(value) {
	if(!(value instanceof Array)) return;
	for(var li=0; li<this.items.length; ++li) {
		var vi=0;
		for(; vi<value.length; ++vi) {
			if(value[vi]==this.items[li].readAttribute('value')) {
				this.items[li].addClassName('Selected');
				break;
			}
		}
		if(vi==value.length) this.items[li].removeClassName('Selected');
	}
},
Value: function() {
	var res=[];
	var index=0;
	for(var i=0; i<this.items.length; ++i) {
		if(!this.items[i].hasClassName('Selected')) continue;
		res[index]=this.items[i].readAttribute('value');
		++index;
	}
	return res;
},
SetAttribute: function(sName, sValue) {
	switch(sName){
		case "visibility":
			switch(sValue){
				case "yes":
					Element.setStyle(this.element, {"display": ""});
					this.enable();
					break;
				case "ro":
				case "vo":
					Element.setStyle(this.element, {"display": ""});
					this.disable();
					break;
				case "no":
					Element.setStyle(this.element, {"display": "none"});
					break;
			}
			break;
		case "style": return;
	}
	this.optionUL.writeAttribute(sName, sValue);
},

ID: function() { return this.ID_; }
});



var DropDown = Class.create(ItemsListAligned, {
	initialize: function($super, element){
		this.element = $(element);
		if (!this.element || this.element.JSControl) return;
		this.element.JSControl = this;
		this.ID_ = element;
		this.localId = $(element).readAttribute('localid');

		this.keyType = this.element.readAttribute("key-type");
		if (!this.keyType) this.keyType = 'string';
// 		this.maxWidth = this.element.hasAttribute("max-width") ?
// 			parseInt(Element.readAttribute(this.element, "max-width")) : Number.MAX_VALUE;
		if (this.element.hasAttribute("max-width")){
			var maxwidth = String(this.element.getAttribute("max-width") || "");
			if (!["em", "ex", "px", "in", "cm", "mm", "pt", "pc"].collect(maxwidth.endsWith, maxwidth).any()) maxwidth += "px";
			Element.setStyle(this.element, {"maxWidth": maxwidth});
		}
		this.width=this.element.readAttribute("width");

		$super($(element+"_LIST"), this.element);
		// following tricky way of finding elements is needed for Query JS control support
		this.fillList=this.element.down('[id="'+element+'_FILL"]');
		this.button = this.element.down('[id="'+element+'_BUTTON"]');
		if (!this.button) return alert("DropDown: button not found");
		this.valueContainer=this.element.down('[id="'+element+'_VALUE"]');
		if (!this.valueContainer){
			this.valueContainer = new Element("span", {"class": "ValueContainer"}).update(" ");
			this.element.insertBefore(this.valueContainer, this.button);
		}

		this.bindEventListeners();

		var src = Element.readAttribute(this.element, "src");
		if (src){
			new ServerCall(src, undefined, {
				onSuccess: function(apacket){
					this.SetupDynamicLI(apacket);
					this.makeVisible();
					this.prevValue=this.getValue();
					new AEvent("WM_INIT", {}, this);
				}.bind(this),
				onException: function(){
// 					alert("onException")
					this.makeVisible();
				}.bind(this),
				thisObject: this
			});
		}else{
			this.SetupStaticLI();
			this.makeVisible();
			this.prevValue=this.getValue();
			new AEvent("WM_INIT", {}, this);
		}
	},

	initialized: false,

	makeVisible: function(){
		Element.setStyle(this.element, {"visibility": ""});
	},

	bindEventListeners: function(){
		Event.observe(this.element, "mousedown", function(){
			this.element.focus();
			Element.scrollContainerTo(this.list, this.highlightedItem);
			this.toggleOpen();
		}.bind(this));
		Event.observe(this.list, ItemsList.events["choice"], function(event){
			this.element.focus();
			this.setValueFromHighlightedAndCallOnchange();
			this.setClosed();
		}.bind(this));
		this.OnKeyDownCallback = this.OnKeyDown.bind(this);
		this.OnKeyPressCallback = this.OnKeyPress.bind(this);
		Event.observe(this.element, "keydown", this.OnKeyDownCallback);
		Event.observe(this.element, "keypress", this.OnKeyPressCallback);
		Event.observe(this.element, "focus", this.elementFocus.bind(this));
		Event.observe(this.element, "blur", this.elementBlur.bind(this));
	},

 unbindEventListeners: function(){
		Event.stopObserving(this.element, "mousedown");
		Event.stopObserving(this.element, "click");
		Event.stopObserving(this.element, "keypress");
		Event.stopObserving(this.element, "keydown");
		Event.stopObserving(this.element, "focus");
		Event.stopObserving(this.element, "blur");
	},

	elementFocus: function(){
		Element.addClassName(this.element, "Focus");
		return false;
	},

	elementBlur: function(){
		Element.removeClassName(this.element, "Focus");
		if(this.kbStr) this.kbStr="";

		var val=this.getValue();
		this.repaintSelected(this.GetItems().find(function(li){
			return Element.readAttribute(li, "itemVal") == val; }), true);

		this.OnChange();
	},

	SetupDynamicLI: function(oPacket) {
		if (this.initialized) return;
		this.CreateDynamicLI(oPacket);
		this.initialized = true;
	},

	ResetDynamicLI: function(oPacket) {
		this.CreateDynamicLI(oPacket);
		this.initialized = true;
		this.OnChange();
	},

	AppendItem: function($super, li){
		$super(li);
		this.fillList.appendChild(li.cloneNode(true));
	},

	ClearList: function($super){
		$super();
		Element.clear(this.fillList);
	},

	CreateDynamicLI: function(oPacket){
		var data = oPacket.Data();
		if (!data.length > 0) return;
		var header = data[0];
		var key = Element.readAttribute(this.element, 'key-column');
		if(!key) key = Element.readAttribute(this.element, 'key');
		var show = Element.readAttribute(this.element, 'show');
		var keyIdx = 0;
		var showIdx = 1;
		for (var c = 0; c < header.length; ++c) {
			if (header[c] == key) keyIdx = c;
			if (header[c] == show) showIdx = c;
		}
		var oldValue = this.getValue();
		this.ClearList();
		var defLabel=Element.readAttribute(this.element, 'def-label');
		if(defLabel!=null) {
			var li = new Element("li");
			li.innerHTML = defLabel;
			this.AppendItem(li);
			var defValue=Element.readAttribute(this.element, 'def-value');
			if(defValue==null) Element.writeAttribute(li, "itemVal", "");
			else Element.writeAttribute(li, "itemVal", defValue);
		}
		for (var i = 1; i < data.length; ++i){
			var li = new Element("li");
			li.innerHTML = data[i][showIdx];
			this.AppendItem(li);
			if(data[i][keyIdx]==null) Element.writeAttribute(li, "itemVal", "");
			else Element.writeAttribute(li, "itemVal", String(data[i][keyIdx].Value()));
		}
		this.setValue(oldValue);
		this.updateWidth();
	},

	SetupStaticLI: function(){
		this.initialized = true;
		this.SetHighlighted(this.list.firstDescendant());

		var li=this.list.down("[selected]");
		if(li) this.changeHighlighting(li, true);

		this.setValueFromHighlighted();
		this.updateWidth();
	},

	changeHighlighting: function(element, highlight){
		if (highlight){
			if (!element || this.highlightedItem == element) return;
			if (this.highlightedItem) this.changeHighlighting(this.highlightedItem, false);
			this.highlightedItem = element;
			if (this.highlightedItem){
				Element.addClassName(this.highlightedItem, "Active");
			}
		}else{
			if (!element || this.highlightedItem != element) return;
			if (!this.highlightedItem) return;
			Element.removeClassName(this.highlightedItem, "Active");
			this.highlightedItem = null;
		}
	},

	OnChange: function(){
		if(this.prevValue==this.getValue()) return;
		this.prevValue=this.getValue();
		new AEvent("CHANGE", {}, this);
	},

	OnKeyDown: function(event){
		switch (event.which || event.keyCode){
			case Event.KEY_ESC:
			case Event.KEY_TAB:
				this.setClosed();
				break;
			case Event.KEY_UP:
			case Event.KEY_LEFT:
				this.highlightPrev();
				this.setValueFromHighlightedAndCallOnchange();
				Element.scrollContainerTo(this.list, this.highlightedItem);
				Event.stop(event);
				break;
			case Event.KEY_DOWN:
			case Event.KEY_RIGHT:
				this.highlightNext();
				this.setValueFromHighlightedAndCallOnchange();
				Element.scrollContainerTo(this.list, this.highlightedItem);
				Event.stop(event);
				break;
			case Event.KEY_RETURN:
				this.setClosed();
				this.setValueFromHighlightedAndCallOnchange();
				Event.stop(event);
				break;
			case 32: //space
				Element.scrollContainerTo(this.list, this.highlightedItem);
				this.toggleOpen();
				Event.stop(event);
				return;
				break;
			case Event.KEY_HOME:
			case Event.KEY_PAGEUP:
				this.highlightFirst();
				this.setValueFromHighlightedAndCallOnchange();
				Element.scrollContainerTo(this.list, this.highlightedItem);
				Event.stop(event);
				break;
			case Event.KEY_END:
			case Event.KEY_PAGEDOWN:
				this.highlightLast();
				this.setValueFromHighlightedAndCallOnchange();
				Element.scrollContainerTo(this.list, this.highlightedItem);
				Event.stop(event);
				break;
			case Event.KEY_BACKSPACE:
				this.kbStr=this.kbStr.substr(0, this.kbStr.length-1);
				this.searchKBInput(this.kbStr);
				Event.stop(event);
				return;
			default:
				return;
		}
		if(this.kbStr) this.kbStr="";
		this.repaintSelected(this.GetHighlighted());
	},

	OnKeyPress: function(evt) {
		var key=evt.which || evt.keyCode;
		var charCode=Event.getKeyCode(evt);

		if(this.kbStr==undefined) this.kbStr="";
		var newStr=this.kbStr;
		if(charCode) newStr+=String.fromCharCode(charCode).toUpperCase();
		else return;
		this.searchKBInput(newStr);
		LogL("kb="+this.kbStr);
	},

	searchKBInput: function(newStr) {
		var items=this.GetItems();
		for(var i=0; i<items.length; ++i) {
			var key=Element.readAttribute(items[i], "itemVal");
			var ss=newStr.replace(/([\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}])/g, "\\$1");
			var show="";
			$A(items[i].childNodes).each(function(node){
				if(node.nodeType==Node.TEXT_NODE) show+=node.nodeValue;
			}.bind(this));
			show=show.replace(/(^\s+)/g, "");
//			var show=node.nodeValue;
			if(show.toUpperCase().search(ss)==0) {
				this.kbStr=newStr;
				this.setValue(key);
				Element.scrollContainerTo(this.list, this.highlightedItem);
				return;
			}
		}
	},

	updateWidth: function(){
		if(this.width) {
			this.fillList.setStyle({width: this.width});
		}
		if (Prototype.Browser.Opera) {
			var w=this.fillList.offsetWidth;
			var sp=this.valueContainer.getStyle("paddingLeft");
			var pw=(sp) ? parseInt(sp, 10) : -1;
			this.valueContainer.setStyle({width: w-pw+1});
		}
// 		Element.setStyle(this.list, {"width": "", "minWidth": ""});
// 		var list=document.body.appendChild(this.list.cloneNode(true));
// 		Element.setStyle(this.valueContainer,
// 			{"width": Math.max(Math.min(Element.getWidth(list), this.maxWidth) - Element.getWidth(this.button), 0) + "px"});
// 		document.body.removeChild(list);
	},

	valueDefiningAttributes: ["itemVal"],

	clearValueContainer: function(){
		Element.update(this.valueContainer, "");
		this.valueDefiningAttributes.each(function(attrName){
			Element.writeAttribute(this.valueContainer, attrName, "");
		}.bind(this));
	},

	repaintSelected: function(li) {
		var inner="";
		$A(li.childNodes).each(function(node){
			if(node.nodeType==Node.TEXT_NODE) {
				var show=node.nodeValue;
				if(this.kbStr && show.toUpperCase().search(this.kbStr)==0) {
					show='<font class="Highlight">'+show.substr(0, this.kbStr.length)+'</font>'+show.substr(this.kbStr.length);
				}
				inner+=show;
			}
			else inner+=GetOuterHTML(node);
		}.bind(this));
		this.valueContainer.update(inner);
	},

	copyValueFromItem: function(li){
		this.clearValueContainer();
		if (li){
//			var oldWidth = Element.getStyle(this.valueContainer, "width");
			Element.writeAttribute(this.valueContainer, "style", Element.readAttribute(li, "style"));
			this.updateWidth();
			this.repaintSelected(li);
			this.valueDefiningAttributes.each(function(attrName){
				Element.writeAttribute(this.valueContainer, attrName, Element.readAttribute(li, attrName));
			}.bind(this));
//			if (oldWidth) Element.setStyle(this.valueContainer, {"width": oldWidth});
//			else this.updateWidth();
		}
	},

	setValueFromHighlighted: function(){
		this.copyValueFromItem(this.GetHighlighted());
	},

	setValueFromHighlightedAndCallOnchange: function(){
		this.setValueFromHighlighted();
		this.OnChange();
	},

	SetTabOrder: function(nTabBase) {
		if (this.disabled) {
			this.element.tabIndex = -1;
			return nTabBase;
		}
		this.nTabBase = nTabBase;
		this.element.tabIndex = nTabBase;
		return ++nTabBase;
	},

	clear: function(){
		this.valueContainer.update();
	},

// 	writeValue: function(element){
// 		if (!element) return;
// 		this.clear();
// 		this.valueContainer.writeAttribute("style", element.readAttribute("style"));
// 		var thisobj = this;
// 		$A(element.childNodes).each(function(node){
// 			thisobj.valueContainer.appendChild(node.cloneNode(true));
// 		});
// 		this.setWidth(this.elementSizes.width);
// 	},

	setValue: function(sVal){

		this.valueSet = sVal;

		this.changeHighlighting(this.list.firstDescendant(), true);
		var li=this.list.down('[itemVal="'+sVal+'"]');
		if(li) this.changeHighlighting(li, true);

//		this.highlightFirst();
//		this.changeHighlighting(this.GetItems().find(function(li){
//			return Element.readAttribute(li, "itemVal") == sVal; }), true);

		this.setValueFromHighlighted();
	},

	valueSet: "",

	SetValue: function(newval) {
		if (!this.refreshBound) {
			var win=AControl.GetParentWindow(this.element);
			win.Subscribe("WM_REFRESH", this.OnWMRefresh, this);
			this.refreshBound = true;
		}

		if (!newval) this.setValue("");
		else if (typeof newval == "object" && typeof newval.Selected == "object"){
			this.initialized = true;

			this.ClearList();
			$A(newval.key).each(function(key, iii){
				var li = new Element("li").update(newval.show[iii]);
				Element.writeAttribute(li, "itemVal", String(key));
				this.AppendItem(li);
			}.bind(this));
			this.updateWidth();
			this.setValue(newval.Selected.Value());
			this.makeVisible();
		}
		else this.setValue(newval.Value());
		this.prevValue=this.getValue();
	},

	getValue: function(){
		return this.initialized ? Element.readAttribute(this.valueContainer, "itemVal") : this.valueSet || "";
	},

	Value: function() {
		var v = this.getValue();
		if (this.keyType == "int") return (v ? optional(int(v)) : undefined);
		if (this.keyType == "int64") return (v ? optional(int64(v)) : undefined);
		return optional(this.getValue());
	},
	OnWMRefresh: function(oEvent) {
		var sLocalID = oEvent.Data()['id'];
		if (sLocalID != this.localId) return;
		new ServerCall(this.element.readAttribute('src'), undefined, {
			onSuccess: this.ResetDynamicLI,
			onException: function(){LogE("Failed to load \"" + sValue + "\"");},
			thisObject: this
		});
	},


	SetAttribute: function(sName, sValue) {
		switch(sName){
			case "src":
				if (this.element.readAttribute('src') == sValue) break;
				new ServerCall(sValue, undefined, {
					onSuccess: this.ResetDynamicLI,
					onException: function(){LogE("Failed to load \"" + sValue + "\"");},
					thisObject: this
				});

				break;
			case "disabled":
				if (sValue=='disabled' || sValue=='yes') this.disable();
				break;
			case "visibility":
				Element.setStyle(this.element, {"visibility": sValue == "no" ? "hidden" : ""});
				this[sValue == "yes" ? "enable" : "disable"]();
				Element[["yes", "ro"].include(sValue) ? "removeClassName" : "addClassName"](this.element, "Flexible");
				break;
		}
		this.element.writeAttribute(sName, sValue);
	},

	disable: function(){
		if (this.disabled) return;
		this.element.addClassName("Disabled");
		this.unbindEventListeners();
		this.element.tabIndex = -1;
		this.disabled = true;
	},

	enable: function(){
	 if (!this.disabled) return;
	 this.element.removeClassName("Disabled");
	 this.bindEventListeners()
	 if (typeof(this.nTabBase) != "undefined") this.SetTabOrder(this.nTabBase);
	 this.disabled = false;
	},

ID: function() { return this.ID_; }
});

