;(function(){

var Papa

;(function(){

function Me ()
{
	var m = this.model = new Me.Model(),
		v = this.view = new Me.View(),
		c = this.controller = new Me.Controller()
	
	m.view = v
	v.controller = c
	c.model = m
	
	m.parent = v.parent = c.parent = this
}

Me.prototype =
{
	bind: function (nodes)
	{
		this.view.bind(nodes)
		
		this.view.checkRequest()
		
		return this
	}
}

Me.className = 'CocktailsPage'
self[Me.className] = Papa = Me

})();


;(function(){

var lettersConversion =
{
	0: '#', 1: '#', 2: '#', 3: '#', 4: '#', 5: '#', 6: '#', 7: '#', 8: '#', 9: '#', '№': '#',
	'ё': 'е', 'й': 'и'
}

Object.extend(Cocktail,
{
	indexByFirstLetter: function ()
	{
		if (this.index.byFirstLetter)
			return
		
		function byFirstLetter (v)
		{
			var letter = v.name.charAt(0).toLowerCase()
			var l = lettersConversion[letter]
			return l || letter
		}
		this.index.byFirstLetter = DB.hashOfAryIndexBy(this.db, byFirstLetter)
	},
	
	getByFirstLetterPrepare: function ()
	{
		this.indexByFirstLetter()
	},
	
	getByFirstLetter: function (letter)
	{
		return this.index.byFirstLetter[letter.toLowerCase()]
	},
	
	getFirstLettersPrepare: function ()
	{
		this.indexByFirstLetter()
	},
	
	getFirstLetters: function ()
	{
		var letters = Object.keys(this.index.byFirstLetter)
		letters.sort()
		return letters
	}
})

Cocktail.findAndBindPrepares()

function Me () {}

Me.prototype =
{
	setFilters: function (filters)
	{
		this.view.renderLetters(Cocktail.getFirstLetters())
		
		this.completeFilters(filters || {})
		var state = this.filters.state
		this.filters.state = null
		this.setState(state, this.filters)
	},
	
	getRandomCocktail: function ()
	{
		return Cocktail.getAll().random(1)[0]
	},
	
	knownStates: {byName: 1, byLetter: 1, top20: 1},
	
	completeFilters: function (filters)
	{
		this.filters =
		{
			name: filters.name || '',
			letter: filters.letter || '*',
			page: filters.page || 0,
			state: this.knownStates[filters.state] ? filters.state : 'byName'
		}
	},
	
	setState: function (state, filters)
	{
		if (this.filters.state == state)
			return
		
		if (state == 'byName')
			this.view.renderRandomCocktail(this.getRandomCocktail())
		
		this.view.turnToState(state)
		this.completeFilters(filters || {})
		this.filters.state = state
		this.applyFilters()
	},
	
	onPageChanged: function(num){
		this.filters.page = num;
		this.view.saveFilters(this.filters);
	},
	
	onLetterFilter: function(letter)
	{
		if (letter == this.filters.letter)
			return
		
		Statistics.cocktailsFilterSelected(letter)
		
		this.filters.page = 0
		this.filters.letter = letter
		this.applyFilters()
	},
	
	onNameFilter: function (name)
	{
		if (name == this.filters.name)
			return
		
		this.filters.name = name
		this.filters.page = 0
		this.applyFilters()
	},
	
	getBySimilarNameCache: {},
	getBySimilarName: function (name)
	{
		if (this.getBySimilarNameCache[name])
			return this.getBySimilarNameCache[name]
			
		var words = name.split(/\s+/),
			res = [], db = Cocktail.getAll()
		
		for (var i = 0; i < words.length; i++)
			words[i] = new RegExp('(?:^|\\s|-)' + RegExp.escape(words[i]), 'i')
		
		var first = words[0], jl = words.length
		SEARCH: for (var i = 0; i < db.length; i++)
		{
			var cocktail = db[i], name
			
			if (first.test(cocktail.name))
				name = cocktail.name
			else if (first.test(cocktail.name_eng))
				name = cocktail.name_eng
			else
				continue SEARCH
			
			for (var j = 1; j < jl; j++)
				if (!words[j].test(name))
					continue SEARCH
			
			res.push(cocktail)
		}
		return (this.getBySimilarNameCache[name] = res)
	},
	
	
	getCocktailsByFilters: function (filters)
	{
		if (filters.state == 'byName')
		{
			if (filters.name)
				return this.getBySimilarName(filters.name)
			
			var res = Cocktail.getAll()
			res.randomize()
			return res
		}
		
		if (filters.state == 'byLetter')
		{
			if (filters.letter == '*')
				return Cocktail.getAll()
			
			if (filters.letter)
				return Cocktail.getByFirstLetter(filters.letter)
		}
		
		if (filters.state == 'top20')
		{
			var res = Cocktail.getByTag('Самые популярные')
			res.sort(Cocktail.complexitySort)
			return res
		}
		
		return []
	},
	
	
	applyFilters: function()
	{
		var filters = this.filters
		var res = this.getCocktailsByFilters(filters)
		this.view.onModelChanged(res, filters)
	}
}

Papa.Model = Me

})();
;(function(){

function remClass(elem, className) { if(elem) elem.removeClassName(className) }

function Me (nodes)
{
	this.riJustInited  = true;
	this.filterElems   = { letter: null }
	this.perPage       = 20;
	this.np            = -1;
	this.renderedPages = {}
	this.nodeCache     = []
}

Me.prototype =
{
	bind: function (nodes)
	{
		this.nodes = nodes
		
		this.dropTargets =
		[
			this.nodes.cartEmpty,
			this.nodes.cartFull
		]
		
		new RollingImagesLite(this.nodes.resultsDisplay, {animationType: 'easeInOutQuad', duration:0.75})
		
		this.fixHashChange()
		this.bindEvents()
	},
	
	fixHashChange: function ()
	{
		// fix for cocktails initialization issue
		this.currentHash = window.location.hash
		var me = this
		function checkHash ()
		{
			if (me.currentHash != window.location.hash)
				window.location.reload(true)
		}
		setInterval(checkHash, 250)
	},
	
	checkRequest: function ()
	{
		var filters = this.filtersFromRequest()
		this.controller.onFiltersChanged(filters)
	},
	
	filtersFromRequest: function ()
	{
		var m = window.location.href.match(/#(.+)$/)
		if (!m)
			return
		
		var filters = UrlEncode.parse(m[1])
		filters.page = +filters.page || 0
		return filters
	},
	
	saveFilters: function (filters) {
		var self = this;
		clearTimeout(this.hashTimeout);
		this.hashTimeout = setTimeout(function() { 
			self.updatePageHash(filters);
		} , 400);
	},
	
	updatePageHash: function (filters)
	{
		var hash = {}
		for (var k in filters)
		{
			var v = filters[k]
			
			if (!v || v == '*')
				continue
			
			if (k == 'state' && v == 'byName')
				continue
			
			hash[k] = v
		}
		
		window.location.hash = UrlEncode.stringify(hash) || 'i'
		this.currentHash = window.location.hash
	},
	
	bindEvents: function ()
	{
		var self = this;
		
		var nodes = this.nodes
		
		var ril = nodes.resultsDisplay.RollingImagesLite;
		
		nodes.bigPrev.addEventListener('mousedown', function(e){ ril.goPrev() }, false);
		nodes.bigNext.addEventListener('mousedown', function(e){ ril.goNext() }, false);
		
		ril.onselect = function (node, num) {
			if (!self.riJustInited) {
				self.controller.onPageChanged(num);
				self.renderNearbyPages(num, 0)
			} else { self.riJustInited = false }
			
			// big pager buttons
			if(num == (self.np-1) || self.np == 1) nodes.bigNext.addClassName('disabled');
			else nodes.bigNext.removeClassName('disabled');
			if(num == 0 || self.np == 1) nodes.bigPrev.addClassName('disabled');
			else nodes.bigPrev.removeClassName('disabled');
		}
		
		nodes.searchByName.getElementsByTagName("form")[0].addEventListener('submit', function(e) { e.preventDefault() }, false);
		var searchByNameInput = nodes.searchByName.getElementsByTagName("input")[0];
		searchByNameInput.addEventListener('keyup', function(e){ self.controller.onNameFilter(this.value) }, false);
		
		var nameSearchHandler = function (e) {
			searchByNameInput.value = this.innerHTML;
			self.controller.onNameFilter(this.innerHTML);
			nodes.panels.addClassName('just-suggested')
		}
		
		nodes.searchExampleName.addEventListener('mousedown', nameSearchHandler, false);
		nodes.searchExampleNameEng.addEventListener('mousedown', nameSearchHandler, false);
		
		var controller = this.controller
		function tabClicked (e)
		{
			var name = e.target.getAttribute('data-tab-name')
			if (!name)
				return
			controller.onTabSelected(name)
		}
		nodes.tabsRoot.addEventListener('click', tabClicked, false)
	},
	
	turnToState: function (state)
	{
		var nodes = this.nodes
		
		var last = nodes.tabs[this.lastState]
		if (last)
			last.removeClassName('selected')
		
		this.lastState = state
		
		var present = nodes.tabs[state]
		if (present)
			present.addClassName('selected')
		
		nodes.panels.className = state
		
		if (state == 'byName')
		{
			nodes.searchByNameInput.value = ''
			nodes.searchByNameInput.focus()
		}
	},
	
	renderRandomCocktail: function (cocktail)
	{
		var nodes = this.nodes
		nodes.searchExampleName.innerHTML = cocktail.name
		nodes.searchExampleNameEng.innerHTML = cocktail.name_eng
	},
	
	onModelChanged: function(resultSet, filters) { // model
		this.currentFilters = filters;
		
		this.renderAllPages(resultSet, filters.page);
		this.renderFilters(this.currentFilters);
	},
	
	renderFilters: function(filters){
		var nodes = this.nodes
		
		remClass(this.filterElems.letter || nodes.lettersAll, 'selected-button');
		if (filters.letter == '*')
		{
			this.filterElems.letter = nodes.lettersAll
		}
		else
		{
			var letterElems = $$("a", nodes.alphabetRu).concat(nodes.lettersAll);
			
			for(var i = 0; i < letterElems.length; i++) {
				if(letterElems[i].innerHTML == filters.letter.toLowerCase()){
					this.filterElems.letter = letterElems[i];
					break;
				}
			}   
		}
		this.filterElems.letter.addClassName('selected-button');
		
		if(filters.page > 0) {
			nodes.resultsDisplay.RollingImagesLite.goToNode($('page_'+filters.page), 'directJump');	
		}
		
		if (filters.name)
		{
			var input = nodes.searchByNameInput
			if (input.value != filters.name)
				input.value = filters.name
		}
	},
	
	renderAllPages: function(resultSet, pageNum){
		var nodes = this.nodes
		
		this.resultSet = resultSet;
		this.np = Math.ceil(resultSet.length / this.perPage)
		
		nodes.resultsRoot.empty();
		
		if (resultSet.length)
			nodes.resultsDisplay.removeClassName('empty')
		else
			nodes.resultsDisplay.addClassName('empty')
			
		
		this.renderedPages = {}
		this.nodeCache     = []
		this.renderSkeleton(this.np);
		this.renderNearbyPages(pageNum);
		
		this.renderPager(this.np);
		nodes.resultsDisplay.RollingImagesLite.sync();
		nodes.resultsDisplay.RollingImagesLite.goInit();
	},
	
	renderSkeleton: function (count)
	{
		var nodes = this.nodes,
			parent = nodes.resultsRoot,
			pages = nodes.pages = []
		
		for (var i = 0; i < count; i++)
		{
			var page = pages[i] = document.createElement('ul')
			page.id = 'page_' + i
			page.className = 'point cocktails';
			parent.appendChild(page)
		}
	},
	
	renderNearbyPages: function (num, delta)
	{
		if (delta === undefined)
			delta = 1
		
		for (var i = num - delta; i <= num + delta; i++)
			if(i >= 0 && i < this.np && !this.renderedPages[i])
				this.renderPage(i)
	},
	
	renderLetters: function (set){
		var nodes = this.nodes
		
		var controller = this.controller
		function click (e)
		{
			var letter = e.target.dataLetter
			controller.onLetterFilter(letter);
		}
		
		nodes.lettersAll.dataLetter = '*'
		nodes.lettersAll.addEventListener('click', click, false)
		
		var parent = nodes.alphabetRu
		
		for(var i = 0; i < set.length; i++){
			var a = document.createElement("a");
			a.innerHTML = set[i];
			a.dataLetter = set[i]
			parent.appendChild(a);
			a.addEventListener('click', click, false)
		}
	},
	
	renderPage: function (num)
	{
		var nodes = this.nodes
		
		var cocktails = this.resultSet,
			node, cocktail, cache = this.nodeCache,
			parent = nodes.pages[num],
			end = (num + 1) * this.perPage,
			dropTargets = this.dropTargets
		
		for (var i = num * this.perPage; i < end; i++)
		{
			var item = document.createElement('li')
			item.className = 'item'
			
			if (!(node = cache[i]))
			{
				if (!(cocktail = cocktails[i]))
					continue
				node = cache[i] = cocktail.getPreviewNodeCropped()
				node.img.__draggable = [cocktail.name, dropTargets]
			}
			item.appendChild(node)
			parent.appendChild(item)
		}
		
		this.renderedPages[num] = true
	},
	
	renderPager: function (numOfPages) {
		var span = this.nodes.pagerRoot;
		span.empty();
		for (var i = 1; i <= numOfPages; i++) {
			var a = document.createElement("a");
			a.className= i >= 10 ? "button two" : "button";
			a.appendChild(document.createTextNode(i));
			span.appendChild(a);
			span.appendChild(document.createTextNode(' '))
		}
	}
}

Papa.View = Me

})();
;(function(){

function Me () {}

Me.prototype =
{
	onFiltersChanged: function (filters)
	{
		this.model.setFilters(filters)
	},
	
	onLetterFilter: function(letter) {
		this.model.onLetterFilter(letter);
	},
	
	onNameFilter: function(name){
		this.model.onNameFilter(name);
	},
	
	onPageChanged: function(num){
		this.model.onPageChanged(num);
	},
	
	onTabSelected: function(name){
		this.model.setState(name);
	}
}

Papa.Controller = Me

})();


})();

;(function(){

function onready ()
{
	UserAgent.setupDocumentElementClassNames()
	IngredientPopup.bootstrap()
	
	var nodes =
	{
		bodyWrapper: $$('#common-main-wrapper .column-main')[0],
		resultsDisplay: $('results_display'),
		resultsRoot: $('surface'),
		pagerRoot: $('p-list'),
		
		bigNext: $$(".pager-big .next")[0],
		bigPrev: $$(".pager-big .prev")[0],
		
		alphabetRu: $('alphabetical-ru'),
		lettersAll: $('letters_all'),
		
		tagsList: $('tags_list'),
		strengthsList: $('strengths_list'),
		methodsList: $('methods_list'),
		
		searchByName: $('search_by_name'),
		searchByNameInput: $$('#search_by_name input')[0],
		searchByLetter: $('search_by_letter'),
		searchByTags: $('search_by_tags'),
		
		mainArea: $('b_content'),
		
		tabsRoot: $$('#search_tabs')[0],
		tabs:
		{
			byName: $$('.by-name')[0],
			byLetter: $$('.by-letter')[0],
			top20: $$('.top-20')[0]
		},
		
		byLetterTab: $$('#search_tabs .by-letter')[0],
		
		searchExampleName: $('search_example_name'),
		searchExampleNameEng: $('search_example_name_eng'),
		searchTipName: $('search_tip_name'),
		
		panels: $('panels'),
		
		cartEmpty: $('cart_draghere'),
		cartFull: $('cart_contents'),
		
		spotlighted: $('spotlighted')
	}
	
	var widget = new CocktailsPage(nodes)
	widget.bind(nodes)
	
	Calculator.init()
}

$.onready(onready)

})();

if (/WebKit\/|MSIE [6789]\./.test(navigator.userAgent))
(function(){

var status = {}

document.addEventListener
(
	'keydown',
	function (e)
	{
		var target = e.target
		
		var ne = document.createEvent('Event')
		ne.initEvent('keypress', true, true)
		
		// copying valueable data
		ne.altKey = e.altKey
		ne.ctrlKey = e.ctrlKey
		ne.metaKey = e.metaKey
		ne.charCode = e.charCode
		ne.keyCode = e.keyCode
		
		if (status[e.keyCode])
			e.stopPropagation()
		else
			status[e.keyCode] = true
		
		if (!target.dispatchEvent(ne))
			e.preventDefault()
	},
	true
)

document.addEventListener
(
	'keyup',
	function (e)
	{
		status[e.keyCode] = false
	},
	true
)

})();
;(function(){

var rex = /([\\\.\*\+\?\$\^\|\(\)\[\]\{\}])/g

if (!RegExp.escape)
RegExp.escape = function (str)
{
	return ('' + str).replace(rex, '\\$1')
}

})();

;(function(){

var Me =
{
	decode: decodeURIComponent,
	encode: encodeURIComponent,
	paramDelimiter: '&',
	
	parse: function (string, forceArray)
	{
		var decode = this.decode
		var res = {}
		
		var parts = String(string).split(this.paramDelimiter)
		for (var i = 0; i < parts.length; i++)
		{
			var pair = parts[i].split('='),
				k = pair[0],
				v = pair[1]
			
			if (v === undefined)
			{
				if (k == '')
					continue
			}
			else
				v = decode(v)
			
			k = decode(k)
			
			if (forceArray)
			{
				if (res[k])
					res[k].push(v)
				else
					res[k] = [v]
			}
			else
			{
				var a = res[k]
				if (a)
				{
					if (typeof res[k] == 'object')
						res[k].push(v)
					else
						res[k] = [res[k], v]
				}
				else
					res[k] = v
			}
		}
		
		return res
	},
	
	stringify: function (data)
	{
		var encode = this.encode, A = Array,
			pairs = []
		
		for (var k in data)
		{
			var v = data[k]
			
			k = encode(k)
			if (v && v.constructor == A)
			{
				for (var i = 0, il = v.length; i < il; i++)
					pairs.push(k + '=' + encode(v[i]))
			}
			else
				pairs.push(k + '=' + encode(v))
		}
		
		return pairs.join(this.paramDelimiter)
	}
}

Me.className = 'UrlEncode'
self[Me.className] = Me

})();
;(function(){

var doc = document, undef, myName = 'NodesShortcut'

function T (text)
{
	return doc.createTextNode(text)
}

function N (tag)
{
	return doc.createElement(tag)
}

function Nc (tag, cn)
{
	var node = doc.createElement(tag)
	node.className = cn
	return node
}

function Nct (tag, cn, text)
{
	var node = doc.createElement(tag)
	node.className = cn
	node.appendChild(doc.createTextNode(text))
	return node
}


function E (tag, cn, props)
{
	var node = doc.createElement(tag)
	if (cn !== undef) node.className = cn
	if (props)
		for (var i in props)
			node.setAttribute(i, props[i])
	return node
}

var Me = self[myName] = {}
	funcs = Me.funcs = {T: T, N: N, Nc: Nc, Nct: Nct, E: E}

var pairs = []
for (var k in funcs)
	pairs.push(k + '=' + myName + '.funcs.' + k)

Me.code = 'var ' + pairs.join(',')
Me.include = function () { return this.code }


})();

;(function(){

var myName = 'MVC'

function Me () {}

Me.prototype =
{
	__mvc_interlink: function ()
	{
		var constructor = this.constructor,
			model = this.model = new constructor.Model(),
			view = this.view = new constructor.View(),
			controller = this.controller = new constructor.Controller()
		
		model.view = controller.view = view
		view.controller = controller
		controller.model = model
		model.parent = view.parent = controller.parent = this
	},
	
	initialize: function () {}
}

self[myName] = Me
Me.className = myName

function Model () {}
Model.prototype.initialize = function () {}
Model.className = myName + '.Model'
Me.Model = Model

function View () {}
View.prototype.initialize = function () {}
View.className = myName + '.View'
Me.View = View

function Controller () {}
Controller.prototype.initialize = function () {}
Controller.className = myName + '.Controller'
Me.Controller = Controller


Me.setup = function (klass, name, parent)
{
	if (!parent)
		parent = Me
	
	klass.prototype = new parent()
	klass.className = name
	
	
	function Model ()
	{
		this.constructor = Model
		this.initialize.apply(this, arguments)
	}
	Model.className = name + '.Model'
	Model.prototype = new parent.Model()
	klass.Model = Model
	
	
	function View ()
	{
		this.constructor = View
		this.initialize.apply(this, arguments)
	}
	View.className = name + '.View'
	View.prototype = new parent.View()
	klass.View = View
	
	
	function Controller ()
	{
		this.constructor = Controller
		this.initialize.apply(this, arguments)
	}
	Controller.className = name + '.Controller'
	Controller.prototype = new parent.Controller()
	klass.Controller = Controller
	
	
	return klass
}

Me.create = function (name, parent)
{
	function klass ()
	{
		this.constructor = klass
		this.__mvc_interlink()
		this.initialize()
	}
	
	return this.setup(klass, name, parent)
}

})();

;(function(){

var Papa

;(function(){

var myName = 'Autocompleter',
	Me = Papa = self[myName] = MVC.create(myName)

var myProto =
{
	initialize: function ()
	{
		this.model.initialize()
		this.view.initialize()
		this.controller.initialize()
		this.model.controller = this.controller
	},
	
	bind: function (main, count)
	{
		this.view.bind({main:main})
		this.setCount(count === undefined ? 15 : count)
		return this
	},
	
	setDataSource: function (ds) { this.model.dataSource = ds },
	setValueGetter: function (f) { this.view.valueGetter = f },
	setValueSetter: function (f) { this.view.valueSetter = f },
	setCount: function (v) { this.model.setCount(v); this.view.setCount(v) },
	setInstant: function (v) { this.controller.instant = v },
	onconfirm: function () {}
}

Object.extend(Me.prototype, myProto)

})();


;(function(){

var Me = Papa.View

eval(NodesShortcut.include())

var myProto =
{
	valueGetter: function (node) { return node.value },
	valueSetter: function (node, value) { node.value = value },
	
	initialize: function ()
	{
		this.nodes = {}
		this.keyMap = {38:'goUp', 40:'goDown', 37:false, 39:false, 9:false, 16:false, 17:false, 18:false, 91:false, 13:'goEnter', 27:'goEscape'}
	},
	
	bind: function (nodes)
	{
		this.nodes = nodes
		var main = nodes.main
		main.setAttribute('autocomplete', 'off')
		
		var list = this.nodes.list = N('ul')
		list.className = 'autocomplete'
		main.parentNode.appendChild(list)
		
		var me = this
		main.addEventListener('blur', function (e) { me.onBlur(e) }, false)
		main.addEventListener('keypress', function (e) { me.onKeyPress(e) }, false)
	},
	
	onKeyPress: function (e)
	{
		var targ = e.target, controller = this.controller,
			action = this.keyMap[e.keyCode]
		// alert(e.keyCode)
		if (action === false)
			return
		else if (action)
		{
			if (controller[action](targ.value) === false)
			{
				e.preventDefault()
				e.stopPropagation()
			}
		}
		else
		{
			var me = this
			setTimeout(function () { me.onValue(targ) }, 1)
		}
	},
	
	onValue: function (node)
	{
		this.controller.goValue(this.valueGetter(node))
	},
	
	onBlur: function (e)
	{
		this.controller.goBlur()
	},
	
	onMouseMove: function (node, e)
	{
		this.controller.itemHovered(node.num)
	},
	
	onMouseDown: function (node, e)
	{
		this.controller.itemClicked(node.num)
	},
	
	setCount: function (count)
	{
		this.createItemsNodes(count)
	},
	
	renderVariant: function (str)
	{
		this.valueSetter(this.nodes.main, str)
	},
	
	show: function ()
	{
		var nodes = this.nodes
		nodes.main.addClassName('autocompleting')
		nodes.list.show()
		this.active = true
	},
	
	hide: function ()
	{
		var nodes = this.nodes
		nodes.main.removeClassName('autocompleting')
		nodes.list.hide()
		this.active = false
	},
	
	createItemsNodes: function (count)
	{
		var list = this.nodes.list, items = this.nodes.items = []
		list.empty()
		
		var me = this
		function mousedown (e) { me.onMouseDown(this, e) }
		function mousemove (e) { me.onMouseMove(this, e) }
		
		for (var i = 0; i < count; i++)
		{
			var item = items[i] = N('li')
			item.className = 'item'
			item.hide()
			list.appendChild(item)
			item.num = i
			item.addEventListener('mousedown', mousedown, false)
			item.addEventListener('mousemove', mousemove, false)
		}
	},
	
	renderResults: function (results)
	{
		var items = this.nodes.items
		for (var i = 0; i < results.length && i < items.length; i++)
		{
			var r = results[i],
				item = items[i]
			item.empty()
			item.appendChild(r[1]) // [1] means a text representing node (or DocumentFragment)
			item.show()
		}
		
		for (; i < items.length; i++)
			items[i].hide()
	},
	
	selectItem: function (num)
	{
		if (this.selected === num)
			return
		
		var node, items = this.nodes.items
		
		if ((node = items[this.selected]))
			node.removeClassName('selected')
		
		if ((node = items[num]))
			node.addClassName('selected')
		
		this.selected = num
	}
}

Object.extend(Me.prototype, myProto)

})();


;(function(){

var Me = Papa.Controller

var myProto =
{
	initialize: function ()
	{
		this.reset()
		this.value = undefined
	},
	
	reset: function ()
	{
		this.results = []
		this.selected = -1
		this.value = ''
	},
	
	begin: function ()
	{
		if (this.active)
			return
		// log('begin')
		
		this.active = true
		this.view.show()
	},
	
	end: function ()
	{
		if (!this.active)
			return
		// log('end')
		
		this.active = false
		this.reset()
		this.view.hide()
	},
	
	search: function ()
	{
		this.model.search(this.value)
	},
	
	setResults: function (results)
	{
		this.selected = -1
		this.results = results
		this.view.renderResults(results)
		this.view.selectItem(-1)
	},
	
	selectBy: function (dir)
	{
		var total = this.results.length,
			selected = this.selected
		
		selected += dir
		
		if (selected < -1)
			selected = total - 1
		else if (selected >= total)
			selected = -1
		
		this.select(selected)
	},
	
	select: function (num)
	{
		if (this.selected === num)
			return
		
		this.selected = num
		this.view.selectItem(num)
	},
	
	sendSelected: function ()
	{
		this.view.renderVariant(this.selectedValue())
	},
	
	selectedValue: function ()
	{
		var selected = this.selected
		return selected < 0 ? this.value : this.results[selected][0] // [0] means a text value
	},
	
	dispatchConfirm: function ()
	{
		return this.parent.onconfirm({type:'confirm', data: {value:this.selectedValue(), selected:this.selected, results:this.results}})
	},
	
	goValue: function (value)
	{
		if (this.value !== value)
		{
			this.value = value
			if (value !== '')
			{
				this.begin()
				this.search()
			}
			else
				this.end()
		}
	},
	
	goUp: function (value)
	{
		if (this.active)
		{
			this.selectBy(-1)
			this.sendSelected()
			return false // drop an event
		}
	},
	
	goDown: function (value)
	{
		if (this.active)
		{
			this.selectBy(1)
			this.sendSelected()
		}
		else
		{
			this.value = value
			if (value !== '')
			{
				this.begin()
				this.search()
			}
		}
		
		return false // drop an event
	},
	
	goEnter: function (value)
	{
		if (this.active)
		{
			if (this.dispatchConfirm() !== false)
				this.sendSelected()
			
			this.end()
			
			return this.instant || false
		}
	},
	
	goEscape: function (value)
	{
		if (this.active)
		{
			this.view.renderVariant(this.value)
			this.end()
		}
	},
	
	goBlur: function ()
	{
		if (this.active)
		{
			this.sendSelected()
			this.end()
		}
	},
	
	itemHovered: function (num)
	{
		this.select(num)
	},
	
	itemClicked: function (num)
	{
		this.select(num)
		if (this.dispatchConfirm() !== false)
			this.sendSelected()
		this.end()
	}
}

Object.extend(Me.prototype, myProto)

})();


;(function(){

var Me = Papa.Model

var myProto =
{
	setCount: function (v) { this.count = v },
	search: function (value)
	{
		var ds = this.dataSource
		this.controller.setResults(ds ? ds.search(value, this.count) : [])
	}
}

Object.extend(Me.prototype, myProto)

})();


})();


