// deep copy using JSON-like lib ;-)
function cloneObject(obj){
	return Object.parse(Object.stringify(obj));
}

function lengthOf(obj){
	var length = 0;
	for(prop in obj) length++;
	return length;
}

Array.prototype.uniq = function(){
	var tmp = [];
	for(var i = 0; i < this.length; i++){
		if(tmp.indexOf(this[i]) == -1) tmp.push(this[i]);
	}
	return tmp;
}


/**
 * Общие функции для компонентов, работающих с товарами (уровень view)
 */

Number.prototype.toFloatString = function(){
	if(this.toString() != parseInt(this)) return this.toString();
	return this + ".0";
}

var GoodHelper = {
    CART : 'cart',

    serializeCartData: function(cd) {
        for(var i = 0; i < cd.cocktails.length; i++){
			// cocktail -> name
			cd.cocktails[i][0] = cd.cocktails[i][0].name;
		}
		for(ingred in cd.goods){
			cd.goods[ingred].good = null;
		}
        return cd;
    },

	deSerializeCartData: function (cartData)
	{
		var dataCocktails = cartData.cocktails,
			cocktails = []
		for (var i = 0; i < dataCocktails.length; i++)
		{
			var cocktail = Cocktail.getByName(dataCocktails[i][0])
			if (cocktail)
				cocktails.push([cocktail, dataCocktails[i][1]])
		}
		
		var gds = {}
		for (var name in cartData.goods)
		{
			var good = Ingredient.getByName(name)
			if (good)
			{
				gds[name] = cartData.goods[name]
				gds[name].good = good
			}
		}
		
		return {cocktails: cocktails, goods: gds}
    },

    ingredientLink: function(ingred){
        return "/cocktails.html#state=byIngredients&ingredients=" + ingred;                
    },
     
	isBottled: function(good){
        if((good.volumes.length == 1) &&
            (good.unit == "шт") && (good.volumes[0][0] == 1)) return false;
        return true;
    },

    /**
	 * Возвращает числительное для данного объема
	 * @param vol - значение объема
	 * @param unit - единица измерения
	 */
	pluralTxt: function(vol, unit){
		if(unit == "кубики") return vol.plural("кубик", "кубика", "кубиков");
        if(unit == "штуки") return vol.plural("штука", "штуки", "штук");
        if(unit == "порция") return vol.plural("порция", "порции", "порций");
		return unit;
	},
	
    normalVolumeTxt: function(vol, unit){
        switch(unit){
            case "мл": if(vol >= 1000) { vol /= 1000; unit = "л";  }; break;
            case  "л": if(vol < 1)     { vol *= 1000; unit = "мл"; }; break;
              
            case "гр": if(vol >= 1000) { vol /= 1000; unit = "кг"; }; break;
            case "кг": if(vol < 1)     { vol *= 1000; unit = "гр"; }; break;
        }

        return vol + " " + unit;
    },

    normalVolumeTxtParsed: function(txt){
		var arr  = txt.match(/^(.+)\ (.+)/);
        return this.normalVolumeTxt(arr[1], arr[2]);
    },

	/**
	 * Возвращает предполагаемое название емкости
	 * для заданного ингредиента
	 * @param ingred - название ингредиента
	 * @param unit - единица измерения ингредиента
	 * @param {Number} vol - объем емкости
	 */
	bottleTxt: function(ingred, unit, vol){
		if(ingred == "Ред Булл") return "Банка ";
		if(ingred == "Кола") {
			if([0.33, 0.15].indexOf(vol) > -1) return "Банка ";
			return "Бутылка ";
		}
		if(unit == "л")     return "Бутылка ";
		if(ingred == "Лед") return "Пакетик ";
		return "";
	},
	
	/**
	 * Возвращает адрес картинки для товара по заданному
	 * названию ингредиента, объекту товара и элементу массива объемов товара
	 * @param name - название ингредиента
	 * @param good - объект товара
	 * @param vol - элемент массива объемов товара
	 */
	goodPicSrc: function(name, good, vol){
		if(!vol) { 
			var i = 0;
			while(!good.volumes[i][2]) i++;
			vol = good.volumes[i];
		}
		return good.getVolumeImage(vol)
	},
	
	getIngredText: function(name){
		var brand = Ingredient.getByName(name).brand || "";
		if(brand.indexOf(name) > -1) name = "";
		var gap = "";
		if(brand && name) gap = " ";
		return name + (brand ? gap + brand : "");
	},
	
	shortName: function(name){
		if(name == "Черносмородиновый ликер") return "Черносмородин. ликер";
		return name;
	}
};

;(function(){

function noop () {  }

Array.prototype.without = function(index) {
	var tmp = [];
	for(var i = 0; i < this.length; i++){
		if(i != index) tmp.push(this[i]);
	}
	return tmp;
}


self.DataFilter = {
	good_paths: [],
	
	/**
	 * Подбор товаров и их емкостей под коктейли
	 * @param goods - хэш товаров
	 * @param cocktailsAndQuant - массив вида [[<cocktail1>, <quantity1>], [<cocktail2>, <quantity2>]]
	 * @return хэш (ключ - ингредиент), включающий для каждого эл-та товар, дозировку, бутылки
	 */
	goodsByCocktails: function(goods, cocktailsAndQuant){
		var res = {};
		for(var i = 0; i < cocktailsAndQuant.length; i++){
			var cocktail = cocktailsAndQuant[i][0];
			var quantity = cocktailsAndQuant[i][1];
			var ingredients = Ingredient.mergeIngredientSets(cocktail.ingredients, cocktail.garnish)
			for(var j = 0; j < ingredients.length; j++){
				
				var ingred = ingredients[j][0];
				
				if(goods[ingred]) {
					var dose = this._parseDose(goods[ingred].unit, ingredients[j][1]);
					if(!res[ingred]) {
						res[ingred] = {};
						res[ingred].good = goods[ingred];
						res[ingred].bottles = {};
						res[ingred].dose = 0;
					}
					res[ingred].dose += dose*quantity;
				}
			}
		}
		
		// предлагаем бутылки
		for(ingred in res){
			var dose = res[ingred].dose;
			var vols = res[ingred].good.volumes;
			res[ingred].bottles = this.countOptimal(dose, vols);
		}
		return res;
	},
	
	countOptimal: function(max_vol, volumes){
		var vols = [], costs = [];
		var j = 0;
		for(var i = 0; i < volumes.length; i++) {
			if(volumes[i][2]) {
				vols[j] = volumes[i][0];
				costs[j] = volumes[i][1];
				j++;
			}
		}
		
		var vol_index = 0,
		vols_length = vols.length,
		biggest = vols[0],
		
		// calculating long tail
		tail = max_vol % (biggest * 2),
		big_bottles_count = Math.round((max_vol - tail) / biggest),
		
		stack = [],
		min = Infinity,
		the_one = [],
		answer = {}
		
		function walk (summ_vol, summ_cost, vols_length, vols, costs)
		{
			for (var i = 0; i < vols_length; i++)
			{
				var cost = costs[i],
				vol = vols[i],
				now_cost = summ_cost + cost,
				now_vol = summ_vol + vol
				
				if (now_cost >= min)
					continue
				
				stack[stack.length] = vol
				if (now_vol >= tail)
				{
					min = now_cost
					the_one = stack.slice()
					// console.info(now_vol, now_cost, stack.slice())
				}
				else
					walk(now_vol, now_cost, vols_length, vols, costs)
				stack.length--
			}
		}
		
		if (tail)
			walk(0, 0, vols_length, vols, costs)
		
		for (var i = 0; i < the_one.length; i++)
			if (answer[the_one[i]]){
				answer[the_one[i]].count++;
			} else {
				answer[the_one[i]] = {};
				answer[the_one[i]].count = 1;
			}
		
		if (big_bottles_count)
		{
			if (answer[biggest]) {
				answer[biggest].count += big_bottles_count;
			} else {
				answer[biggest] = {};
				answer[biggest].count = big_bottles_count;
			}
		}
		
		for(var i = 0; i < volumes.length; i++){
			noop() // for FF <= 3.5.2 with jit on
			var volume = volumes[i], val = volume[0]
			if(answer[val])
				answer[val].vol = volume;
		}
		
		return answer
	},
	
	bottleByIngredientAndVolume: function(goods, ingred, vol){
		var res = {};
		var volumes = goods[ingred].volumes;
		for(var i = 0; i < volumes.length; i++){
			if(volumes[i][0] == vol) {
				res.vol = volumes[i];
				break;
			}
		}
		return res;
	},
	
	cocktailsByLetter: function (set, letter){
		var res = [];	
		var reg = new RegExp("^(" + letter.toUpperCase() + ")");
		for(var i = 0; i < set.length; i++) {
			if(set[i].name.match(reg)){
				res.push(set[i]);
			}
		}
		return res;
	},
	
	cocktailsByTag: function (set, tag) {
		var res = [];
		for(var i = 0; i < set.length; i++){
			if(set[i].tags.indexOf(tag) > -1){
				res.push(set[i]);
			}
		}
		return res;
	},
	
	cocktailsByStrength: function(set, strength) {
		var res = [];
		for(var i = 0; i < set.length; i++){
			if(set[i].strength == strength) {
				res.push(set[i]);
			}
		}
		return res;
	},
	
	cocktailsByIngredients: function(set, ingredients) {
		var res = [];
		for(var i = 0; i < set.length; i++) {
			var good = 0;
			for(var j = 0; j < set[i].ingredients.length; j++) {
				for(var k = 0; k < ingredients.length; k++){
					if(set[i].ingredients[j][0] == ingredients[k]) good++;
				}
			}
			if(good == ingredients.length) res.push(set[i]);
		}
		return res;
	},
	
	nameSort: function(a, b){
		if(a.name > b.name) return 1;
		else if(a.name == b.name) return 0;
		else return -1;
	},
	
	/**
	 * Нормализация объема относительно заданной единицы
	 * @param normUnit - заданная единица (напр., "л")
	 * @param txt - текст объема (напр., "15 мл")
	 * @return нормализованное значение (напр., 0.015)
	 */
	_parseDose: function(normUnit, txt){
		var arr = txt.match(/^(.+)\ (.+)/);
		var vol = arr[1];
		var unit = arr[2];
		if(unit == "мл" && normUnit == "л") return vol/1000;
		else if((unit.indexOf("кубик") > -1) && normUnit == "кубиков") return parseInt(vol);
		else if(unit == "шт" && normUnit == "шт") return this._parseDecimal(vol);
		else if(unit == "капли" && normUnit == "л") return vol/40000;
		else if(unit == normUnit) return parseFloat(vol);
	},
	
	/**
	 * Парсинг значений объема, заданных в виде дробей
	 * @param volume - например, "1/2"
	 * @return число типа float наподобие 0.5
	 */
	_parseDecimal: function(volume){
		if(volume.indexOf("/") > -1) return eval(volume);
		else return parseFloat(volume);
	},
	
	/**
	 * Нахождение подходящей емкости по заданному объему
	 * @param volumes массив объемов вида [<емкость>, <цена>, <наличие>]
	 * @param dose объем, под который ищем емкость
	 * @return volume элемент массива объемов
	 */
	findClosestVol: function(volumes, dose){
		var closest_idx = 0;
		for(var i = 0; i < volumes.length; i++) {
			if((volumes[i][0] > volumes[closest_idx][0]) && volumes[i][2]) closest_idx = i;
		}
		for(var i = 0; i < volumes.length; i++){
			if(volumes[i][2]) { // в наличии
				var gap = volumes[i][0] - dose;
				var closestGap = volumes[closest_idx][0] - dose;
				if((gap >= 0) && (gap < closestGap)) closest_idx = i;
			}
		}
		return volumes[closest_idx];
	}
}

})();
/**
 * Реализация постоянного хранилища данных
 *
 * На основе библиотеки Storage.js v1.1
 * (c) 2008, Ilya Kantor (http://browserpersistence.ru)
 */

Storage = {
    swfUrl: "/js/common/storage.swf",    
    init: function(onready) {                
       	var browser = navigator.userAgent;
		var rx = Programica.userAgentRegExps;
		if(rx.Gecko.test(browser)) this.globalStorage(onready);
		else if(rx.MSIE.test(browser)) this.userData(onready);
		else this.flash8(onready); 
    }
};

/**
 * HTML5 standard
 * @browsers Firefox 2+, MSIE 8
 */
Storage.globalStorage = function(onready) {
    var storage = globalStorage[location.hostname];
    Storage = {
        get:    function(key)        { return storage[key] ? String(storage[key]) : null; },
        put:    function(key, value) { storage[key] = value; },
        remove: function(key)        { delete storage[key]; },    
        clear:  function()           { for(i in storage) delete storage[i]; },

        getKeys: function() {
            var res = [];
            for(i in storage) res.push(i);
            return res;
        }
    }
    onready();
};

/**
 * @browsers MSIE 5+
 */
Storage.userData = function(onready) {
    var namespace = "data";

    if (!document.body.addBehavior) {            
        throw new Error("No addBehavior available");
    }

	var e = document.createElement("iframe");
	e.setAttribute('id', 'storageFrame');
	e.style.border = '0';
	e.style.width  = '0';
	e.style.height = '0';
	var iframe = document.body.appendChild(e);
	iframe.src='/js/common/proxy.html';
	
	iframe.addEventListener('load', function(e){
		var storage = iframe.contentWindow.document.getElementById('storageElement');
		storage.load(namespace);

	    Storage = {
	        get: function(key) {
	            return storage.getAttribute(key);
	        },

	        put: function(key, value) {
	            storage.setAttribute(key, value);
	            storage.save(namespace);
	        },

	        remove: function(key) {
	            storage.removeAttribute(key);
	            storage.save(namespace);
	        },

	        clear: function() {
	            var attrs = storage.XMLDocument.documentElement.attributes;

	            for(var i = 0; i < attrs.length; i++) storage.removeAttribute(attrs[i].name);
	            storage.save(namespace);
	        },

	        getKeys: function() {
	            var res = [];
	            var attrs = storage.XMLDocument.documentElement.attributes;

	            for(var i = 0; i < attrs.length; i++) res.push(attrs[i].name);
	            return res;
	        }
	    }
	    onready();
	}, false);
};

/**
 * Flash 8
 * @browsers any
 */
Storage.flash8 = function(onready) { 
    var movie = null;
    var swfId = "StorageMovie";
    
	while(document.getElementById(swfId)) swfId = '_' + swfId;
    
	var swfUrl = Storage.swfUrl;
    
    // first setup storage, make it ready to accept back async call
    Storage = {       
        get:    function(key)        { return movie.get(key)},
		put:    function(key, value) { movie.put(key, value); },
        remove: function(key)        { movie.remove(key); },
        clear:  function()           { movie.clear(); },
        
        getKeys: function() {
            return movie.getkeys();  // lower case in flash to evade ExternalInterface bug         
        },
        
        ready: function() {
            movie = document[swfId];
            onready();
        }
    }
    
    // embed flash into document
    var protocol = window.location.protocol == 'https' ? 'https' : 'http';
    var containerStyle = "width:0; height:0; position: absolute; z-index: 10000; top: -1000px; left: -1000px;";        
    var objectHTML = '<embed src="' + swfUrl + '" '
                              + ' bgcolor="#ffffff" width="0" height="0" '
                              + 'id="' + swfId + '" name="' + swfId + '" '
                              + 'swLiveConnect="true" '
                              + 'allowScriptAccess="sameDomain" '
                              + 'type="application/x-shockwave-flash" '
                              + 'pluginspage="' + protocol +'://www.macromedia.com/go/getflashplayer" '
                              + '></embed>';                    
    var div = document.createElement("div");
    div.setAttribute("id", swfId + "Container");
    div.setAttribute("style", containerStyle);
    div.innerHTML = objectHTML;
    document.body.appendChild(div);
};
    

;(function(){

/**
 * Get element's absolute position. Properly handles Safari's body scroll*.
 * 
 * @param e - element
 * @return {Object} position - x,y
 */
function getPosition (n)
{
	var x = 0, y = 0, p
	for (;;)
	{
		x += n.offsetLeft
		y += n.offsetTop
		if ((p = n.offsetParent))
		{
			x -= n.scrollLeft
			y -= n.scrollTop
			n = p
		}
		else
			break
	}
	
	return {x:x, y:y};
}

function hook (e)
{
	var node = e.target
	if (node.__draggable)
	{
		var opts = node.__draggable
		node.__draggable = null
		new Me(node, opts[0], opts[1]).dispatch(e)
	}
}
document.addEventListener('mousedown', hook, false)

/**
 * Класс, который позволяет сделать элемент перетаскиваемым (создается его клон)
 * В результате перетаскивания у элемента-цели срабатывает метод onDrop(name)
 * 
 * @param element который мы хотим таскать
 * @param name - имя или идентификатор этого элемента (или любые данные)
 * @param dropTargets - массив элементов-целей, на которые можно перетаскивать
 */
var Me = self.Draggable = function (element, name, dropTargets){
	this.STYLE_CURSOR = 'drag-cursor';
	
	this.dragObject = null;
	var self = this;
	
	function elementWaits(e) {
		e.preventDefault();
		var s = self.startMouse
		if (Math.abs(s.x - e.pageX) > 4 || Math.abs(s.y - e.pageY) > 4)
			beginDrag(e)
	}
	
	function elementMove(e){
		e.preventDefault();
		if(self.dragObject){
			var delta = self.delta, style = self.style
			style.left = (e.pageX + delta.x)  + "px";
			style.top  = (e.pageY + delta.y) + "px";
			return false;
		}
	}
	
	function mouseDown (e)
	{
		self.movements = 0
		self.startMouse = {x:e.pageX, y:e.pageY}
		e.preventDefault()
		document.addEventListener('mousemove', elementWaits, false);
	}
	element.addEventListener('mousedown', mouseDown, false)
	this.dispatch = mouseDown
	
	function beginDrag(e) {
		var node = self.dragObject = element.cloneNode(true);
		self.style = node.style
		node.addClassName("dragging-object")
		var startPos = getPosition(element)
		self.delta = {x: startPos.x - e.pageX, y: startPos.y - e.pageY}
		
		document.body.appendChild(node)
		// document.body.addClassName(self.STYLE_CURSOR);
		for(var i = 0; i < dropTargets.length; i++){
			if(dropTargets[i].onDragStart) dropTargets[i].onDragStart(element);
		}
		
		document.removeEventListener('mousemove', elementWaits, false);
		document.addEventListener('mousemove', elementMove, false);
		elementMove.apply(this, [e])
	}
	
	document.addEventListener('mouseup', function(e){
		document.removeEventListener('mousemove', elementMove, false);
		document.removeEventListener('mousemove', elementWaits, false);
		if(self.dragObject) {
			try
			{
				// FIXME: self.dragObject may be not appended to body
				document.body.removeChild(self.dragObject);
			}
			catch (ex) {}
			// document.body.remClassName(self.STYLE_CURSOR);
			
			// dropping
			for(var i = 0; i < dropTargets.length; i++){
				if(dropTargets[i].style.display == "block"){
					var targPos    = getPosition(dropTargets[i]);
					var targWidth  = parseInt(dropTargets[i].offsetWidth);
					var targHeight = parseInt(dropTargets[i].offsetHeight);
					
					if(
						(e.pageX > targPos.x)                &&
						(e.pageX < (targPos.x + targWidth))  &&
						(e.pageY > targPos.y)                &&
						(e.pageY < (targPos.y + targHeight))){
						if (dropTargets[i].onDrop(name) === true)
							break;
					}
				}
			}
			
			for(var i = 0; i < dropTargets.length; i++)
				if (dropTargets[i].onDragEnd)
					dropTargets[i].onDragEnd();
			
			self.dragObject = null;
		}
	}, false);
}

})();
/**
 * Cookie functionality. 
 * All cookies are saved with "path=/"
 */
var Cookie = {
  set: function(name, value) {
    return (document.cookie = escape(name) + '=' + escape(value || '') + "; path=/");
  },

  get: function(name) {
    var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + escape(name) + '=([^;\\s]*)'));
    return (cookie ? unescape(cookie[2]) : null);
  },

  remove: function(name) {
    var cookie = Cookie.get(name) || true;
    Cookie.set(name, '', -1);
    return cookie;
  },
  
  getKeys: function(){
	var res = [];
	var arr = document.cookie.match(/(\w+)=[\w\d\S]*;*/ig);
	for(var i = 0; i < arr.length; i++){
		res.push(arr[i].split("=")[0])
	}
	return res;
  },
  
  clear: function(){
	var keys = Cookie.getKeys();
	for(var i = 0; i < keys.length; i++) Cookie.remove(keys[i]); 
  }
};


;(function(){

var myName = 'Theme'
var Me = self[myName] =
{
	initialize: function (db)
	{
		this.db = db
	},
	
	bind: function ()
	{
		var db = this.db
		
		for (var k in db)
		{
			var item = db[k]
			if (!item.href)
				continue
			
			var node = $(k)
			if (node)
			{
				node.href = item.href
			}
		}
	}
}

})();

;(function(){ try {
	var m = /\btheme=(\d\d\d\d\.\d\d)/.exec(location.hash)
	if (m)
	{
		$('theme-stylesheet').href = '/t/theme/' + m[1] + '/theme.css'
		document.cookie = 'theme=' + m[1]// + '; expires=' + new Date()
	}
} catch (ex) {} })();


Theme.initialize({
	"spotlighted":{"href":"/cocktail/martini_royale/"},
	"branded-image":{"href":"/cocktail/martini_royale/"}
})
