MagazinePage =
{
	initialize: function (nodes)
	{
		var params = {
"cocktails":{"author":[[],["Пьяное золото","Цитрусовый бурбон","Валенсианская вода в кувшине","Гранатовый тини","Томми Ди сауэр","Мастер и Маргарита","Вишня и вишня","Ред дресс","Гейша мартини","Бразильский лимонад","Южный морской бриз","Наоми","Эволюшен","Тыкван до","Чувство","Дрим дайкири меренги","Олдбой","Фокси леди шутер","Антонио","Голубичный коллинз","Самоан фог каттер 2","Лонг берри айс ти","Егерь с огурцом","Любимый","Старомодный на цедре","Асаи сауэр","Горько-сладкая симфония 2","Красная Москва","Белый бунгало","Бубен шотов","№1","Твою мать","Потенциале спешл","Тея","Карма","Виски сауэр Моджо","Падение миссионера","Кумкват ти","Штырлиц","Диксиленд смэш","Секретный пунш","Счастливый билет","Чайна ред гимлет","Куба либре","Блэк саббат"]],"classic":[[],["Кровавая Мэри","Мятный джулеп","Старомодный","Московский мул","Лошадиная шея","Космополитен","Сингапурский слинг","Ирландский кофе","Драй мартини","Дайкири","Американо","Белый русский","Негрони","Черный русский","Кайпиринья","Ржавый гвоздь","Бренди Александр","Бронкс","Кровь и песок","Белая леди","Сайдкар","Френч 75","Кловер клаб","Кузнечик","Сазерак","Писко сауэр","Писко пунш","Ураган","Беллини","Маргарита","Том коллинз","Джек Роуз","Манхэттен","Рамос джин физ"]],"pop":[[],["Лонг айленд айс ти","Мохито","Текила санрайз","Самбука","Виски кола","Джин тоник","Кейп Кодер","Б-52","Кайпиринья","Секс на пляже","Грог","Космополитен","Май тай","Кровавая Мэри","Зомби","Глинтвейн","Водка мартини","Дайкири","Голубая лагуна","Ирландский кофе","Кир Рояль","Текила бум","Отвертка","Гарибальди","Белый русский","Драй мартини"]],"special":[[],["Джин тоник"]]},
"promos":[{"name":"Brand Beefeater","html_name":"brand-beefeater","href":"/cocktail/gin_tonic/"},{"name":"Knowledge ICE","html_name":"knowledge-ice","href":"/combinator.html#q%3DЛед%20в%20кубиках%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Brand Baileys","html_name":"brand-baileys","href":"/combinator.html#q%3DАйриш%20крим%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Combinator Absinth and Pineapple Juice","html_name":"combinator-absinth-and-pineapple-juice","href":"http://www.inshaker.ru/cocktail/absinth_and_pineapple/"},{"name":"Brand Grand Marnier","html_name":"brand-grand-marnier","href":"/cocktail/grand_o/"},{"name":"Brand Johnnie Walker","html_name":"brand-johnnie-walker","href":"/combinator.html#q=Виски&s=increasing-complexity&y=0"},{"name":"Cocktail Whisky Apple Juice","html_name":"cocktail-whisky-apple-juice","href":"/cocktail/whisky_with_apple_juice/"},{"name":"Brand Martini","html_name":"brand-martini","href":"/combinator.html#q=Мартини&s=increasing-complexity&y=0"},{"name":"Combinator Tequila Celery Honey","html_name":"combinator-tequila-celery-honey","href":"/combinator.html#q=Текила%20+%20Сельдерей%20+%20Мед&s=increasing-complexity&y=0"},{"name":"Combinator Gin Lime Raspberry","html_name":"combinator-gin-lime-raspberry","href":"/combinator.html#q=Джин%20+%20Лайм%20+%20Свежемороженая%20малина&s=increasing-complexity&y=0"},{"name":"Brand Perrier","html_name":"brand-perrier","href":"/combinator.html#q%3DСодовая%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Knowledge Kaemka","html_name":"knowledge-kaemka","href":"/cocktail/golden_margarita/"},{"name":"Combinator Vodka Lime Grape","html_name":"combinator-vodka-lime-grape","href":"http://www.inshaker.ru/combinator.html#q=Водка%20+%20Лайм%20+%20Виноград&s=increasing-complexity&y=0"},{"name":"Brand Bacardi OakHeart","html_name":"brand-bacardi-oakheart","href":"/cocktail/spice_and_ice/"},{"name":"Brand Olmeca","html_name":"brand-olmeca","href":"/combinator.html#q%3DЗолотая%20текила%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Brand Bushmills","html_name":"brand-bushmills","href":"/combinator.html#q%3DВиски%20ирландский%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Brand Malibu","html_name":"brand-malibu","href":"/combinator.html#q%3DМалибу%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Combinator Rum Ice Cream","html_name":"combinator-rum-ice-cream","href":"/combinator.html#q=ром%20+%20Мороженое&s=increasing-complexity&y=0"},{"name":"Brand Pere Magloire","html_name":"brand-pere-magloire","href":"/combinator.html#q%3DКальвадос%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Brand Monin","html_name":"brand-monin","href":"/combinator.html#q%3DСироп%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Combinator Calvados Lavender","html_name":"combinator-calvados-lavender","href":"/combinator.html#q=Кальвадос%20+%20Сироп%20лаванды&s=increasing-complexity&y=0"},{"name":"Brand De Kuyper Peachtree","html_name":"brand-de-kuyper-peachtree","href":"/combinator.html#q%3DПерсиковый%20ликер%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Brand Antica","html_name":"brand-antica","href":"/combinator.html#q%3DВкусовая%20самбука%20%26s%3Dincreasing-complexity%26y%3D0"},{"name":"Brand Absolut","html_name":"brand-absolut","href":"/combinator.html#q=Absolut"}],
"tags":["Авторские хиты","Алкогольные","Безалкогольные","Белые","Глинтвейны","Все коктейли","Голубые","Желтые","Зеленые","Классические","Компоты","Кофейные","Красные","Лимонады","Миксы","Милкшейки","Морсы","На компанию","Необычная подача","Оранжевые","Подача","Поджигают","Прозрачные","Просто приготовить","Разноцветные","Розовые","Самые популярные","Сливочные","Согревающие","Фреши","Фруктовые","Шоты","Ягодные","В шейкере","Давят мадлером","В блендере","Укладывают слоями","Готовят на огне","Смешивают в стакане","Маргариты","Дайкири","Мохито","Наливки","Сангриты и чейзеры","Гроги","Победители"]
}
		var model       = this.model         = new MagazinePageModel(params)
		var controller  = this.controller    = new MagazinePageController()
		var view        = this.view          = new MagazinePageView(nodes)
		
		model.view = view
		controller.view = view
		controller.model = model
		view.controller = controller
		
		view.start()
	}
}

$.onready
(
	function ()
	{
		var nodes =
		{
			cocktails: $$('.info-blocks .cocktail-list'),
			tagsList: $$('#tags-list')[0],
			promo: $('promo'),
			arrows:[$$('#promo-prev')[0], $$('#promo-next')[0]]
		}
		
		MagazinePage.initialize(nodes)
	}
)

;(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 M = Math, myName = 'Motion', globalTimer = GlobalTimer
function Me (begin, end, duration, motion, onstep, onstop)
{
	var me = this, frame = 0, total = M.ceil(duration * globalTimer.fps), delta = end - begin
	
	this.onstop = onstop
	this.onstep = onstep
	this.step = function ()
	{
		me.onstep(motion(frame, begin, delta, total))
		if (frame++ >= total)
			me.stop(true)
	}
	
}

Me.prototype =
{
	start: function ()
	{
		if (!this.running)
		{
			this.running = true
			globalTimer.remove(this.timer)
			this.timer = globalTimer.add(this.step) // step is already a prepared callback
		}
		return this
	},
	
	stop: function (comleted)
	{
		if (this.running)
		{
			this.running = false
			globalTimer.remove(this.timer)
			if (this.onstop)
				this.onstop(comleted)
		}
		return this
	}
}

self[myName] = Me

})();

// ============================================================================================
// Easing Equations v2.0
// September 1, 2003
// (c) 2003 Robert Penner, all rights reserved. 
// This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html.
// Ported to JavaScript by Peter Leonov for Liby.js motion ability
// ============================================================================================
Motion.types=
(function(){var M=Math,e=M.cos,f=M.sin,g=M.sqrt,h=M.PI,i=M.pow,j=M.abs,k=M.asin,l={directJump:function(t,b,c,d){return c},linearTween:function(t,b,c,d){return c*t/d+b},easeInQuad:function(t,b,c,d){return c*(t/=d)*t+b},easeOutQuad:function(t,b,c,d){return-c*(t/=d)*(t-2)+b},easeInOutQuad:function(t,b,c,d){return((t/=d/2)<1)?c/2*t*t+b:-c/2*((--t)*(t-2)-1)+b},easeInCubic:function(t,b,c,d){return c*(t/=d)*t*t+b},easeOutCubic:function(t,b,c,d){return c*((t=t/d-1)*t*t+1)+b},easeInOutCubic:function(t,b,c,d){return((t/=d/2)<1)?c/2*t*t*t+b:c/2*((t-=2)*t*t+2)+b},easeInQuart:function(t,b,c,d){return c*(t/=d)*t*t*t+b},easeOutQuart:function(t,b,c,d){return-c*((t=t/d-1)*t*t*t-1)+b},easeInOutQuart:function(t,b,c,d){return((t/=d/2)<1)?c/2*t*t*t*t+b:-c/2*((t-=2)*t*t*t-2)+b},easeInQuint:function(t,b,c,d){return c*(t/=d)*t*t*t*t+b},easeOutQuint:function(t,b,c,d){return c*((t=t/d-1)*t*t*t*t+1)+b},easeInOutQuint:function(t,b,c,d){return((t/=d/2)<1)?c/2*t*t*t*t*t+b:c/2*((t-=2)*t*t*t*t+2)+b},easeInSine:function(t,b,c,d){return-c*e(t/d*(h/2))+c+b},easeOutSine:function(t,b,c,d){return c*f(t/d*(h/2))+b},easeInOutSine:function(t,b,c,d){return-c/2*(e(h*t/d)-1)+b},easeInExpo:function(t,b,c,d){return(t==0)?b:c*i(2,10*(t/d-1))+b},easeOutExpo:function(t,b,c,d){return(t==d)?b+c:c*(-i(2,-10*t/d)+1)+b},easeInCirc:function(t,b,c,d){return-c*(g(1-(t/=d)*t)-1)+b},easeOutCirc:function(t,b,c,d){return c*g(1-(t=t/d-1)*t)+b},easeInOutCirc:function(t,b,c,d){return((t/=d/2)<1)?-c/2*(g(1-t*t)-1)+b:c/2*(g(1-(t-=2)*t)+1)+b},easeInBounce:function(t,b,c,d){return c-l.easeOutBounce(d-t,0,c,d)+b},easeInOutExpo:function(t,b,c,d){if(t==0)return b;if(t==d)return b+c;if((t/=d/2)<1)return c/2*i(2,10*(t-1))+b;return c/2*(-i(2,-10*--t)+2)+b},easeInElastic:function(t,b,c,d,a,p){if(t==0)return b;if((t/=d)==1)return b+c;if(!p)p=d*.3;if(a<j(c)){var s=p/4;a=c}else s=p/(2*h)*k(c/a);return-(a*i(2,10*(t-=1))*f((t*d-s)*(2*h)/p))+b},easeOutElastic:function(t,b,c,d,a,p){if(t==0)return b;if((t/=d)==1)return b+c;if(!p)p=d*.3;if(a<j(c)){var s=p/4;a=c}else s=p/(2*h)*k(c/a);return a*i(2,-10*t)*f((t*d-s)*(2*h)/p)+c+b},easeInOutElastic:function(t,b,c,d,a,p){if(t==0)return b;if((t/=d/2)==2)return b+c;if(!p)p=d*(.3*1.5);if(a<j(c)){a=c;var s=p/4}else s=p/(2*h)*k(c/a);if(t<1)return-.5*(a*i(2,10*(t-=1))*f((t*d-s)*(2*h)/p))+b;else return a*i(2,-10*(t-=1))*f((t*d-s)*(2*h)/p)*.5+c+b},easeInBack:function(t,b,c,d,s){if(s==null)s=1.70158;return c*(t/=d)*t*((s+1)*t-s)+b},easeOutBack:function(t,b,c,d,s){if(s==null)s=1.70158;return c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},easeInOutBack:function(t,b,c,d,s){if(s==null)s=1.70158;if((t/=d/2)<1)return c/2*(t*t*(((s*=(1.525))+1)*t-s))+b;else return c/2*((t-=2)*t*(((s*=(1.525))+1)*t+s)+2)+b},easeOutBounce:function(t,b,c,d){if((t/=d)<(1/2.75))return c*(7.5625*t*t)+b;else if(t<(2/2.75))return c*(7.5625*(t-=(1.5/2.75))*t+.75)+b;else if(t<(2.5/2.75))return c*(7.5625*(t-=(2.25/2.75))*t+.9375)+b;else return c*(7.5625*(t-=(2.625/2.75))*t+.984375)+b},easeInOutBounce:function(t,b,c,d){if(t<d/2)return l.easeInBounce(t*2,0,c,d)*.5+b;else return l.easeOutBounce(t*2-d,0,c,d)*.5+c*.5+b}};return l})();
;(function () {

var M = Motion, myName = 'Animation'

function Me (node, motion, duration, trans, unit)
{
	this.node = node
	switch (typeof motion)
	{
		case 'string':
			var name = motion
			if (!(motion = M.types[name]))
				throw new Error('Unknown motion type name "' + name + '"')
			break
		case 'function':
			break
		default:
			throw new Error('Motion type must be a string or a function, got "' + typeof motion + '"')
	}
	this.motion = motion
	this.duration = duration
	this.trans = trans
	this.unit = unit
	this.running = false
	this.completed = 0
	this.motions = []
	
	var me = this
	function complete () { me.complete() }
	for (var i = 0; i < trans.length; i++)
	{
		var tr = trans[i]
		function bakeStep (tr)
		{
			return function (value)
			{
				Me.setStyleProperty(node, tr.property, value, unit)
			}
		}
		this.motions[i] = new M(tr.begin, tr.end, duration, motion, bakeStep(tr), complete)
	}
	
}

Me.defaults = {unit: 'px', motion: 'linearTween', duration: 1}

Element.prototype.animate = function (motion, props, duration, unit)
{
	var defaults = Me.defaults
	if (!motion)
		motion = defaults.motion
	if (!duration)
		duration = defaults.duration
	if (!unit)
		unit = defaults.unit
	
	var trans = []
	for (var k in props)
	{
		var prop = props[k]
		if (prop.length == 2)
			trans.push({property: k, begin: prop[0], end: prop[1]})
		else
			trans.push({property: k, begin: Me.getStyleProperty(this, k), end: prop[0] || prop})
	}
	return new Me(this, motion, duration, trans, unit).start()
}


Me.prototype =
{
	oncomplete: function () {},
	start: function ()
	{
		if (!this.running)
		{
			this.running = true
			
			var motions = this.motions
			for (var i = 0; i < motions.length; i++)
				motions[i].start()
		}
		return this
	},
	
	stop: function ()
	{
		if (this.running)
		{
			this.running = false
			
			var motions = this.motions
			for (var i = 0; i < motions.length; i++)
				motions[i].stop()
		}
		return this
	},
	
	complete: function ()
	{
		if (++this.completed >= this.motions.length)
			this.oncomplete()
	}
}

Me.getStyleProperty = function (node, p)
{
	if (p == "top" && !node.style[p])
		return node.offsetTop
	
	if (p == "left" && !node.style[p])
		return node.offsetLeft
	
	
	if (p == "opacity" && isNaN(parseFloat(node.style[p])))
		return 1
	
	
	if (/scroll/.test(p))
		return node[p]
	
	return parseFloat(node.style[p]) || 0
},

Me.setStyleProperty = function (node, p, value, unit)
{
	try
	{
		if (/color/.test(p))
			return node.style[p] = 'rgb(' + parseInt(value) + ',' + parseInt(value) + ',' + parseInt(value) + ')'
		
		// for SVG elements
		if (p == 'r')
			return node.r.baseVal.value = value
		
		
		if (/scroll/.test(p))
			return node[p] = Math.round(value)
		
		if (p == 'opacity')
			return node.style[p] = value
		
		if ((p == 'width' || p == 'height') && value < 0)
			value = 0
		
		if (unit == 'em')
			return node.style[p] = Math.round(value * 100) / 100 + unit
		
		return node.style[p] = Math.round(value) + unit
	}
	catch (ex)
	{
		log('setStyleProperty(' + arguments +'): ' + ex)
		return value
	}
}

self[myName] = Me

})();

function RollingImagesLite (node, conf)
{
	this.conf = {duration: 1, animationType: 'easeOutBack'}
	Object.extend(this.conf, conf)
	this.current = null
	this.mainNode = node
	this.mainNode.RollingImagesLite = this
	
	
	var t = this
	function mouseup (e)
	{
		e.preventDefault()
		clearInterval(t.svInt)
		document.removeEventListener('mouseup', mouseup, false)
	}
	
	this.prevmousedown = function (e)
	{
		e.preventDefault()
		clearInterval(t.svInt)
		t.goPrev()
		t.svInt = setInterval(function () { t.goPrev() }, t.conf.duration * 1000 * 0.5 + 150)
		document.addEventListener('mouseup', mouseup, false)
	}
	
	this.nextmousedown = function (e)
	{
		e.preventDefault()
		clearInterval(t.svInt)
		t.goNext()
		t.svInt = setInterval(function () { t.goNext() }, t.conf.duration * 1000 * 0.5 + 150)
		document.addEventListener('mouseup', mouseup, false)
	}
	
	this.sync()
	if (this.conf.goInit !== false)
		this.goInit()
}

RollingImagesLite.prototype =
{
	sync: function ()
	{
		this.viewport = this.my('viewport')[0]
		if (!this.viewport)
			throw new Error('Can`t find viewport for ' + this.mainNode)
		if (!this.viewport.animate)
			throw new Error('Viewport can`t be animated!')
		
		this.points = this.my('point')
		this.buttons = this.my('button')
		this.aPrev = this.my('prev')[0]
		this.aNext = this.my('next')[0]
		
		// if syncing when pushed
		clearInterval(this.svInt)
		
		var t = this
		if (this.aPrev)
			this.aPrev.addEventListener('mousedown', this.prevmousedown, false)
		
		if (this.aNext)
			this.aNext.addEventListener('mousedown', this.nextmousedown, false)
		
		for (var i = 0, il = this.buttons.length; i < il; i++)
			this.buttons[i].onmousedown = function (fi) { return function () { t.goToFrame(fi) } } (i)
		
		this.updateNavigation()
	},
	
	goPrev: function () { if (this.current > 0) this.goToFrame(this.current - 1) },
	goNext: function () { if (this.current < this.points.length - 1) this.goToFrame(this.current + 1) },
	my: function (cn) { return this.mainNode.getElementsByClassName(cn) },
	
	goInit: function ()
	{
		return this.goToFrame(0, 'directJump')
	},
	
	goToFrame: function (n, anim, dur) { return this.points ? this.goToNode(this.points[n || 0], anim, dur) : null },
	
	goToNode: function (node, anim, dur)
	{
		if (!node)
			return null
		
		if (this.mainNode.onjump)
			if (this.mainNode.onjump(node) === false)
				return null
		
		// change number of current node
		for (var i = 0, il = this.points.length; i < il; i++)
			if (this.points[i] == node)
				this.setCurrent(i)
		
		return this.animateTo(node.offsetLeft, node.offsetTop, anim, dur)
	},
	
	animateTo: function (left, top, anim, dur)
	{
		if (this.animation)
			this.animation.stop()
		return this.animation = this.viewport.animate(anim || this.conf.animationType, {scrollLeft: left, scrollTop: top}, dur || this.conf.duration)
	},
	
	jumpTo: function (left, top) { this.viewport.scrollLeft = left; this.viewport.scrollTop = top },
	jumpToFrame: function (n)
	{
		var node = this.points[n]
		if (node)
		{
			this.setCurrent(n)
			this.jumpTo(node.offsetLeft, node.offsetTop)
		}
	},
	
	updateNavigation: function ()
	{
		for (var i = 0, il = this.buttons.length; i < il; i++)
			this.buttons[i].removeClassName('selected-button')
		
		var button = this.buttons[this.current]
		if (button)
			button.addClassName('selected-button')
		
		if (this.aPrev)
		{
			if (this.current > 0)
				this.aPrev.removeClassName('disabled')
			else
				this.aPrev.addClassName('disabled')
		}
		
		if (this.aNext)
		{
			if (this.current < this.points.length - 1)
				this.aNext.removeClassName('disabled')
			else
				this.aNext.addClassName('disabled')
		}
	},
	
	setCurrent: function (num)
	{
    // if (num == this.current)
		//	return
		
		this.current = num
		this.updateNavigation()
		
		var cp = this.points[this.current]
		if (this.onselect)
			this.onselect(cp, this.current)
		
		if (cp && cp.onselect)
			cp.onselect()
	}
}


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

MagazinePageModel.prototype =
{
	initialize: function (params)
	{
		for(var key in params)
			this[key] = params[key]
	},
	
	setState: function (state)
	{
		var blocks = this.cocktails,
			cocktails = {}
		
		for (var k in blocks)
		{
			var block = blocks[k]
			
			var all = block[0].concat(block[1].slice().randomize())
			cocktails[k] = all.map(function (v) { return Cocktail.getByName(v) })
		}
		
		this.processTags(this.tags)
		
		var data =
		{
			cocktails: cocktails,
			promos: this.promos
		}
		
		this.view.modelChanged(data, state)
	},
	
	processTags: function (names)
	{
		var tags = []
		for (var i = 0, il = names.length; i < il; i++)
		{
			var name = names[i]
			
			var count = Cocktail.getByTag(name).length
			if (!count)
				continue
			
			var id = name.replace(/\s/, '-').toLowerCase()
			
			tags.push({name: name, count: count, id: id, link: {q: name}})
		}
		
		tags.sort(function (a, b) { return b.count - a.count })
		
		var all = tags[0]
		all.link.s = 'by-date'
		
		this.view.renderTags(tags)
	}
}

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

MagazinePageController.prototype =
{
	initialize: function () {},
	
	start: function ()
	{
		var hash = window.location.hash.replace(/^#/, '')
		hash = UrlEncode.parse(hash)
		this.model.setState({initFrame: hash.name})
	},
	
	updateHash: function (name)
	{
		window.location.hash = UrlEncode.stringify({name: name})
	}
}

;(function(){

eval(NodesShortcut.include())

var UrlEncodeLight = {}
Object.extend(UrlEncodeLight, UrlEncode)
UrlEncodeLight.encode = function (v) { return ('' + v).replace('&', '%26') }
UrlEncodeLight.decode = function (v) { return ('' + v).replace('%26', '&') }

function Me (nodes)
{
	this.nodes = nodes
	this.imagesLoaded = false
	this.switchBlock = false
	this.blockNames = ['special', 'pop', 'author', 'classic']
	
	new RollingImagesLite(nodes.promo, {animationType: 'easeInOutQuad', duration:0.75})
	
	var cocktails = nodes.cocktails
	for(var i = 0; i < cocktails.length; i++)
		new RollingImagesLite(cocktails[i], {animationType: 'easeOutQuad'})
}

Me.prototype =
{
	start: function ()
	{
		this.controller.start()
	},
	
	modelChanged: function (data, state)
	{
		this.renderPromo(this.nodes.promo, data.promos, 1, state)
		
		var cocktailNodes = this.nodes.cocktails,
			blockNames = this.blockNames,
			blocks = data.cocktails
		
		for (var i = 0, il = blockNames.length; i < il; i++)
			this.renderCocktails(cocktailNodes[i], blocks[blockNames[i]], 1)
	},
	
	_createCocktailElement: function (cocktail)
	{
		return cocktail.getPreviewNode()
	},
	
	_createLinkElement: function (link, links)
	{
		var li = document.createElement("li")
		var a  = document.createElement("a")
		a.href = link[1]
		var img = document.createElement("img")
		img.src = "/magazine/links/" + (links.indexOf(link) + 1) + ".png"
		var txt = document.createTextNode(link[0])
		a.appendChild(img)
		a.appendChild(txt)
		li.appendChild(a)
		return li
	},
	
	createPromoElement: function (promo)
	{
		var a  = document.createElement("a")
		a.href = promo.href
		var img = document.createElement("img")
		img.alt = promo.name
		img.setAttribute("lazy", "/magazine/promos/" + (promo.html_name) + ".jpg")
		a.appendChild(img)
		a.className = "point"
		return a
	},
	
	getPromoImages: function ()
	{
		return images = this.nodes.promo.getElementsByTagName("img")
	},
	
	loadFrames: function (list, onImageLoaded)
	{
		var images = this.getPromoImages()
		
		for (var i = 0; i < list.length; i++)
		{
			var img = images[list[i]]
			if (!img.src)
			{
				img.src = img.getAttribute("lazy")
				if (onImageLoaded)
					img.onload = onImageLoaded
			}
		}
	},
	
	getRange: function (initFrame)
	{
		var range = [initFrame]
		var images = this.getPromoImages()
		
		if (images[initFrame - 1])
			range.push(initFrame - 1)
		if (images[initFrame + 1])
			range.push(initFrame + 1)
		
		var l = images.length
		
		if (range.indexOf(1) > -1)
			range.push(l - 1) // first == last (fake)
		if (range.indexOf(l - 2) > -1)
			range.push(0) // last == first (fake)
		
		return range
	},
	
	loadInitialFrames: function (initFrame)
	{
		var me = this, counter = 0
		var range = this.getRange(initFrame)
		
		this.loadFrames
		(
			range,
			function ()
			{
				counter++
				if (counter == range.length)
					me.imagesLoaded = true
			}
		)
	},
	
	renderCocktails: function (node, set, len)
	{
		this.renderSet(node, set, len, this._createCocktailElement)
	},
	
	renderLinks: function (node, set, len)
	{
		this.renderSet(node, set, len, this._createLinkElement)
	},
	
	renderPromo: function (node, set, len, state)
	{
		var ri = node.RollingImagesLite
		var parent = node.getElementsByClassName('surface')[0]
		
		parent.empty()
		
		// One fake before the actual series, one after
		parent.appendChild(this.createPromoElement(set[set.length - 1]))
		for (var i = 0; i < set.length; i++)
			parent.appendChild(this.createPromoElement(set[i]))
		parent.appendChild(this.createPromoElement(set[0]))
		ri.sync()
		
		if (set.length > 1)
		{
			var len = ri.points.length, me = this
			// Jumping to avoid fakes
			function switchFrame (prev)
			{
				if (!me.switchBlock)
				{
					var cur = ri.current, after = cur
					
					me.switchBlock = true
					function switchUnblock () { me.switchBlock = false }
					function jumpToAfter () { ri.goToFrame(after, 'directJump'); switchUnblock() }
					function slideToAfter () { ri.goToFrame(after).oncomplete = switchUnblock }
					
					if (prev)
					{
						if (cur == 1)
						{
							after = len - 2
							ri.goToFrame(0).oncomplete = jumpToAfter
						}
						else
						{
							after = cur - 1
							slideToAfter()
						}
					}
					else
					{
						if (cur == len - 2)
						{
							after = 1
							ri.goToFrame(len - 1).oncomplete = jumpToAfter
						}
						else
						{
							after = cur + 1
							slideToAfter()
						}
					}
					
					var promo = set[after-1]
					Statistics.magazinePromoViewed(promo)
					me.controller.updateHash(promo.name)
					me.loadFrames(me.getRange(after))
				}
			}
			
			this.nodes.arrows[0].addEventListener('click', function (e) { switchFrame(true)  }, false)
			this.nodes.arrows[1].addEventListener('click', function (e) { switchFrame(false) }, false)
			
			var initFrame = state.initFrame
			for (var i = 0; i < set.length; i++)
				if (set[i].name == initFrame)
				{
					initFrame = i + 1
					break
				}
			
			if (!initFrame)
				initFrame = 1//Math.round(Math.random() * (len - 1)) + 1
			if (!this.getPromoImages()[initFrame])
				initFrame = 1
			
			this.loadInitialFrames(initFrame)
			ri.jumpToFrame(initFrame)
			
			// Wait for initial images to load and start switching
			var tries = 0
			var imageLoadTimer = setInterval
			(
				function ()
				{
					if (me.imagesLoaded || tries++ > 10)
						clearInterval(imageLoadTimer)
				},
				100
			)
		}
	},
	
	renderSet: function (node, set, len, renderFunction)
	{
		var parent = node.getElementsByClassName('surface')[0]
		parent.empty()
		for (var i = 0; i < set.length; i++)
		{
			if (i % len == 0)
			{
				var point = document.createElement('ul')
				point.className = 'point'
				parent.appendChild(point)
			}
			if (set[i])
				point.appendChild(renderFunction(set[i], set))
		}
		node.RollingImagesLite.sync()
	},
	
	renderTags: function (tags)
	{
		var list = this.nodes.tagsList
		
		list.empty()
		
		var columned = [], width = 4, height = Math.ceil(tags.length / width)
		for (var i = 0, il = tags.length; i < il; i++)
		{
			var x = (i / height) >> 0
			var y = i % height
			
			var tag = tags[i]
			columned[y * width + x] = tag
			if (y == height - 1 || i == il - 1)
				tag.bottom = true
		}
		
		for (var i = 0, il = columned.length; i < il; i++)
		{
			var tag = columned[i]
			
			if (!tag)
			{
				list.appendChild(Nc('span', 'space'))
				continue
			}
			
			var item = Nc('a', (tag.bottom ? 'item bottom' : 'item') + ' ' +  tag.id)
			list.appendChild(item)
			item.href = '/combinator.html#' + UrlEncodeLight.stringify(tag.link)
			
			var name = Nct('span', 'name', tag.name)
			item.appendChild(name)
			
			var icon = Nc('span', 'icon')
			item.appendChild(icon)
			
			var count = Nct('span', 'count', tag.count)
			item.appendChild(count)
		}
	}
}

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

})();

