BarPage =
{
	initialize: function (nodes, barsDB, cocktailsDB)
	{
		this.view.owner = this
		this.controller.owner = this
		this.model.owner = this
		
		this.view.initialize(nodes)
		this.model.initialize(barsDB, cocktailsDB)
		
		this.view.readBarCityNames()
	}
}

$.onready
(
	function ()
	{
		var nodes =
		{
			photos:
			{
				root:            $$('.b-content .photos')[0],
				viewport:        $$('.b-content .photos .viewport')[0],
				surface:         $$('.b-content .photos .surface')[0],
				prev:            $$('.b-content .photos .prev')[0],
				next:            $$('.b-content .photos .next')[0],
				items:           $$('.b-content .photos .point')
			},
			carte:
			{
				root:            $$('#carte')[0],
				viewport:        $$('#carte .viewport')[0],
				surface:         $$('#carte .surface')[0],
				prev:            $$('#carte .prev')[0],
				next:            $$('#carte .next')[0]
			},
			barName: $('bar-name'),
			cityName: $('city-name'),
			showMore: $$('.about .show-more')[0],
			barMore: $$('.about .more')[0],
			map: $('map'),
			positionControl: $$('.position-control')[0],
			barPrev: $$('.b-title .hrefs .prev')[0],
			barNext: $$('.b-title .hrefs .next')[0]
		}
		RoundedCorners.round(nodes.photos.root)
		BarPage.initialize(nodes, Bar, Cocktail)
	}
)

;(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 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

})();

BarPage.model =
{
	owner: null, // must be defined before initialize
	
	initialize: function () { },
	
	getCocktailsByNames: function (arr)
	{
		var res = []
		for (var i = 0; i < arr.length; i++)
			res[i] = Cocktail.getByName(arr[i])
		return res
	},
	
	getPrevNext: function (name, query)
	{
		query = query || {}
		
		var bars = Bar.getByQuery(query)
		if (!bars)
			return []
		
		for (var i = 0; i < bars.length; i++)
			if (bars[i].name == name)
				return [bars[i-1], bars[i+1]]
		
		return []
	},
	
	setQuery: function (query)
	{
		var bar = Bar.getByCityName(query.city, query.name)
		if (bar)
		{
			var data =
			{
				bar: bar,
				carte: this.getCocktailsByNames(bar.carte),
				otherBarsSet: Bar.getAllByCity(query.city),
				prevNext: this.getPrevNext(query.name, {city: query.city, format: query.format, feel: query.feel})
			}
			
			this.owner.view.modelChanged(data)
		}
	}
}
BarPage.controller =
{
	owner: null, // must be defined before initialize
	
	initialize: function ()
	{
		
	},
	
	barCityNamesLoaded: function (state)
	{
		this.cityName = state.city
		this.barName = state.name
		this.owner.model.setQuery(state)
	},
	
	toggleMoreClicked: function ()
	{
		this.owner.view.toggleMore()
	},
	
	moreIsMaximized: function () {  },
	moreIsMinimized: function () {  }
}
{(function(){

var doc = document
function N (name) { return doc.createElement(name) }
function T (text) { return doc.createTextNode(text) }

BarPage.view =
{
	owner: null, // must be defined before initialize
	
	initialize: function (nodes)
	{
		this.nodes = nodes
		
		this.renderPhotos()
		
		var barMore = nodes.barMore
		if (barMore)
		{
			barMore.maximize = function () { this.animate('easeOutQuad', {height: this.scrollHeight}, 1) }
			barMore.minimize = function () { this.animate('easeOutQuad', {height: 1}, 1) }
			barMore.toggleHeight = function ()
			{
				if (this.isMaximized)
				{
					this.minimize()
					return this.isMaximized = false
				}
				else
				{
					this.maximize()
					return this.isMaximized = true
				}
			}
		}
		
		var controller = this.owner.controller
		nodes.showMore.addEventListener('click', function () { controller.toggleMoreClicked() }, false)
		
		nodes.barPrev.hide = nodes.barNext.hide = function () { this.addClassName('hidden') }
	},
	
	renderPhotos: function ()
	{
		var photos = this.nodes.photos,
			items = photos.items
		
		var total = items.length
		if (total > 1)
			photos.surface.appendChild(items[0].cloneNode(true))
		
		var list = new LazyList()
		list.bind(photos)
		list.configure({pageLength: 1, friction: 100, pageVelocity: 37.5, soft: Infinity, min: 75, max: 100})
		list.load = function (nodes)
		{
			for (var i = 0, il = nodes.length; i < il; i++)
			{
				// buggy in Firefox
				// var image = nodes[i].firstChild
				// if (!image.src)
				// 	image.src = image.getAttribute('data-lazy-src')
			}
		}
		list.setNodes(items, total)
	},
	
	modelChanged: function (data)
	{
		var nodes = this.nodes
		
		// bar
		this.bar = data.bar
		
		// cocktails
		this.renderCocktails(data.carte)
		this.renderMap(data.bar, data.otherBarsSet)
		this.renderPrevNext(data.prevNext)
	},
	
	readBarCityNames: function ()
	{
		var nodes = this.nodes,
			barName = nodes.barName.innerHTML,
			cityName = nodes.cityName.innerHTML
		
		var state = {}
		state.name = barName
		state.city = cityName
		
		this.owner.controller.barCityNamesLoaded(state)
	},
	
	toggleMore: function ()
	{
		var barMore = this.nodes.barMore
		if (barMore)
		{
			var miximized = barMore.toggleHeight()
			this.owner.controller[miximized ? 'moreIsMaximized' : 'moreIsMinimized']()
		}
	},
	
	initMap: function (bar)
	{
		if (this.map)
			return
		
		var map = this.map = new Map(),
			nodes = this.nodes
		
		map.bind({main: this.nodes.map, control: nodes.positionControl})
	},
	
	renderMap: function (current, bars)
	{
		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 node = current.mapPoint.createNode()
		node.addClassName('selected')
		map.setCenter({lat: current.point[0], lng: current.point[1]}, 13)
	},
	
	renderCocktails: function (cocktails)
	{
		var listNodes = this.nodes.carte
		
		var clNodes =
		{
			root: listNodes.root,
			viewport: listNodes.viewport,
			surface: listNodes.surface,
			prev: listNodes.prev,
			next: listNodes.next
		}

		var cl = new CocktailList()
		cl.bind(clNodes)
		cl.configure({pageLength: 5, pageVelocity: 36.5})
		cl.setCocktails(cocktails)
	},
	
	renderPrevNext: function (prevNext)
	{
		if (prevNext[0])
		{
			this.nodes.barPrev.href = prevNext[0].pageHref()
			this.nodes.barPrev.title = prevNext[0].name
		}
		else
			this.nodes.barPrev.hide()
		
		if (prevNext[1])
		{
			this.nodes.barNext.href = prevNext[1].pageHref()
			this.nodes.barNext.title = prevNext[1].name
		}
		else
			this.nodes.barNext.hide()
	}
}

})()}

