/*
 * Autocompletes a symbol based on a partial symbol or name match.
 *
 * Usage:
 * 		var s = new SymbolPicker(inputElementOrId);
 *
 * Note: to avoid dropdown positioning conflicts, the parent input
 * 		element should be wrapped in a positioned container
 * 		(position: relative | absolute)
 */
window.SymbolPicker = Class.create(Ajax.Autocompleter, {

	initialize: function($super, element, url, options) {

		element = $(element);

		var choices = new Element('div', {'class': 'symbolpicker_results', 'style': 'z-index:1000'});
		choices.hide();
		element.parentNode.appendChild(choices);

		options = Object.extend({
			paramName: 'keyword',
			minChars: -1,
			selected: 'selected',
			select: 'symbol',
			text: 'Search',
			tokens: options && options.multiple ? ',' : null,
			onShow:	function(element, update) {
				if(!update.style.position || update.style.position=='absolute') {
					update.style.position = 'absolute';
					Position.clone(element, update, {
						setWidth: false,
						setHeight: false,
						offsetTop: element.offsetHeight
					});
				}
				update.show();
			},
			onHide:	function(element, update) {
				update.hide();
			},
			afterUpdateElement: function(element, selected) {
				if (options && options.onSelect)
					options.onSelect(
						selected.down('.symbol').collectTextNodes(),
						selected.down('.name').collectTextNodes());
			}
		}, options || {});

		this.addHelperText(element, options.text);

		$super(element, choices, url, options);

	},

	addHelperText: function(element, blank) {
		if (!element.value) {
			element.style.color = '#999';
			element.value = blank;
		}
		var highlight = function() {
			if (element.value == blank) {
				element.style.color = '#000';
				setTimeout(function() { element.select(); });
			}
		};
		var blur = function() {
			if (element.value == '' || element.value == blank) {
				element.value = blank;
				element.style.color = '#999';
			}
		};
		element.on('focus', highlight);
		element.on('click', highlight);
		element.on('blur', blur);
		element.on('keydown', function(e) {
			if (e.keyCode == Event.KEY_RETURN)
				if (element.value == blank)
					element.value = '';
		}.bindAsEventListener(this));
		blur();
		$(element.form).on('submit', function(e) {
			if (element.value == blank)
				element.value = '';
		}.bindAsEventListener(this));
	},

	updateChoices: function(data) {
		var ht = function(str) {
			var match = this.getToken();
			if (str.indexOf(match))
				return str.replace(new RegExp('('+match+')', 'i'), '<span class="match">$1</span>');
			return str;
		}.bind(this);
		if (!this.changed && this.hasFocus) {
			this.stopIndicator();
			var suggestions = data.evalJSON(false);
			if (this.update.firstChild)
				this.update.firstChild.remove();
			this.entryCount = suggestions ? suggestions.length : 0;

			var ul = new Element('ul');
			this.update.appendChild(ul);

			if (this.entryCount > 0) {
				for (var i = 0; i < suggestions.length; i++) {
					var li = new Element('li');
					li.insert(new Element('div', {'class': 'symbol'}).update(ht(suggestions[i].symbol)));
					li.insert(new Element('div', {'class': 'name'}).update(ht(suggestions[i].caption)));
					li.insert(new Element('div', {'class': 'type'}).update(ht(suggestions[i].exchange)));
					li.autocompleteIndex = i;
					ul.insert(li);
					this.addObservers(li);
				}
			}

			this.index = 0;

			if(this.entryCount == 1 && this.options.autoSelect) {
				this.selectEntry();
				this.hide();
			} else {
				this.render();
			}

		}
	},

	// Override default mark* methods, scrollIntoView does funny
	// things on most browsers if it's already visible
	markPrevious: function() {
		if(this.index > 0) this.index--;
		else this.index = this.entryCount-1;
		this.makeVisible(this.getEntry(this.index), true);
	},

	markNext: function() {
		if(this.index < this.entryCount-1) this.index++;
		else this.index = 0;
		this.makeVisible(this.getEntry(this.index), false);
	},

	// Only scroll if offscreen
	makeVisible: function(e, align) {
		var vo = $(e).viewportOffset();
		if (vo.top < 0 || vo.top + e.offsetHeight > document.viewport.getHeight())
			e.scrollIntoView(align);
	}

});

