// fix for FF 1.5 ;)
if (!Array.copy)
	Array.copy = function (src) { return Array.prototype.slice.call(src) }

BarsPage =
{
	initialize: function (nodes)
	{
		var state = {view: 'list'}
		var model = this.model = new BarsPageModel()
		var controller = this.controller = new BarsPageController(state)
		var view = this.view = new BarsPageView(controller, nodes)
		model.view = view
		controller.view = view
		controller.model = model
		
		view.checkHash()
	}
}

$.onready
(
	function ()
	{
		document.documentElement.removeClassName('loading')
		
		var nodes =
		{
			titleAll: $$('#head .all')[0],
			titleSearch: $$('#head .search')[0],
			titleSearchName: $$('#head .search .cocktail')[0],
			titleSearchAll: $$('#head .search .drop-cocktail')[0],
			viewSwitcher: $('switch-view'),
			viewSwitcherButtons: $$('#switch-view .view-list, #switch-view .view-map'),
			barsContainer: $('bars-container'),
			citySelecter:
			{
				main: $('bars-city'),
				button: $$('#bars-city .button')[0],
				options: $$('#bars-city .options')[0]
			},
			formatSelecter:
			{
				main: $('bars-format'),
				button: $$('#bars-format .button')[0],
				options: $$('#bars-format .options')[0]
			},
			feelSelecter:
			{
				main: $('bars-feel'),
				button: $$('#bars-feel .button')[0],
				options: $$('#bars-feel .options')[0]
			},
			map: $('map'),
			mapSurface: $$('#map .surface')[0],
			positionControl: $$('.position-control')[0],
			
			moreInfo: $('more-info'),
			guidePopup: $('guide-info-popup'),
			guidePopupBody: $$('#guide-info-popup .popup-window')[0]
		}
		
		RoundedCorners.round(nodes.map)
		
		BarsPage.initialize(nodes)
	}
)

;(function(){

var decode = decodeURIComponent,
	encode = encodeURIComponent

var myName = 'UrlEncode',
	Me = self[myName] =
{
	paramDelimiter: '&',
	
	parse: function (string, forceArray)
	{
		var res = {}
	
		var parts = String(string).split(this.paramDelimiterRex || this.paramDelimiter)
		for (var i = 0; i < parts.length; i++)
		{
			var pair = parts[i].split('='),
				name = decode(pair[0]),
				val = decode(pair[1] || '')
		
			if (forceArray)
			{
				if (res[name])
					res[name].push(val)
				else
					res[name] = [val]
			}
			else
			{
				if (res[name])
				{
					if (typeof res[name] == 'array')
						res[name].push(val)
					else
						res[name] = [res[name], val]
				}
				else
					res[name] = val
			}
		}
	
		return res
	},
	
	stringify: function (data)
	{
		var pd = this.paramDelimiter
		
		if (!data)
			return ''
		
		if (typeof data.toUrlEncode == 'function')
			return data.toUrlEncode()
		
		switch (data.constructor)
		{
			case Array:
				var arr = []
				for (var j = 0, jl = data.length; j < jl; j++)
					arr.push(encode(data[j]))
				return arr.join(pd)
			
			case Object:
				var arr = []
				for (var i in data)
					if (i !== undefined && i != '')
					{
						var val = data[i]
						var enci = encode(i)
						if (val !== undefined && val !== null)
							switch (val.constructor)
							{
								case Array:
									for (var j = 0, jl = val.length; j < jl; j++)
										arr.push(enci + "=" + encode(val[j]))
									break
								case Object:
									arr.push(enci + "=" + encode('[object]'))
									break
								default:
									arr.push(enci + "=" + encode(val))
									break
							}
					}
				return arr.join(pd)
			
			default:
				return encode(data)
		}
	}
}

})();
;(function(){

var myName = 'GoogleApiLoader'

function Me (keys, host, language)
{
	this.host = /[^.]+\.[^.]+$/i.exec(host || location.host)
	this.state = 'init'
	this.apis = []
	this.language = language || (self.LanguagePack ? LanguagePack.code : 'en')
	this.keys = keys
	this.prerequisites = {}
}

Me.prototype =
{
	load: function (name, version)
	{
		if (name)
			this.apis.push({name: name, version: version})
		
		var me = this
		
		if (this.state == 'init')
		{
			if (!this.keys)
				throw new Error(myName + ': keys is undefined')
			
			this.node = $.include('http://www.google.com/jsapi?key=' + this.keys[this.host])
			
			function wait ()
			{
				if (!self.google)
					return
				
				clearInterval(timer)
				me.apiLoaderLoaded(self.google)
			}
			
			var timer = setInterval(wait, 250)
			
			this.state = 'loading'
		}
		
		if (this.state == 'ready')
			setTimeout(function () { me.fireAll() }, 1)
			
		return this
	},
	
	apiLoaderLoaded: function (google)
	{
		this.state = 'ready'
		this.google = google
		this.apiLoaded({name: 'loader'}, this.google['loader'])
		
		this.fireAll()
	},
	
	fireAll: function ()
	{
		for (var i = 0; i < this.apis.length; i++)
			this.loadApi(this.apis[i])
		
		this.apis.length = 0
	},
	
	loadApi: function (api)
	{
		var me = this
		function callback (e)
		{
			me.apiLoaded(api)
		}
		
		var opts =
		{
			nocss: true,
			language: this.language,
			callback: callback
		}
		
		this.google.load(api.name, api.version, opts)
	},
	
	apiLoaded: function (api)
	{
		this.dispatchEvent({type: api.name, api: this.google[api.name]})
	}
}

Me.mixIn(EventDriven)

Me.className = myName
self[myName] = Me

})();


;(function(){

var myName = 'TabSwitcher'

function Me ()
{
	this.nodes = {tabs:[], sections:[]}
}

Me.prototype =
{
	eventType: 'mousedown',
	
	bind: function (nodes)
	{
		var me = this
		this.mouseListener = function (e) { me.onMouse(e, this) }
		
		this.setTabs(nodes.tabs)
		this.setSections(nodes.sections)
		
		return this
	},
	
	unbind: function ()
	{
		this.setTabs([])
	},
	
	onMouse: function (e, node)
	{
		// if (e.target != node)
		// 	return
		
		var tabs = this.nodes.tabs,
			i, num = -1, value
		
		for (i = 0; i < tabs.length; i++)
			if (node === tabs[i])
			{
				value = node.getAttribute('data-tab-name')
				num = i
			}
		
		this.select(value, num)
	},
	
	select: function (value, num)
	{
		var ok = this.dispatchEventData('select', {value: value, num: num})
		if (ok)
			this.renderSelected(num)
		return ok
	},
	
	setTabs: function (tabs)
	{
		var listener = this.mouseListener, node, eventType = this.eventType
		
		var old = this.nodes.tabs
		for (var i = 0; i < old.length; i++)
			if ((node = old[i]))
				node.removeEventListener(eventType, listener, false)
		
		var numByName = this.numByName = {},
			names = this.names = []
		this.nodes.tabs = tabs
		for (var i = 0; i < tabs.length; i++)
			if ((node = tabs[i]))
			{
				node.addEventListener(eventType, listener, false)
				var name = node.getAttribute('data-tab-name')
				if (name !== undefined)
				{
					numByName[name] = i
					names.push(name)
				}
			}
	},
	
	getNames: function () { return this.names },
	
	setSections: function (sections)
	{
		this.nodes.sections = sections
	},
	
	renderSelected: function (num)
	{
		var nodes = this.nodes, node
		
		if (typeof num !== 'number')
			num = this.numByName[num]
		
		var tabs = nodes.tabs
		for (var i = 0; i < tabs.length; i++)
			if ((node = tabs[i]))
				node.toggleClassName('selected', num === i)
		
		var sections = nodes.sections
		for (var i = 0; i < sections.length; i++)
			if ((node = sections[i]))
				node.toggleClassName('hidden', num !== i)
	}
	
}

Me.mixIn(EventDriven)

self[myName] = Me
Me.className = myName

})();
;(function(){

var myName = 'Selecter'

function Me (group)
{
	this.nodes = {optionsCache: []}
	this.constructor = Me
	
	this.valToNum = {}
	this.options = []
	this.optionPresent = []
	
	this.lastSelected = -1
	
	this.group = group
	
	var arr = Me.groups[group]
	if (arr)
		arr.push(this)
	else
		Me.groups[group] = [this]
}

Me.groups = {}
Me.closeGoup = function (group)
{
	var arr = Me.groups[group]
	
	if (!arr)
		return
	
	for (var i = 0, il = arr.length; i < il; i++)
		arr[i].close()
}


eval(NodesShortcut.include())

Me.prototype =
{
	bind: function (nodes)
	{
		this.nodes = nodes
		nodes.optionsCache = []
		
		this.bindEvents()
		
		return this
	},
	
	bindEvents: function ()
	{
		var nodes = this.nodes,
			main = nodes.main,
			me = this
		
		function open (e)
		{
			e.preventDefault()
			Me.closeGoup(me.group)
			
			main.addClassName('open')
			main.addEventListener('mousedown', close, false)
			main.removeEventListener('mousedown', open, false)
			document.addEventListener('mouseup', close, false)
		}
		
		function close ()
		{
			main.removeClassName('open')
			main.addEventListener('mousedown', open, false)
			main.removeEventListener('mousedown', close, false)
			document.removeEventListener('mouseup', close, false)
		}
		
		function select (e)
		{
			e.stopPropagation()
			close(e)
			me.select(e.target.getAttribute('data-selecter-option-num'))
		}
		
		this.close = close
		
		main.addEventListener('mousedown', open, false)
		main.addEventListener('mouseup', function (e) { e.stopPropagation() }, false)
		
		var options = nodes.options
		options.addEventListener('mousedown', select, false)
		options.addEventListener('mouseup', select, false)
	},
	
	close: function () {},
	
	setOptions: function (options)
	{
		var nodes = this.nodes,
			root = nodes.options,
			main = nodes.main
		
		root.empty()
		var valToNum = this.valToNum = {},
			optionsCache = nodes.optionsCache = []
		
		this.options = options
		var optionPresent = this.optionPresent = []
		
		if (!options.length)
		{
			main.removeClassName('single')
			main.addClassName('empty')
			return options
		}
		
		main.removeClassName('empty')
		
		for (var i = 0; i < options.length; i++)
		{
			var option = options[i]
			
			valToNum[option] = i
			optionPresent[i] = true
			
			var li = optionsCache[i] = Nc('li', 'option')
			li.setAttribute('data-selecter-option-num', i)
			li.appendChild(T(option))
			root.appendChild(li)
		}
		
		if (options.length == 1)
			main.addClassName('single')
		else
			main.removeClassName('single')
		
		return options
	},
	
	setCaption: function (value)
	{
		var button = this.nodes.button
		button.empty()
		button.appendChild(T(value))
	},
	
	select: function (num)
	{
		if (!this.optionPresent[num])
			return
		
		if (!this.dispatchEventData('select', {value: this.options[num], num: num}))
			return
		
		this.renderSelected(num)
		
	},
	
	renderSelectedValue: function (value)
	{
		this.renderSelected(this.valToNum[value])
	},
	
	renderSelected: function (num)
	{
		if (num === this.lastSelected)
			return
		
		var optionsCache = this.nodes.optionsCache
			
		var last = optionsCache[this.lastSelected]
		if (last)
			last.removeClassName('selected')
		
		
		optionsCache[num].addClassName('selected')
		
		this.setCaption(this.options[num])
		
		this.lastSelected = num
	}
}

Me.mixIn(EventDriven)
Me.className = myName
self[myName] = Me

})();

var Selecter1 =
{
	stack: [],
	
	bind: function (main)
	{
		main.nodes =
		{
			caption: main.getElementsByClassName('caption')[0],
			options: main.getElementsByClassName('options')[0]
		}
		
		if (!main.onselect)
		 	main.onselect = function () {}
		
		main.setCaption = function (str)
		{
			this.nodes.caption.innerHTML = str
		}
		
		main.setOptions = function (options)
		{
			var optionsNode = this.nodes.options
			optionsNode.empty()
			
			this.remClassName('empty')
			this.remClassName('single')
			
			if (options && options.length)
			{
				for (var i = 0; i < options.length; i++)
				{
					var li = document.createElement('li')
					li.appendChild(document.createTextNode(options[i]))
					optionsNode.appendChild(li)
				}
				
				if (options.length == 1)
					this.addClassName('single')
			}
			else
				this.addClassName('empty')
			
			return options
		}
		
		main.getNodeNumber = function (node)
		{
			var optionsChilds = this.nodes.options.childNodes
			for (var i = 0; i < optionsChilds.length; i++)
				if (optionsChilds[i] == node)
					return i
			return -1
		}
		
		main.getValueNumber = function (val)
		{
			var optionsChilds = this.nodes.options.childNodes
			for (var i = 0; i < optionsChilds.length; i++)
				if (optionsChilds[i].innerHTML == val)
					return i
			return -1
		}
		
		main.removeGarbageNodes = function ()
		{
			var options = this.nodes.options
			var optionsChilds = this.nodes.options.childNodes
			for (var i = 0; i < optionsChilds.length; i++)
				if (optionsChilds[i].nodeType != 4)
					options.removeChild(optionsChilds[i])
		}
		
		main.select = function (num, force)
		{
			if (typeof num !== 'number')
				num = this.getValueNumber(num)
			var optionsChilds = Array.copy(this.nodes.options.childNodes)
			var selected = optionsChilds[num]
			if (selected)
			{
				if (!force && this.onselect(selected.innerHTML, num, selected) === false)
					return
				
				for (var i = 0; i < optionsChilds.length; i++)
					optionsChilds[i].remClassName('selected')
				
				selected.addClassName('selected')
				this.setCaption(selected.innerHTML)
			}
			else
				log('Can`t select option with value "'+num+'": no such option`')
		}
		
		main.removeGarbageNodes()
		
		function close (e)
		{
			main.remClassName('open')
			main.addEventListener('mousedown', open, false)
			main.removeEventListener('mousedown', close, false)
			document.removeEventListener('mouseup', close, false)
		}
		
		function open (e)
		{
			if (main.nodes.options.childNodes.length < 2)
				return
			Selecter.closeAll()
			e.stopPropagation()
			main.addClassName('open')
			main.addEventListener('mousedown', close, false)
			main.removeEventListener('mousedown', open, false)
			document.addEventListener('mouseup', close, false)
		}
		
		function select (e)
		{
			e.stopPropagation()
			close()
			var target = e.target
			if (target.nodeName == 'LI')
				main.select(main.getNodeNumber(target))
		}
		
		main.open = open
		main.close = close
		
		main.addEventListener('mousedown', open, false)
		main.addEventListener('mouseup', function (e) { e.stopPropagation() }, false)
		main.nodes.options.addEventListener('mousedown', select, false)
		main.nodes.options.addEventListener('mouseup', select, false)
		
		main.setOptions([])
		this.stack.push(main)
		
		return main
	},
	
	closeAll: function ()
	{
		for (var i = 0; i < this.stack.length; i++)
			this.stack[i].close()
	}
}

;(function(){

var Papa

;(function(){

var myName = 'Map',
	Me = Papa = MVC.create(myName)

var myProto = 
{
	bind: function (nodes)
	{
		this.view.bind(nodes)
		return this
	},
	
	setCenter: function (center, zoom) { this.model.setCenter(center, zoom) },
	setPoints: function (points) { this.model.setPoints(points) },
	apiLoaded: function () { this.dispatchEvent('ready') }
}

Object.extend(Me.prototype, myProto)
Me.mixIn(EventDriven)

self[myName] = Me

})();


;(function(){

function Me () {}
Papa.Overlay = Me

})();


;(function(){

var Me = Papa.View

eval(NodesShortcut.include())

var myProto =
{
	initialize: function ()
	{
		this.nodes = {}
		this.visibleMarkers = {}
	},
	
	bind: function (nodes)
	{
		this.nodes = nodes
		if (!nodes.wrapper)
			nodes.wrapper = nodes.main
		
		var me = this
		googleApiLoader.addEventListener('maps', function (e) { me.apiLoaded(e) }, false)
		googleApiLoader.load('maps', 2)
		nodes.wrapper.addClassName('loading')
	},
	
	apiLoaded: function (e)
	{
		var api = this.api = e.api
		this.updateOverlayProto()
		this.createMap()
		
		this.ready = true
		this.controller.apiLoaded()
	},
	
	createMap: function ()
	{
		var api = this.api
		
		var map = this.map = new api.Map2(this.nodes.main)
		var me = this
		api.Event.addListener(map, 'load', function () { me.mapLoaded(this) })
		map.enableContinuousZoom()
	},
	
	setCenter: function (center, zoom)
	{
		if (!this.ready)
			return
		
		this.map.setCenter(new this.api.LatLng(center.lat, center.lng), zoom)
	},
	
	mapLoaded: function ()
	{
		var me = this
		this.nodes.wrapper.removeClassName('loading')
		this.api.Event.addListener(this.map, 'moveend', function () { me.mapMoveEnd(this) })
		this.addControls()
	},
	
	addControls: function ()
	{
		var nodes = this.nodes,
			control = nodes.control
		
		if (!control)
		{
			var api = this.api, controlPosition = new api.ControlPosition(api.ANCHOR_TOP_LEFT, new api.Size(10, 15))
			this.map.addControl(new api.SmallMapControl(), controlPosition)
			return
		}
		
		var main = nodes.main,
			map = this.map
		
		main.appendChild(control)
		
		var actions =
		{
			top:    ['panDirection', 0, 1],
			right:  ['panDirection', -1, 0],
			bottom: ['panDirection', 0, -1],
			left:   ['panDirection', 1, 0],
			plus:   ['zoomIn'],
			minus:  ['zoomOut']
		}
		
		function move (e)
		{
			var action = actions[e.target.getAttribute('data-map-action')]
			if (action)
				map[action[0]].apply(map, action.slice(1))
		}
		
		control.addEventListener('click', move, false)
	},
	
	updateOverlayProto: function ()
	{
		var proto = Papa.Overlay.prototype,
			api = this.api
		
		Object.extend(proto, new api.Overlay())
		proto.api = api
	},
	
	mapMoveEnd: function (map)
	{
		var center = map.getCenter(),
			bounds = map.getBounds(),
			sw = bounds.getSouthWest(),
			ne = bounds.getNorthEast()
		
		this.controller.moved({lat:center.lat(), lng:center.lng()}, map.getZoom(), {lat:sw.lat(), lng:sw.lng()}, {lat:ne.lat(), lng:ne.lng()})
	},
	
	renderPoints: function (points)
	{
		if (!this.ready)
			return
		
		var map = this.map,
			visible = this.visibleMarkers,
			now = this.visibleMarkers = {}
		
		for (var i = 0; i < points.length; i++)
		{
			var point = points[i], pid = point.mapPointId
			
			// get the marker and insert it into the new visibleMarkers hash
			now[pid] = point
			
			// add marker (and delete its record) only if it isn't already shown
			if (!visible[pid])
				map.addOverlay(point)
			else
				delete visible[pid]
		}
		
		// remove all the markers that are still visible
		for (var k in visible)
			map.removeOverlay(visible[k])
	}
}

Object.extend(Me.prototype, myProto)

})();


;(function(){

var Me = Papa.Controller

var myProto = 
{
	moved: function (center, zoom, sw, ne)
	{
		this.parent.dispatchEvent({type:'moved', center:center, zoom:zoom, sw:sw, ne:ne})
	},
	
	apiLoaded: function () { this.model.apiLoaded(); this.parent.apiLoaded() }
}

Object.extend(Me.prototype, myProto)

})();


;(function(){

var Me = Papa.Model

var myProto =
{
	initialize: function ()
	{
		this.points = []
		this.count = 0
	},
	
	apiLoaded: function ()
	{
		this.view.setCenter(this.center, this.zoom)
		this.view.renderPoints(this.points)
	},
	
	setCenter: function (center, zoom)
	{
		this.center = center
		this.zoom = zoom
		this.view.setCenter(center, zoom)
	},
	
	setPoints: function (points)
	{
		if (!this.parent.dispatchEvent({type:'pointsSet', points: points}))
			return
		
		var count = this.count
		for (var i = 0, il = points.length; i < il; i++)
		{
			var point = points[i]
			if (!point.mapPointId)
				point.mapPointId = ++count
		}
		this.count = count
		
		this.points = points
		this.view.renderPoints(points)
	}
}

Object.extend(Me.prototype, myProto)

})();


})();
;(function(){

var myName = 'MapLightMarker'

function Me () {}

eval(NodesShortcut.include())

Me.prototype = new Map.Overlay()

var myProto =
{
	initialize: function (map)
	{
		var ll = this.ll
		this.latlng = new this.api.LatLng(ll.lat, ll.lng)
		
		var node = this.node || (this.node = this.createNode())
		map.getPane(G_MAP_MARKER_PANE).appendChild(node)
		this.map = map
	},
	
	createNode: function ()
	{
		return Nct('div', 'point', 'createNode() is not implemented')
	},
	
	redraw: function (force)
	{
		if (!force)
			return
		
		var sw = this.map.fromLatLngToDivPixel(this.latlng)
		
		var style = this.node.style
		style.left = sw.x + 'px'
		style.top = sw.y + 'px'
	},
	
	remove: function ()
	{
		this.node.remove()
	}
}

Object.extend(Me.prototype, myProto)

self[myName] = Me
Me.className = myName

})();


window.googleApiLoader = new GoogleApiLoader
({
	'inshaker.ru': 'ABQIAAAARQzYWu9IpurDSJW9DIJqrxRkBrAtdI-gKvPAeDorTK26GBT4DBTWsZV4qSbs-J27hgsqukt5Ef_TCg',
	'programica.ru':  'ABQIAAAARQzYWu9IpurDSJW9DIJqrxQVF992HTeapfH7j2YfASPwC0rg6BRLdvrEuTsIejJP0tsK0O0WOScMCw'
}, location.host, 'ru')


;(function(){

var myName = 'BarPoint'

function Me (bar)
{
	this.bar = bar
	this.ll = {lat: bar.point[0], lng: bar.point[1]}
	this.nodes = {}
}

Me.prototype = new MapLightMarker()

eval(NodesShortcut.include())

function stopPropagation (e) { e.stopPropagation() }

var myProto =
{
	ll: {lat: 0, lng: 0},
	
	createNode: function ()
	{
		return this.node || (this.node = this.getNode())
	},
	
	getNode: function ()
	{
		var nodes = this.nodes,
			bar = this.bar
		
		var main = nodes.main = Nc('div', 'point')
		main.addEventListener('mousedown', stopPropagation, false)
		
		var icon = nodes.icon = main.appendChild(Nc('a', 'icon'))
		icon.href = this.bar.pageHref()
		
		var title = nodes.title = main.appendChild(Nc('dl', 'title'))
		
		var name = nodes.name = title.appendChild(Nct('dt', 'point-name', bar.name))
		
		var contacts = bar.contacts
		if (contacts)
		{
			nodes.address = title.appendChild(Nct('dd', 'address', contacts.address))
			nodes.tel = title.appendChild(Nct('dd', 'tel', contacts.tel))
		}
		
		return main
	}
}

Object.extend(Me.prototype, myProto)

Me.className = myName
self[myName] = Me

})();

function BarsPageModel ()
{
	BarsPageModel.name = "BarsPageModel"
	this.constructor = BarsPageModel
	this.initialize.apply(this, arguments)
}

BarsPageModel.prototype =
{
	initialize: function () { },
	
	setState: function (state)
	{
		state = Object.copy(state)
		
		var cities = Bar.getCities(state)
		if (!state.city)
			state.city = cities[0]
		
		if (state.bar)
			state.bar = Bar.getByCityName(state.city, state.bar)
		
		var barsSet = Bar.getByQuery(state)
		
		var now = new Date(), hYearMs = 3600 * 24 * (366 / 4) * 1000,
			neo = [], normal = [], future = []
		
		for (var i = 0, il = barsSet.length; i < il; i++)
		{
			var bar = barsSet[i]
			var openDate = bar.openDate ? now - new Date(bar.openDate) : - 1
			if (openDate < 0) //// fill bars what opened in future
			{
				bar.labelType = 'future'
				future.push(bar)
			}
			else if (openDate < hYearMs) //// fill new bars
			{
				bar.labelType = 'new'
				neo.push(bar)
			}
			else //// other bars are neither 'new' nor 'future'
			{
				normal.push(bar)
			}
		}
		barsSet = neo.concat(normal, future)
		
		var city = City.getByName(state.city)
		var view = this.view
		view.modelChanged({bars: barsSet, state: state, city: city})
		view.renderTitle(Cocktail.getByName(state.cocktail))
		view.renderCities(cities, state.city)
		view.renderFormats(Bar.getFormats(state), state.format)
		view.renderFeels(Bar.getFeels(state), state.feel)
	}
}

function BarsPageController ()
{
	BarsPageController.name = "BarsPageController"
	this.constructor = BarsPageController
	this.initialize.apply(this, arguments)
}

BarsPageController.prototype =
{
	state: {city: undefined, format: undefined, feel: undefined},
	
	initialize: function (state)
	{
		this.state = Object.copy(state)
		this.emptyState = Object.copy(state)
	},
	
	hashUpdated: function (hash)
	{
		var state = this.state
		if (hash)
			Object.extend(state, hash)
		else
			state = this.state = Object.copy(this.emptyState)
		
		this.view.setHash(state)
		this.view.setViewType(state.view)
		this.model.setState(state)
	},
	
	mapMoved: function (ll, zoom)
	{
		var state = this.state
		state.zoom = zoom
		state.lat = Math.round(ll.lat * 10000) / 10000
		state.lng = Math.round(ll.lng * 10000) / 10000
		this.view.setHash(state)
	},
	
	showAllBars: function ()
	{
		this.cocktailSelected()
	},
	
	viewTypeSwitched: function (type)
	{
		this.state.view = type
		this.view.setHash(this.state)
		this.model.setState(this.state)
	},
	
	cocktailSelected: function (val)
	{
		var state = this.state
		state.cocktail = val
		state.city = state.format = state.feel = undefined
		this.view.setHash(state)
		this.model.setState(state)
	},
	citySelected: function (val)
	{
		var state = this.state
		delete state.bar
		state.city = val
		state.format = undefined
		state.feel = undefined
		this.view.setHash(state)
		this.model.setState(state)
	},
	formatSelected: function (val)
	{
		var state = this.state
		state.format = val
		state.feel = undefined
		this.view.setHash(state)
		this.model.setState(state)
	},
	feelSelected: function (val)
	{
		this.state.feel = val
		this.view.setHash(this.state)
		this.model.setState(this.state)
	}
}


function BarsPageView ()
{
	BarsPageView.name = "BarsPageView"
	this.constructor = BarsPageView
	this.initialize.apply(this, arguments)
}

BarsPageView.prototype =
{
	initialize: function (controller, nodes)
	{
		this.controller = controller
		this.nodes = nodes
		this.cache = {barNode: {}}
		
		var me = this
		
		var ts = this.viewTypeSwitcher = new TabSwitcher()
		ts.bind({tabs: nodes.viewSwitcherButtons, sections:[this.nodes.barsContainer, this.nodes.map]})
		ts.addEventListener('select', function (e) { me.setViewNum(e.data.value) }, false)
		
		var s = this.formatSelecter = new Selecter()
		s.bind(nodes.formatSelecter)
		s.addEventListener('select', function (e) { controller.formatSelected(e.data.value) }, false)
		
		var s = this.feelSelecter = new Selecter()
		s.bind(nodes.feelSelecter)
		s.addEventListener('select', function (e) { controller.feelSelected(e.data.value) }, false)
		
		var s = this.citySelecter = new Selecter()
		s.bind(nodes.citySelecter)
		s.addEventListener('select', function (e) { controller.citySelected(e.data.value) }, false)
		
		nodes.titleSearchAll.addEventListener('mousedown', function () { controller.showAllBars({}) }, false)
		
		nodes.moreInfo.addEventListener('click', function (e) { nodes.guidePopup.show() }, false)
		nodes.guidePopup.addEventListener('click', function (e) { nodes.guidePopup.hide() }, false)
		nodes.guidePopupBody.addEventListener('click', function (e) { e.stopPropagation() }, false)
	},
	
	checkHash: function ()
	{
		var hash = null,
			hashStr, winStr
		
		if (hashStr = location.hash.substr(1))
			hash = UrlEncode.parse(hashStr)
		else if (winStr = WindowName.get('bars:state'))
			hash = UrlEncode.parse(winStr)
		
		this.controller.hashUpdated(hash)
	},
	
	setHash: function (hash)
	{
		var urledHash = UrlEncode.stringify(hash)
		location.hash = "#" + urledHash
		WindowName.set('bars:state', urledHash)
	},
	
	modelChanged: function (data)
	{
		this.renderBars(data)
	},
	
	setViewNum: function (type)
	{
		this.setViewType(type)
		this.controller.viewTypeSwitched(type)
	},
	
	setViewType: function (type)
	{
		this.viewTypeSwitcher.renderSelected(type)
	},
	
	renderCities: function (options, selected)
	{
		var s = this.citySelecter
		s.setOptions(options)
		if (selected)
			s.renderSelectedValue(selected)
		else
			s.renderSelected(0)
	},
	
	renderFormats: function (options, selected)
	{
		var s = this.formatSelecter
		s.setOptions(options)
		if (selected)
			s.renderSelectedValue(selected)
		else
			s.renderSelected(0)
	},
	
	renderFeels: function (options, selected)
	{
		var s = this.feelSelecter
		s.setOptions(options)
		if (selected)
			s.renderSelectedValue(selected)
		else
			s.renderSelected(0)
	},
	
	renderBars: function (data)
	{
		var state = data.state
		if (!state.view || state.view == 'list')
			return this.renderBarsList(data)
		else if (state.view == 'map')
			return this.renderBarsMap(data)
		else
			log('Unknown view type "' + state.view + '"')
	},
	renderBarsList: function (data)
	{
		var parent = this.nodes.barsContainer,
			bars = data.bars
		
		parent.empty()
		for (var i = 0; i < bars.length; i++)
		{
			var bar = bars[i]
			var node = this.getBarNode(bar)
			parent.appendChild(node)
			parent.appendChild(document.createTextNode(' '))
		}
	},
	renderBarsMap: function (data)
	{
		var bars = data.bars,
			state = data.state,
			city = data.city
		
		this.initMap()
		var map = this.map
		
		
		var points = []
		for (var i = 0; i < bars.length; i++)
		{
			var bar = bars[i]
			bar.mapPoint = points[i] = new BarPoint(bar)
		}
		map.setPoints(points)
		
		var current = state.bar
		if (current && current.mapPoint)
		{
			var node = current.mapPoint.createNode()
			node.addClassName('selected')
		}
		
		if (this.lastCity != state.city)
		{
			var lat, lng, zoom
			if (!this.lastCity && state.lat && state.lng)
			{
				lat = parseFloat(state.lat)
				lng = parseFloat(state.lng)
				zoom = parseInt(state.zoom) || 10
			}
			else if (current)
			{
				var point = current.point
				lat = point[0]
				lng = point[1]
				zoom = 17
			}
			else
			{
				var point = city.point
				lat = point[0]
				lng = point[1]
				zoom = city.zoom || 10
			}
			
			map.setCenter({lat: lat, lng: lng}, zoom)
			this.lastCity = state.city
		}
	},
	
	initMap: function ()
	{
		if (this.map)
			return
		
		var map = this.map = new Map(),
			nodes = this.nodes
		
		map.bind({main: nodes.mapSurface, wrapper: nodes.map, control: nodes.positionControl})
		var controller = this.controller
		map.addEventListener('moved', function (e) { controller.mapMoved(e.center, e.zoom) }, false)
	},
	
	renderTitle: function (cocktail)
	{
		var nodes = this.nodes
		if (cocktail)
		{
			nodes.titleAll.hide()
			nodes.titleSearch.show()
			var nameNode = nodes.titleSearchName
			nameNode.innerHTML = cocktail.nameVP || cocktail.name
			nameNode.href = '/cocktails/' + cocktail.name_eng.htmlName() + '.html'
		}
		else
		{
			nodes.titleSearch.hide()
			nodes.titleAll.show()
		}
	},
	
	getBarNode: function (bar)
	{
		var main = this.cache.barNode[bar.id] || (this.cache.barNode[bar.id] = this.createBarNode(bar))
		main.setName(bar.name)
		main.setImage(bar.smallImageHref())
		main.setHref(bar.pageHref())
		return main
	},
	
	createBarNode: function (bar)
	{
		var main = document.createElement('li'),
			nameCont = document.createElement('a'),
			name = document.createElement('span')
		
		name.className = 'bar-name'
		name.innerHTML = bar.name
		
		nameCont.appendChild(name)
		main.appendChild(nameCont)
		
		main.className = 'bar-mini'
		main.setImage = function (src) { main.style.backgroundImage = 'url('+src+')' }
		main.setName = function (text) { name.innerHTML = text }
		main.setHref = function (href) { nameCont.href = href }
		
		if (bar.labelType == 'new')
		{
			var label = document.createElement('span')
			label.className = 'label'
			label.innerHTML  = 'Бар недавно открылся, заходи посмотреть!'
			nameCont.appendChild(label)
			main.addClassName(bar.labelType)
		}
		
		return main
	}
}



// beta :)
var LocationHash =
{
	onchange: function () {  },
	bind: function (loc)
	{
		this.location = loc
		this.lastHash = this.location.hash
		
		var me = this
		function check ()
		{
			if (me.location.hash != me.lastHash)
			{
				me.lastHash = me.location.hash
				me.onchange(me.get(), me.last)
			}
		}
		
		setInterval(check, 500)
		document.addEventListener('click', function () { setTimeout(check, 50) }, true)
	},
	
	set: function (val)
	{
		this.location.hash = this.last = String(val)
		this.lastHash = this.location.hash
	},
	
	get: function ()
	{
		return this.location.hash.replace(/^#/, '')
	}
}

var WindowName =
{
	get: function (key)
	{
		var hash = UrlEncode.parse(decodeURIComponent(window.name))
		return hash ? hash[key] : undefined
	},
	
	set: function (key, val)
	{
		var hash = UrlEncode.parse(decodeURIComponent(window.name)) || {}
		hash[key] = val
		window.name = encodeURIComponent(UrlEncode.stringify(hash))
		return val
	},
	
	clear: function () { window.name = "" }
}
