var Cart = $.inherit({

	__constructor: function(cfg) {
		this.resetIndex();
		this.items = {};
		this.url = cfg.url;
		this.discount = 0;
		this.addItems(cfg.items);
		this.listeners = {};
		this.customer = cfg.customer;
		this.customer.discount = parseInt(this.customer.discount);
		if(isNaN(this.customer.discount) || this.customer.discount < 0){
			this.customer.discount = 0;
		}

	},

	listen: function(evCode, alias, ct, handler){
		if(!this.listeners[evCode]){
			this.listeners[evCode] = {}
		}
		this.listeners[evCode][alias] = {'ct':ct, 'handler': handler };
	},
	fire: function(evCode, args){
		if(!this.listeners[evCode]){
			return false;
		}
		for(var alias in this.listeners[evCode]){
			var ct = this.listeners[evCode][alias].ct;
			var handler = this.listeners[evCode][alias].handler;
			handler.call(ct, args);
		}
		return true;
	},

	addToIndex: function(code){
		if (!this.items[code]) return false;
		this.itemsIndex.i[this.itemsIndex.length++] = code;
		this.items[code].idx = this.itemsIndex.length - 1;
	},
	getItemsIndexLength: function(){
		return this.itemsIndex.length;
	},
	getItemCodeByIndex: function(idx){
		if(!this.itemsIndex.i[idx]) return false;
		return this.itemsIndex.i[idx];
	},
	confirmAdd: function(data) {
		$.ajax({
			url: this.url.item.add,
			dataType: 'json',
			'data': data,
			'context': this,
			'type': 'POST',
			success: function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result) {
					return false;
				}
				var added = this.addItems(r.data);
				this.fire('addItems', added);
			}
		});
	},
	addItems: function(items) {
		if ($.isEmptyObject(items)) {
			return false;
		}
		this.empty = false;
		var added = {};

		for (var item_group in items) {
			if ($.isEmptyObject(items[item_group])) continue;
			for (var index in items[item_group]) {
				var item_code = item_group + '_' + index;
				var item = items[item_group][index];

				this.items[item_code] = new CartItem({
					'cart': this,
					'item': item,
					'url':this.url.item,
					'idx': false
				});

				this.addToIndex(item_code);
				added[item_code] = this.items[item_code];
			}
		}

		return added;
	},
	confirmDelete:function(item) {

		$.ajax({
			'url': this.url.item['delete'],
			'dataType': 'json',
			'data': {'ot_id':item.ot_id,'id':item.id},
			'context': this,
			'type': 'POST',
			'success': function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result) {
					return false;
				}
				this.deleteItem(item);
			}
		});
	},
	deleteItem: function(item) {

		if (!(item = this.getItem(item.ot_id, item.id))) return false;
		delete this.items[item.ot_id + '_' + item.id];
		this.reindexItems();
		this.fire('deleteItem', item);
		delete item;
	},

	reindexItems: function() {
		this.resetIndex();
		for (var k in this.items) {
			this.addToIndex(k);
		}
	},
	resetIndex: function() {
		this.itemsIndex = {'length': 0, 'i':{}};
	},
	getItem: function(ot_id, id) {
		var k = ot_id + '_' + id;
		return this.items[k] ? this.items[k] : null;
	},

	confirmClear: function() {
		$.ajax({
			url: this.url.clear,
			dataType: 'json',
			context: this,
			'type': 'POST',
			success: function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result)return false;
				this.clear();
			}
		});
	},

	clear: function() {
		this.items = {};
		this.resetIndex();
		this.fire('clear');
	},
	getDiscountValue: function(){
		var f = (this.getTotalCost() / 100) * this.getDiscountPercent();
		return f.toFixed(2);
	},
	getDiscountPercent: function(){
		return this.customer.discount;
	},
	getToPayCost: function(){
		return (this.getTotalCost() - this.getDiscountValue()).toFixed(2);
	},
	getTotalCost: function() {
		if ($.isEmptyObject(this.items)) return 0;
		var t = 0;
		for (var indx in this.items) {
			t = t + this.items[indx].getPrice() * this.items[indx].getQuantity();
		}
		return parseFloat(t).toFixed(2);
	}
});

var CartItem = $.inherit({
	__constructor: function(cfg) {
		this.cart = cfg.cart;
		this.id = cfg.item.id;
		this.ot_id = cfg.item.ot_id;
		this.quantity = cfg.item.quantity;
		this.weight = cfg.item.weight;
		this.price = cfg.item.price;
		this.name = cfg.item.name;
		this.description = cfg.item.description;
		this.descriptionTagsFree = cfg.item.descriptionTagsFree;
		this.unionType = cfg.item.unionType;
		this.mediumImage = cfg.item.mediumImage;
		this.normalImage = cfg.item.normalImage;
		this.largeImage = cfg.item.largeImage;
		this.largestImage = cfg.item.largestImage;
		this.idx = cfg.idx;
		this.url = cfg.url;
    if(cfg.item.base) this.base = cfg.item.base;

		this.listeners = {};
	},
	listen: function(evCode, alias, ct, handler){
		if(!this.listeners[evCode]){
			this.listeners[evCode] = {}
		}
		this.listeners[evCode][alias] = {'ct':ct, 'handler': handler };
	},

	fire: function(evCode){
		if(!this.listeners[evCode]){
			return false;
		}
		for(var alias in this.listeners[evCode]){
			var ct = this.listeners[evCode][alias].ct;
			var handler = this.listeners[evCode][alias].handler;
			handler.call(ct, this);
		}
		return true;
	},

	getId: function(){
		return this.id;
	},
	getOtId: function(){
		return this.ot_id;
	},
	getIdx: function(){
		return this.idx;
	},
	getName: function(){
		return this.name;
	},
	getDescription: function(){
		return this.description;
	},
	getDescriptionTagsFree: function(){
		return this.descriptionTagsFree;
	},
	getUnionType: function(){
		return this.unionType;
	},
	getWeight: function(){
		return this.weight;
	},
	getPrice: function() {
		return this.price;
	},
	getUrl: function(){
		return this.url;
	},
	getMediumImage: function(){
		return this.mediumImage;
	},
	getNormalImage: function(){
		return this.normalImage;
	},
	getLargeImage: function(){
		return this.largeImage;
	},
	getLargestImage: function(){
		return this.largestImage;
	},
	quantityChange: function(val) {
		val = parseInt(val);
		if (isNaN(val) || val < 1) {
			return false
		}
		var data = {
			'ot_id':this.ot_id,
			'id':this.id,
			'quantity':val
		};
		$.ajax({
			url: this.url.quantityUpdate,
			dataType: 'json',
			'data': data,
			context: this,
			'type': 'POST',
			success: function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result) {
					return this.quantityUpdate(this.quantity);
				} else {
					return this.quantityUpdate(r.data[this.ot_id][this.id].quantity);
				}
			},
			error: function(XMLHttpRequest, textStatus, errorThrown) {
			}
		});
	},
	quantityUpdate: function(val) {
		if (val != this.quantity) {
			this.setQuantity(val);
		}
		this.fire('quantityUpdate');
	},

	setQuantity: function(val) {
		val = parseInt(val);
		if (isNaN(val) || val < 1) {
			return false;
		}
		this.quantity = val;
	},
	getQuantity: function() {
		return this.quantity;
	},

	resetQuantityValues: function() {
		this.quantityInput.val(this.getQuantity());
		return true;
	}
});

var CartBlock = $.inherit({
	__constructor: function(cfg) {
		this.items = {};
		this.cart = window.CartInstance;
		this.maxVisibleItems = 4;
		this.itemsBox = null;
		this.minOrderCost = cfg.minOrderCost || -1;
		if ($(cfg.container).length) {
			this.container = $(cfg.container);
		}
		this.bottomPannelIsRendered = false;

		this.HookSenders();
		this.addItems();
		this.cart.listen('deleteItem', 'CartBlockDI', this, this.deleteItem);
		this.cart.listen('addItems', 'CartBlockARI', this, this.addAndRefreshItems);
		this.cart.listen('clear', 'CartBlockClear', this, this.clear);
	},

	getItem: function(ot_id, id) {
		var k = ot_id + '_' + id;
		return this.items[k] ? this.items[k] : null;
	},
	addAndRefreshItems: function(items){
		if($.isEmptyObject(items)){
			return false;
		}
		items = this.addItems(items);
		this.refresh(items);
	},
	addItems: function(items){
		items = $.isEmptyObject(items) ? this.cart.items : items;
		if($.isEmptyObject(items)){
			return false;
		}
		var added = {};
		for(var index in items){
			this.items[index] = new CartBlockItem({
				'cart': this,
				'item': items[index]
			});
			added[index] = this.items[index];
		}
		return added;
	},
	receiveItem: function(data) {
		var ot_id = data.ot_id;
		var id = data.id;
		var quantity = parseInt(data.quantity);
		if (isNaN(quantity) || quantity < 1) {
			quantity = 1;
		}
		var item = this.getItem(ot_id, id);
		if (item) {
			item.quantityChange(item.getQuantity() + quantity);
			return;
		}
		this.confirmAdd({
			'id': id,
			'ot_id': ot_id,
			'quantity': quantity
		});
	},
	confirmAdd: function(data) {
		this.cart.confirmAdd(data);
	},
	HookSenders: function() {
		var adders = $('.cart-adder');
		if (!adders.length) return false;
		var cart = this;
		adders.each(function(index) {
			this.cartSender = new CartItemSender({
				'element': $(this),
				'cart': cart
			})
		});
	},
	getItemsBox: function() {
		return this.itemsBox;
	},
	quantityUpdate: function() {
		this.refreshTotalCost();
	},
	refreshTotalCost: function() {
		if (!this.totalCostE || !this.totalCostE.length) return false;
		this.totalCostE.html(this.cart.getTotalCost());
	},
	confirmDelete: function(item){
		this.cart.confirmDelete(item)
	},
	getUrl: function(){
		return this.cart.url;
	},
	deleteItem: function(item) {

		if (!(item = this.getItem(item.ot_id, item.id))) return false;

		item.unrender();

		delete this.items[item.getOtId() + '_' + item.getId()];
		delete item;
		this.unrenderItems();
		this.refresh();
	},
	confirmClear: function() {
		this.cart.confirmClear();
	},
	clear: function() {
		this.items = {};
		this.refresh();
	},
	getItemsIndexLength: function(){
		return this.cart.getItemsIndexLength();
	},
	getItemCodeByIndex: function(idx){
		return this.cart.getItemCodeByIndex(idx);
	},

	scrollUp: function() {
		var first = this.getFirstVisibleId();
		var firstIdx = this.items[first].getIdx();
		if (this.getItemsIndexLength() < this.maxVisibleItems
				|| firstIdx == 0){
			return false;
		}
		var last = this.getLastVisibleId();
		this.items[last].unrender();

		var newFirst = this.getItemCodeByIndex(firstIdx - 1);
		this.items[newFirst].render(null, this.items[first].getE());
	},
	scrollDown: function() {
		var last = this.getLastVisibleId();
		var lastIdx = this.items[last].getIdx();
		if (this.getItemsIndexLength() < this.maxVisibleItems
				|| lastIdx == (this.getItemsIndexLength() - 1)) {
			return false;
		}
		var first = this.getFirstVisibleId();
		this.items[first].unrender();

		var newLast = this.getItemCodeByIndex(lastIdx + 1);
		this.items[newLast].render(this.items[last].getE());
	},

	getFirstVisibleId: function() {
		if ($.isEmptyObject(this.items)) return null;
		for (var k in this.items) {
			if (this.items[k].isVisible) return k;
		}
		return null;
	},

	getLastVisibleId: function() {
		if ($.isEmptyObject(this.items)) return null;
		var i = 0;
		var id = null;
		for (var k in this.items) {
			if (i == this.maxVisibleItems) {
				break;
			}

			if (this.items[k].isVisible) {
				id = k;
				i++;
			}
		}
		return id;
	},

	getVisibleCount: function() {
		if ($.isEmptyObject(this.items)) return 0;
		var i = 0;
		for (var k in this.items) {
			if (this.items[k].isVisible) i++;
		}
		return i;
	},

	cartPage: function() {
		if (this.cart.getTotalCost() < this.minOrderCost) {
			alert(Lang.cart.minOrderCostAlert + ' ' + this.minOrderCost + ' ' + Lang.currency.grivna.shortUnit + '.');
			return false;
		}

		document.location.href = this.getUrl().cartPage;
	},

	renderItems: function(items) {
		if (!items) {
			items = this.items;
		}
		var i = this.maxVisibleItems - this.getVisibleCount();
		if (i > 0) {
			for (var index in items) {
				if (i-- <= 0) break;
				items[index].render();
			}
		}
	},

	unrenderItems: function() {
		if ($.isEmptyObject(this.items)) return false;
		for (var k in this.items) {
			this.items[k].unrender();
		}
	},

	refresh: function(added) {
		var items = added ? added : this.items;
		if ($.isEmptyObject(items)) {
			this.renderEmpty();
		} else {
			if (this.itemsBox.hasClass('cart-empty')) {
				this.itemsBox
						.removeClass('cart-empty')
						.empty();
			}
			this.renderItems(items);
		}
		this.refreshBottomPannel();
		this.refreshScroll();

	},

	refreshBottomPannel: function() {
		if (!this.bottomPannelE) {
			return false;
		}
		if (!this.bottomPannelIsRendered) {
			this.renderBottomPannel();
		}
		if (this.cart.itemsIndex.length > 0) {
			this.bottomPannelE.show();
			this.refreshTotalCost();
		} else {
			this.bottomPannelE.hide();
		}
	},

	refreshScroll:function() {
		if (this.cart.itemsIndex.length > this.maxVisibleItems) {
			this.scrollerUp.show();
			this.scrollerDown.show();
		} else {
			this.scrollerUp.hide();
			this.scrollerDown.hide();
		}
	},

	renderBottomPannel: function() {
		if (!this.bottomPannelE) {
			return false;
		}
		var ct = this;
		this.bottomPannelE.empty();
		this.bottomPannelE.hide();
		this.bottomPannelE
				.append($('<div/>', {'class':'separator2'}))
				.append($('<div/>', {'class':'cart-total'})
				.append($('<div/>', {'class':'cart-total-cost-title'}).html(Lang.cart.totalCost))
				.append($('<div/>', {'class':'cart-total-cost'})
				.append(
				this.totalCostE = $('<span/>', {'class':'cart-total-cost-value'})
				)
				.append($('<span/>', {'class':'cart-total-cost-currency'})
				.html(' ' + Lang.currency.grivna.shortUnit + '.')
				)
				)
				.append($('<div/>', {'class':'clear'}))
				)
				.append($('<div/>', {'class':'cart-buttons'})
				.append($('<div/>', {'class':'cart-buttons-scrollup'})
				.append($('<a/>', {'class':'linkUp', 'href':'#'})
				.html(Lang.cart.buttons.scrollUp)
				)
				)
				.append($('<div/>', {'class':'cart-buttons-cartpage'})
				.html(Lang.cart.buttons.cartPage)
				.bind('click', function() {
			return ct.cartPage();
		})
				)
				.append($('<div/>', {'class':'clear'}))
				);
		this.bottomPannelIsRendered = true;
	},

	render: function() {
		if (!this.container) return false;
		var ct = this;
		this.scrollerUp = $('<div/>', {'class': 'arrowTop' })
				.css('display', 'none')
				.bind('click', function() {
			ct.scrollUp();
		});

		this.scrollerDown = $('<div>', {'class': 'arrowBottom' })
				.css('display', 'none')
				.bind('click', function() {
			ct.scrollDown();
		});
		this.bottomPannelE = $('<div/>', {'class':'cart-bottom-pannel'});

		$('<div/>', {'id':'cartBlock'})
				.append($('<div/>', {'class':'shoppingTop'}))
				.append($('<div/>', {'class':'shoppingTitle'})
				.append($('<div/>', {'class':'cart-title'}).html(Lang.cart.title))
				.append($('<div/>', {'class':'cart-buttons-clear'})
				.html(Lang.cart.buttons.clear)
				.bind('click', function(ev) {
			ct.confirmClear();
		})
				)
				.append($('<div/>', {'class':'clear'}))
				)
				.append($('<div/>', {'class':'shoppingCenter'})
				.append(this.scrollerUp)
				.append((this.itemsBox = $('<div/>', {'class':'cart-items'})))
				.append(this.scrollerDown)
				.append(this.bottomPannelE)
				)
				.append($('<div/>', {'class':"shoppingBottom"}))
				.appendTo(this.container);
	},

	renderEmpty: function() {
		if (!this.itemsBox) return;
		this.itemsBox.html(Lang.cart.isEmpty);
		this.itemsBox.addClass('cart-empty')
	}
});

var CartBlockItem = $.inherit({
	__constructor: function(cfg) {
		this.item = cfg.item;

		this.cart = cfg.cart;
		this.E,
		this.priceE,
		this.quantityInput,
		this.isVisible = false;

		this.hookListeners();
	},
	hookListeners: function(){
		this.item.listen('quantityUpdate', 'CartBlockItemQU', this, this.quantityUpdate);
	},
	getWeight: function(){
		return this.item.getWeight();
	},
	getName: function(){
		return this.item.getName();
	},
	getId: function(){
		return this.item.getId();
	},
	getOtId: function(){
		return this.item.getOtId();
	},
	getIdx: function(){
		return this.item.getIdx();
	},
	getUrl: function(){
		return this.item.getUrl();
	},
	getMediumImage: function(){
		return this.item.getMediumImage();
	},
	getNormalImage: function(){
		return this.item.getNormalImage();
	},
	getLargeImage: function(){
		return this.item.getLargeImage();
	},
	getLargestImage: function(){
		return this.item.getLargestImage();
	},
	getDescription: function(){
		return this.item.getDescription();
	},
	getUnionType: function(){
		return this.item.getUnionType();
	},
	getQuantity: function() {
		return this.item.getQuantity();
	},
	quantityIncrease: function(){
		this.quantityChange(this.getQuantity() + 1);
	},
	quantityDecrease: function(){
		if (this.getQuantity() < 2) {
			return false;
		}
		this.quantityChange(this.getQuantity() - 1);
	},
	quantityChange: function(val) {
		this.item.quantityChange(val);
	},
	quantityUpdate: function(val) {
		if (val == this.getQuantity()){
			return this.resetQuantityValues();
		}
		if (this.isVisible) {
			this.quantityInput.val(this.getQuantity());
		}
		this.priceUpdate();
		this.cart.quantityUpdate(this);
	},
	makeAlt: function(){
		return this.getName()+'. '+this.getWeight()+' '+this.getUnionType()+'. '+this.getPrice()+' '+Lang.currency.grivna.shortUnit+'.';
	},
	resetQuantityValues: function() {
		this.quantityInput.val(this.getQuantity());
		return true;
	},
	handleQuantInpChange: function(ev) {

		var inp = $(ev.target);
		var val = parseInt(inp.val());

		if (isNaN(val) || val < 1) {
			val = 1;
		}

		return this.quantityChange(val);
	},
	priceUpdate: function() {
		if (!this.priceE || !this.priceE.length)
			return false;
		this.priceE.html(parseFloat(this.getPrice() * this.getQuantity()).toFixed(2));
	},
	getPrice: function() {
		return this.item.getPrice();
	},
	getE: function() {
		return this.E;
	},
	deleteItem: function(){
		this.cart.confirmDelete(this.item);
	},
	getBox: function() {
		this.box = this.cart.getItemsBox()
		return this.box && this.box.length;
	},
	render: function(after, before) {
		if (!this.box && !this.getBox()) {
			return false;
		}
		var ct = this;
		this.priceE = $('<span/>', {'class':'item-price-value'});
		this.quantityInput = $('<input/>', {
			'type':'text',
			'name':'quantityCart_' + this.getId(),
			'id': 'quantityCart_' + this.getId()})
				.addClass('qtyInput')
				.val(this.getQuantity())
				.bind('change', function(ev) {
					return ct.handleQuantInpChange(ev);
				});
		this.E = $('<div/>', {
			'class':'cart-item',
			'title': this.item.getDescriptionTagsFree()
		});
		this.E
			.append($('<h5>').html(this.getName()))
			.append($('<div class="quantity1">')
				.append($('<div class="minus">'))
				.append($('<div class="plus">'))
				.append(this.quantityInput)
			)
			.append($('<div class="cost">')
				.append(this.priceE)
				.append($('<span/>', {'class':'item-price-currency'}).html(' ' + Lang.currency.grivna.shortUnit + '.'))
			)
			.append($('<div/>', {'class':"item-delete-button"})
				.bind('click', function() {
					ct.deleteItem();
				})
			)
			.append($('<div class="clear">'))
			.bind('mouseenter', function() {
				on_product_over(ct.getId(), ct.makeAlt(), ct.getMediumImage(), ct.getLargestImage());
			})
			.bind('click', function(ev) {
				if ($(ev.target).hasClass('minus')) {
					ct.quantityDecrease();
				}
				if ($(ev.target).hasClass('plus')) {
					ct.quantityIncrease();
				}
			});
		this.priceUpdate();
		if (after) {
			this.E.insertAfter(after);
		} else if (before) {
			this.E.insertBefore(before);
		} else {
			this.E.appendTo(this.box);
		}

		this.isVisible = true;
	},
	unrender: function() {
		this.isVisible = false;
		if (this.E && this.E.length) {
			this.E.remove()
		}

	}
});

var CartPage = $.inherit(
	CartBlock, {
	__constructor: function(cfg){
		this.__base(cfg);
		this.discountE,
		this.guestDeliveryFormE,

		this.quantityPersonInp = false;
    this.extIng = {
      imbir: {price: 2, q:0},
      vassaby: {price: 2, q:0},
      soy: {price: 2, q:0},
    };
    this.extIngInp = false;
	},
	findToPayCost: function() {
		this.toPayCostE = $(this.container).find('.cost-to-pay-value');
		if (!this.toPayCostE.length){
			this.toPayCostE = false
		}
		return this.toPayCostE;
	},
	findTotalCost: function() {
		this.totalCostE = $(this.container).find('.total-cost-value');
		if (!this.totalCostE.length){
			this.totalCostE = false
		}
		return this.totalCostE;
	},
	getTotalCost: function(){
    var costByItems = parseFloat(this.cart.getTotalCost());
    var costByExtIng = parseFloat(this.getExtIngCost());
		return (costByItems+costByExtIng).toFixed(2);
	},
	getDiscountValue: function(){
    var f = (this.getTotalCost() / 100) * this.cart.getDiscountPercent();
    return f.toFixed(2);
	},
	getToPayCost: function(){
    return (this.getTotalCost() - this.getDiscountValue()).toFixed(2);
	},
  getExtIngCost: function(){
    if(!this.extIngInp || !this.extIngInp.length){
      return 0;
    }
    var c = 0;
    var ct = this;
    this.extIngInp.each(function(i,e){
      var cval = $(e).val();
      cval = parseInt(cval);
      if(isNaN(cval) || cval < 0
      || !e.__expingCode
      || !ct.extIng[e.__expingCode]){
        return;
      }
      var price = ct.extIng[e.__expingCode]['price'];
      c = c+(price*cval);
    });
    return c;
  },

	getVisibleCount: function() {
		return -1;
	},

	addItems: function(items){
		items = $.isEmptyObject(items) ? this.cart.items : items;
		if($.isEmptyObject(items)){
			return false;
		}
		var added = {};
		for(var index in items){
			this.items[index] = new CartPageItem({
				'cart': this,
				'item': items[index]
			});
			added[index] = this.items[index];
		}
		return added;
	},

	getQuantityPerson: function(){
		if(!this.quantityPersonInp || !this.quantityPersonInp.length) return false;
		return this.quantityPersonInp.val();
	},
	quantityPersonIncrease: function(){
		var val = parseInt(this.getQuantityPerson());
		if(isNaN(val) || val > 10){
			val = 10;
		}else if(val == 10){
			return false;
		}else{
			val++;
		}
		this.quantityPersonChange(val);
	},
	quantityPersonDecrease: function(){
		if (this.getQuantityPerson() < 1) {
			return false;
		}
		this.quantityPersonChange(this.getQuantityPerson() - 1);
	},
	handleQuantityPersonInpChange: function(ev) {

		var inp = $(ev.target);
		var val = parseInt(inp.val());
		return this.quantityPersonChange(val);
	},
	quantityPersonChange: function(val) {
		val = parseInt(val);
		if (isNaN(val) || val < 1) {
			val = 0;
		}
		return this.quantityPersonInp.val(val);
	},

  handleExtIngChange: function(ev) {
    if(ev.target['__prevVal'] == undefined){
      ev.target.__prevVal = null;
    }
    var inp = $(ev.target);
    var val = parseInt(inp.val());
    var cval = val;

    if (isNaN(val) || val < 1) {
      val = 0;
    }
    inp.val(val);
    if(ev.target.__prevVal != val){
      this.refreshBottomPannel();
    }
    ev.target.__prevVal = val;
    return val;
  },

	quantityUpdate: function() {
		this.refreshBottomPannel();
	},
	orderingSuccess: function() {
		window.location.href = this.cart.url.orderingSuccess;
	},
	orderingFailed: function(r) {
		alert(r.data);
	},
	insertGuestDeliveryForm: function(str) {
		if (!str || !this.guestDeliveryFormE) {
			return false;
		}
		this.guestDeliveryFormE
			.html(str);

		dynplaceholder_init('guestDiscountCart', Lang.cart.page.deliveryFrom.guestDiscountCart);
		dynplaceholder_init('guestFirstName', Lang.cart.page.deliveryFrom.guestFirstName);
		dynplaceholder_init('guestPhone_p1', Lang.cart.page.deliveryFrom.guestPhone_p1);
		dynplaceholder_init('guestPhone_p2', Lang.cart.page.deliveryFrom.guestPhone_p2);
    dynplaceholder_init('guestAddress', Lang.cart.page.deliveryFrom.guestAddress);
		dynplaceholder_init('guestNote', Lang.cart.page.deliveryFrom.guestNote);
		var p = document.getElementById('guestPhone_p2');
		var x = p.parentNode.clientWidth - 10;
		p.style.widths=x + 'px';
		$('#guestPhone_p1').autotab({ target: 'guestPhone_p2', format: 'numeric' });
		$('#guestPhone_p2').autotab({ format: 'numeric', previous: 'guestPhone_p1' });

		$('#guestDiscountCart').autotab({ format: 'numeric' });

	},
	insertExistsAdressesBlock: function(str) {
		if(!this.bottomPannelE.items.existsAdressesE.length) return false;
		this.bottomPannelE.items.existsAdressesE
			.html(str);
	},
	refreshTotalCost: function() {
		if (!this.totalCostE && !this.findTotalCost()) return false;
		this.totalCostE.html(this.getTotalCost());
	},
	refreshToPayCost: function() {
		if (!this.toPayCostE && !this.findToPayCost()) return false;
		this.toPayCostE.html(this.getToPayCost());
	},
	refreshDiscountValue: function() {
		if (!this.discountE || !this.discountE.length) return false;
		this.discountE.html(this.getDiscountValue());
	},

  refreshExtIng: function(){
    if(!this.extIngInp || !this.extIngInp.length){
      return 0;
    }
    var ct = this;
    this.extIngInp.each(function(i,e){
      var q = parseInt($(e).val());
      if(isNaN(q)
      || !e.__expingCode
      || !ct.extIng[e.__expingCode]){
        return;
      }
      var price = ct.extIng[e.__expingCode]['price'];
      var cost = parseFloat(price*q);
      var holder = $('#ext-ing-total-cost-'+e.__expingCode);
      if(!holder || !holder.length){
        return;
      }
      holder.html(cost);
    });
  },

	refreshBottomPannel: function() {
		if (!this.bottomPannelE) {
			return false;
		}
		if (!this.bottomPannelIsRendered) {
			this.renderBottomPannel();
		}
    this.refreshExtIng();
		this.refreshTotalCost();
		this.refreshToPayCost();
		this.refreshDiscountValue();
		if (this.cart.itemsIndex.length > 0) {
			this.bottomPannelE.show();
		} else {
			this.bottomPannelE.hide();
		}
	},
	refresh: function() {
		if ($.isEmptyObject(this.items)) {
			this.renderEmpty();
		} else {
			if (this.itemsBox.hasClass('cart-empty')) {
				this.itemsBox
						.removeClass('cart-empty')
						.children().not('.cart-page-headers.row').remove();
			}
			this.renderItems(this.items);
			this.refreshBottomPannel();
		}
	},
	orderNow: function() {
		if(!checkCartData()){
			return false;
		}
		var data = {};
		data['orderDelivery[person_count]'] = this.quantityPersonInp.val();
    // ext ingredients
    var ct = this;
    if(this.extIngInp && this.extIngInp.length){
      this.extIngInp.each(function(i,e){
        var cval = parseInt($(e).val());
        if(isNaN(cval) || cval < 1
        || !e.__expingCode
        || !ct.extIng[e.__expingCode]){
          return;
        }
        data['orderDelivery[exting]['+e.__expingCode+']'] = cval;
      });
    }



		if(this.cart.customer.user_id > 0){
			var addressStr = '';

			var e = this.bottomPannelE.items.existsAdressesE.find('input[checked].');
			if(e.val() == 'other'){
				addressStr = trim(this.bottomPannelE.items.existsAdressesE.find('#otherAddress').val());
			}else if(!isNaN(parseInt(e.val()))){
				addressStr = this.bottomPannelE.items.existsAdressesE.find('#__lb'+parseInt(e.val())).html();
			}
			if(!addressStr.length){
				alert(Lang.rollhouse.errors.deliveryAddressNotFound);
				return false;
			}
			data['orderDelivery[address]'] = addressStr;
		}else{
      data['orderDelivery[address]'] = this.bottomPannelE.find('#guestAddress').val();
			data['orderDelivery[note]'] = this.bottomPannelE.find('#guestNote').val();
			data['orderDelivery[fullname]'] = this.bottomPannelE.find('#guestFirstName').val();
			data['orderDelivery[phone]'] = this.bottomPannelE.find('#guestPhone_p1').val()+ '-' + this.bottomPannelE.find('input#guestPhone_p2.gField').val();
			data['orderDelivery[discount_card]'] = this.bottomPannelE.find('#guestDiscountCart').val();
		}

		$('div.cart-buttons-order-now').hide();
		$('img.cart-order-status-inprogress').show();
		$.ajax({
			url: this.cart.url.orderNow,
			'data': data,
			dataType: 'json',
			'context': this,
			'type': 'post',
			success: function(r, textStatus, XMLHttpRequest) {
				if(!r || !r.result){
					this.orderingFailed(r);
				}else{
					this.orderingSuccess();
				}
			},
			'complete': function(){
				$('img.cart-order-status-inprogress').hide();
				$('div.cart-buttons-order-now').show();
			}
		});
	},

	renderTotalTable: function(){
		var ct = this;
		this.quantityPersonInp =
			$('<input/>', {'type':'text','name':'quantityPerson', id:'guestPersonCount'})
				.addClass('qtyInput').addClass('gField').val(0)
				.bind('change', function(ev) {
					return ct.handleQuantPersonInpChange(ev);
				});
		var table = $('<table/>', {'cellspacing':0, 'cellpadding':0, 'class':'cart-total-table'});

		table
			.append($('<tr/>', {'class':'total-cost-row'})
				.append($('<td>', {'class':'caption-total'}).html(Lang.cart.page.total.captionTotal+':'))
				.append($('<td>', {'class':'caption-your-order'}).html( Lang.cart.page.total.captionYourOrder+':'))
				.append($('<td>', {'class':'cost'})
					.append($('<span/>', {'class':'total-cost-value'}).html(this.getTotalCost()))
					.append($('<span/>', {'class':'union'}).html(' '+Lang.currency.grivna.shortUnit+'.'))
				)
			)
			.append($('<tr/>')
				.append($('<td>', {'class':'caption-to-pay', colspan: 2}).html(Lang.cart.page.total.captionToPay+':'))
				.append($('<td>', {'class':'cost-to-pay'})
					.append($('<span/>', {'class':'cost-to-pay-value'}).html(this.getToPayCost()))
					.append($('<span/>', {'class':'union'}).html(' '+Lang.currency.grivna.shortUnit+'.'))
				)
			)
			.append($('<tr/>')
				.append($('<td>', {'class':'caption-person-quantity', colspan: 2}).html(Lang.cart.page.total.captionPersonQuantity+':'))
				.append($('<td>', {'class':'person-quantity'})
					.append($('<div>', {'class':'tip-container'})
						.append($('<div/>', {'class':'quantity-selector'})
							.append($('<div class="minus">').bind('click', function(ev) {ct.quantityPersonDecrease()}))
							.append($('<div class="plus">').bind('click', function(ev) {ct.quantityPersonIncrease()}))
							.append(this.quantityPersonInp)
							.append($('<span/>', {'class':'tip', id:'guestPersonCount_tipx'}))
						)
					)
				)
			)
			.append($('<tr/>', {'class':'order-now-row'})
				.append($('<td>', {'class':'order-now-cell', colspan: 3})
					.append($('<img/>',{'class':'cart-order-status-inprogress', 'src':'/images/ajax/rh-loading.gif'})
						.hide()
					)
					.append($('<div/>',{'class':'cart-buttons-order-now'})
						.html(Lang.cart.order)
						.bind('click', function(){
							ct.orderNow();
						})
					)
				)
			);

		if(this.cart.getDiscountPercent() > 0){
			this.discountE = $('<span/>', {'class':'discount-value'});
			var dE = $('<tr/>')
				.append($('<td>', {'class':'caption-discount', colspan: 2}).html(Lang.cart.page.total.captionDiscount+ ' '+this.cart.getDiscountPercent()+'%:'))
				.append($('<td>', {'class':'total-discount'})
					.append(this.discountE.html(this.cart.getDiscountValue()))
					.append($('<span/>', {'class':'union'}).html(' '+Lang.currency.grivna.shortUnit+'.'))
				);
			dE.insertAfter(table.find('.total-cost-row'));
		}
		table.appendTo(this.bottomPannelE.items.cartTotalCost);
		this.renderGuestDeliveryForm();
		this.renderExistsAddress();
	},

	renderGuestDeliveryForm: function(){
		var ct = this;
		if(this.cart.customer.user_id > 0){
			return false;
		}
		var e = this.bottomPannelE.items.cartTotalCost.find('.order-now-row');
		if(!e.length) return false;

		this.guestDeliveryFormE = $('<td>', {'class':'guest-delivery-form-cell', colspan: 3})
		var row = $('<tr/>')
				.append(this.guestDeliveryFormE);

		row.insertBefore(e);

		$.ajax({
			url: this.cart.url.guestdeliveryform,
			dataType: 'html',
			'context': this,
			'type': 'GET',
			success: function(r, textStatus, XMLHttpRequest) {
				this.insertGuestDeliveryForm(r);
			}
		});

	},
	renderExistsAddress: function(){
		var ct = this;
		if(this.cart.customer.user_id < 1){
			return false;
		}

		$.ajax({
			url: this.cart.url.existsaddressesblock,
			dataType: 'html',
			'context': this,
			'type': 'GET',
			success: function(r, textStatus, XMLHttpRequest) {
				this.insertExistsAdressesBlock(r);
			}
		});

	},

  renderExtIngTable: function(){
    this.extIngE = $('#cart-page-ext-ingredients');
    if(!this.extIngE.length){
      return false;
    }
    this.extIngInp = this.extIngE.find('.ext-ing-input');
    if(!this.extIngInp.length){
      return false;
    }
    var ct = this;
    var reg = /ext\-ing\-(\w+)/i;
    this.extIngInp.each(function(i,e){
      var inp = $(e);
      var idstr = inp.attr('id');
      var regr = reg.exec(idstr);
      if(!regr || !regr[1]){
        return false;
      }
      e.__expingCode = regr[1];

      inp.change(function(ev) {
        return ct.handleExtIngChange(ev);
      });
       $(inp).siblings('.minus').click(function(ev){
         var val = inp.val();
         inp.val(--val);
         inp.trigger('change');
         return;
       });
       $(inp).siblings('.plus').click(function(ev){
         var val = inp.val();
         inp.val(++val);
         inp.trigger('change');
         return;
       });
    });

    this.bottomPannelE.append(this.extIngE);
  },

	renderBottomPannel: function() {
		var ct = this;
		this.bottomPannelE = $('<div/>', {'class':'cart-page-bottom-pannel'});
		this.bottomPannelE.items = {
			existsAdressesE: $('<div/>',{'class': 'exist-addresses-box'}),
			cartTotalCost: $('<div/>',{'class': 'cart-total-cost-box'})
		};
    this.renderExtIngTable();
		this.bottomPannelE
			.append($('<table/>', {'cellpadding': 0, 'cellspacing': 0, 'border': 0})
				.append($('<tr/>')
					.append($('<td/>', {'class': 'exist-addresses-column'})
						.append(this.bottomPannelE.items.existsAdressesE)
						.append($('<div/>', {'class':'cart-page-delivery-info'}).html(Lang.cart.page.deliveryInfo))
					)
					.append($('<td/>',{'class':'total-table-column'})
						.append(this.bottomPannelE.items.cartTotalCost)
					)
				)
			);
		this.renderTotalTable();
		this.bottomPannelE.appendTo(this.boxE);
		this.bottomPannelIsRendered = true;
	},
	render: function() {
		if (!this.container) return false;
		var ct = this;
		this.boxE = $('<div/>', {'class':'cart-page-box'});
		this.itemsBox = $('<table/>', {'cellpadding': 0, 'cellspacing': 0, 'border': 0, width:'100%'});
		this.tableHeadersRowE = $('<tr/>', {'class': 'cart-page-headers row'});
		this.tableHeadersRowE
			.append($('<th/>', {'class': 'cell image'}).html('&nbsp;'))
			.append($('<th/>', {'class': 'cell name'}).html(Lang.cart.page.table.columns.name))
			.append($('<th/>', {'class': 'cell quantity'}).html(Lang.cart.page.table.columns.quantity))
			.append($('<th/>', {'class': 'cell weight'}).html(Lang.cart.page.table.columns.weight))
			.append($('<th/>', {'class': 'cell price-cell'}).html(Lang.cart.page.table.columns.summ))
			.append($('<th/>', {'class': 'cell close-button'}).html('&nbsp;'));

		this.tableHeadersRowE.appendTo(this.itemsBox);
		this.itemsBox.appendTo(this.boxE);
		this.boxE.appendTo(this.container);
		this.renderBottomPannel();
	},
	renderEmpty: function() {
		if (!this.itemsBox) return;
		$('<tr/>', {'class':'cart-page-item row'})
			.append($('<td/>', {'class':'cell empty', colspan: 6}).html(Lang.cart.isEmpty))
			.appendTo(this.itemsBox)
		this.itemsBox.addClass('cart-empty')
		this.refreshBottomPannel();
	}
});

var CartPageItem = $.inherit(
	CartBlockItem, {
	__constructor: function(cfg){
		this.__base(cfg);
		this.quantityValueE = false;
		this.totalWeightValueE = false;
	},
	getTotalCost: function(){
		return this.getPrice() * this.getQuantity();
	},
	getTotalWeight: function(){
		return this.getWeight() * this.getQuantity();
	},
	quantityUpdate: function(val) {
		if (val == this.getQuantity()){
			return this.resetQuantityValues();
		}
		if (this.isVisible) {
			this.quantityInput.val(this.getQuantity());
		}
		this.priceUpdate();
		if(!this.quantityValueE && !this.findQuantityValueE()){
			throw new Exception('Unable to find quantity-value elements');
		}

		this.quantityValueE.html(this.getQuantity());
		this.refreshTotalWeight();
		this.cart.quantityUpdate(this);
	},
	findQuantityValueE: function(){
		var e = this.E.find('.quantity-value');
		if(!e.length){
			return false;
		}
		this.quantityValueE = e;
		return this.quantityValueE;
	},
	findTotalWeightValueE: function(){
		var e = this.E.find('.total-weight-value');
		if(!e.length){
			return false;
		}
		this.totalWeightValueE = e;
		return this.totalWeightValueE;
	},
	refreshTotalWeight: function(){
		if(!this.totalWeightValueE && !this.findTotalWeightValueE()){
			return false;
		}
		this.totalWeightValueE.html(this.getTotalWeight());
	},
	render: function(after, before) {
		if (!this.box && !this.getBox()) {
			return false;
		}
		var ct = this;
		this.priceE = $('<span/>', {'class':'value'});
		this.quantityInput = $('<input/>', {
				'type':'text',
				'name':'quantityCart_' + this.getId(),
				'id': 'quantityCart_' + this.getId()})
			.addClass('qtyInput')
			.val(this.getQuantity())
			.bind('change', function(ev) {
				return ct.handleQuantInpChange(ev);
			});
		var weightTd = false;

		if(!this.item.getWeight()){
			weightTd = $('<td/>', {'class':'cell weight'});
		}else{
      var base = $('<div/>');
      if(this.item.base){
        base = $(this.item.base)
      }
			weightTd = $('<td/>', {'class':'cell weight'})
        .append(base)
				.append($('<div/>', {'class':'total'})
					.append($('<span/>', {'class':'total-weight-value'}).html(this.getTotalWeight()))
					.append($('<span/>', {'class':'union'}).html(' '+this.getUnionType()))
				)
				.append($('<div/>', {'class':'detailed'})
					.append($('<span/>').html('('))
					.append($('<span/>', {'class':'quantity-value'}).html(this.getQuantity()))
					.append($('<span/>').html(' '+Lang.cart.unions.items.short+'. '+Lang.cart.other.by+' '))
					.append($('<span/>', {'class':'weight'}).html(this.getWeight()))
					.append($('<span/>', {'class':'union'}).html(' '+this.getUnionType()+'.)'))
				)
		}

		this.E = $('<tr/>', {'class':'cart-page-item row'})
			.append($('<td/>', {'class':'cell image'})
				.append($('<img/>', {'alt':'', src:this.getNormalImage()}))
			)
			.append($('<td/>', {'class':'cell name'})
				.append($('<div/>', {'class':'value'}).html(this.getName()))
				.append($('<div/>', {'class':'description'}).html(this.getDescription()))
			)
			.append($('<td/>', {'class':'cell quantity'})
				.append($('<div/>', {'class':'quantity-selector'})
					.append($('<div class="minus">').bind('click', function(ev) {ct.quantityDecrease()}))
					.append($('<div class="plus">').bind('click', function(ev) {ct.quantityIncrease()}))
					.append(this.quantityInput)
				)
			)
			.append(weightTd)
			.append($('<td/>', {'class':'cell price-cell'})
				.append($('<div/>', {'class':'total'})
					.append(this.priceE.html(this.getTotalCost()))
					.append($('<span/>', {'class':'union'}).html(' '+Lang.currency.grivna.shortUnit+'.'))
				)
				.append($('<div/>', {'class':'detailed'})
					.append($('<span/>').html('('))
					.append($('<span/>', {'class':'quantity-value'}).html(this.getQuantity()))
					.append($('<span/>').html(' '+Lang.cart.unions.items.short+'. '+Lang.cart.other.by+' '))
					.append($('<span/>', {'class':'price-value'}).html(this.getPrice()))
					.append($('<span/>', {'class':'union'}).html(' '+Lang.currency.grivna.shortUnit+'.)'))
				)
			)
			.append($('<td/>', {'class':'cell close-button'})
				.append($('<div/>', {'class':"delete-button"})
					.bind('click', function() {
							ct.deleteItem();
						})
				)
			);

		this.quantityE = this.E.find('span.quantity');

		this.priceUpdate();
		if (after) {
			this.E.insertAfter(after);
		} else if (before) {
			this.E.insertBefore(before);
		} else {
			this.E.appendTo(this.box);
		}

		this.isVisible = true;
	}
});

var CartItemSender = $.inherit({
	__constructor: function(cfg) {
		if (!$(cfg.element).length) {
			return false;
		}
		this.element = $(cfg.element);
		this.cart = cfg.cart;

		var ct = this;
		this.element.bind('click', function(ev) {
			if ($(ev.target).hasClass('add-to-cart')) {
				ct.sendItemToCart();
			}
		})
	},
	sendItemToCart: function() {
		if (!this.cart || !this.element) return false;
		var data = {};
		var qInput = this.element.find('input.qtyInput');
		var prod = this.element.find('input.product-id');
		var prodOt = this.element.find('input.product-ot_id');
		if (!qInput.length || !prod.length || !prodOt.length) return false;
		var prodId = prod.val();
		var prodOtId = prodOt.val();
		var quantity = parseInt(qInput.val());
		this.cart.receiveItem({
			'id': parseInt(prodId),
			'ot_id': parseInt(prodOtId),
			'quantity': quantity
		});
	}
});

var Last = $.inherit({

	__constructor: function(cfg) {
		this.resetIndex();
		this.items = {};
		this.url = cfg.url;
		this.discount = 0;
		this.addItems(cfg.items);
		this.listeners = {};
		this.customer = cfg.customer;
		this.customer.discount = parseInt(this.customer.discount);
		if(isNaN(this.customer.discount) || this.customer.discount < 0){
			this.customer.discount = 0;
		}
	},

	listen: function(evCode, alias, ct, handler){
		if(!this.listeners[evCode]){
			this.listeners[evCode] = {}
		}
		this.listeners[evCode][alias] = {'ct':ct, 'handler': handler };
	},
	fire: function(evCode, args){
		if(!this.listeners[evCode]){
			return false;
		}
		for(var alias in this.listeners[evCode]){
			var ct = this.listeners[evCode][alias].ct;
			var handler = this.listeners[evCode][alias].handler;
			handler.call(ct, args);
		}
		return true;
	},

	addToIndex: function(code){
		if (!this.items[code]) return false;
		this.itemsIndex.i[this.itemsIndex.length++] = code;
		this.items[code].idx = this.itemsIndex.length - 1;
	},
	getItemsIndexLength: function(){
		return this.itemsIndex.length;
	},
	getItemCodeByIndex: function(idx){
		if(!this.itemsIndex.i[idx]) return false;
		return this.itemsIndex.i[idx];
	},
	confirmAdd: function(data) {
		$.ajax({
			url: this.url.item.add,
			dataType: 'json',
			'data': data,
			'context': this,
			'type': 'POST',
			success: function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result) {
					return false;
				}
				var added = this.addItems(r.data);
				this.fire('addItems', added);
			}
		});
	},
	addItems: function(items) {
		if ($.isEmptyObject(items)) {
			return false;
		}
		this.empty = false;
		var added = {};

		for (var item_group in items) {
			if ($.isEmptyObject(items[item_group])) continue;
			for (var index in items[item_group]) {
				var item_code = item_group + '_' + index;
				var item = items[item_group][index];

				this.items[item_code] = new CartItem({
					'cart': this,
					'item': item,
					'url':this.url.item,
					'idx': false
				});

				this.addToIndex(item_code);
				added[item_code] = this.items[item_code];
			}
		}

		return added;
	},
	confirmDelete:function(item) {

		$.ajax({
			'url': this.url.item['delete'],
			'dataType': 'json',
			'data': {'ot_id':item.ot_id,'id':item.id},
			'context': this,
			'type': 'POST',
			'success': function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result) {
					return false;
				}
				this.deleteItem(item);
			}
		});
	},
	deleteItem: function(item) {

		if (!(item = this.getItem(item.ot_id, item.id))) return false;
		delete this.items[item.ot_id + '_' + item.id];
		this.reindexItems();
		this.fire('deleteItem', item);
		delete item;
	},

	reindexItems: function() {
		this.resetIndex();
		for (var k in this.items) {
			this.addToIndex(k);
		}
	},
	resetIndex: function() {
		this.itemsIndex = {'length': 0, 'i':{}};
	},
	getItem: function(ot_id, id) {
		var k = ot_id + '_' + id;
		return this.items[k] ? this.items[k] : null;
	},

	confirmClear: function() {
		$.ajax({
			url: this.url.clear,
			dataType: 'json',
			context: this,
			'type': 'POST',
			success: function(r, textStatus, XMLHttpRequest) {
				if (!r || !r.result)return false;
				this.clear();
			}
		});
	},

	clear: function() {
		this.items = {};
		this.resetIndex();
		this.fire('clear');
	},
	getDiscountValue: function(){
		var float = (this.getTotalCost() / 100) * this.getDiscountPercent();
		return float.toFixed(2);
	},
	getDiscountPercent: function(){
		return this.customer.discount;
	},
	getToPayCost: function(){
		return (this.getTotalCost() - this.getDiscountValue()).toFixed(2);
	},
	getTotalCost: function() {
		if ($.isEmptyObject(this.items)) return 0;
		var t = 0;
		for (var indx in this.items) {
			t = t + this.items[indx].getPrice() * this.items[indx].getQuantity();
		}
		return parseFloat(t).toFixed(2);
	}
});

var LastBlock = $.inherit({
	__constructor: function(cfg, cartBox) {
		this.items = {};
    this.cartBox = cartBox;
		this.cart = window.LastInstance;
		this.maxVisibleItems = 4;
		this.itemsBox = null;
		this.minOrderCost = cfg.minOrderCost || -1;
		if ($(cfg.container).length) {
			this.container = $(cfg.container);
		}
		this.bottomPannelIsRendered = false;

		this.addItems();
	},

	getItem: function(ot_id, id) {
		var k = ot_id + '_' + id;
		return this.items[k] ? this.items[k] : null;
	},
	addAndRefreshItems: function(items){
		if($.isEmptyObject(items)){
			return false;
		}
		items = this.addItems(items);
		this.refresh(items);
	},
	addItems: function(items){
		items = $.isEmptyObject(items) ? this.cart.items : items;
		if($.isEmptyObject(items)){
			return false;
		}
		var added = {};
		for(var index in items){
			this.items[index] = new LastBlockItem({
				'cart': this,
				'item': items[index]
			});
			added[index] = this.items[index];
		}
		return added;
	},
	receiveItem: function(data) {
		var ot_id = data.ot_id;
		var id = data.id;
		var quantity = parseInt(data.quantity);
		if (isNaN(quantity) || quantity < 1) {
			quantity = 1;
		}
		var item = this.getItem(ot_id, id);
		if (item) {
			item.quantityChange(item.getQuantity() + quantity);
			return;
		}
		this.confirmAdd({
			'id': id,
			'ot_id': ot_id,
			'quantity': quantity
		});
	},
	confirmAdd: function(data) {
		this.cart.confirmAdd(data);
	},
	getItemsBox: function() {
		return this.itemsBox;
	},
	quantityUpdate: function() {
		this.refreshTotalCost();
	},
	refreshTotalCost: function() {
		if (!this.totalCostE || !this.totalCostE.length) return false;
		this.totalCostE.html(this.cart.getTotalCost());
	},
	confirmDelete: function(item){
		this.cart.confirmDelete(item)
	},
	getUrl: function(){
		return this.cart.url;
	},
	deleteItem: function(item) {

		if (!(item = this.getItem(item.ot_id, item.id))) return false;

		item.unrender();

		delete this.items[item.getOtId() + '_' + item.getId()];
		delete item;
		this.unrenderItems();
		this.refresh();
	},
	confirmClear: function() {
		this.cart.confirmClear();
	},
	clear: function() {
		this.items = {};
		this.refresh();
	},
	getItemsIndexLength: function(){
		return this.cart.getItemsIndexLength();
	},
	getItemCodeByIndex: function(idx){
		return this.cart.getItemCodeByIndex(idx);
	},

	scrollUp: function() {
		var first = this.getFirstVisibleId();
		var firstIdx = this.items[first].getIdx();
		if (this.getItemsIndexLength() < this.maxVisibleItems
				|| firstIdx == 0){
			return false;
		}
		var last = this.getLastVisibleId();
		this.items[last].unrender();

		var newFirst = this.getItemCodeByIndex(firstIdx - 1);
		this.items[newFirst].render(null, this.items[first].getE());
	},
	scrollDown: function() {
		var last = this.getLastVisibleId();
		var lastIdx = this.items[last].getIdx();
		if (this.getItemsIndexLength() < this.maxVisibleItems
				|| lastIdx == (this.getItemsIndexLength() - 1)) {
			return false;
		}
		var first = this.getFirstVisibleId();
		this.items[first].unrender();

		var newLast = this.getItemCodeByIndex(lastIdx + 1);
		this.items[newLast].render(this.items[last].getE());
	},

	getFirstVisibleId: function() {
		if ($.isEmptyObject(this.items)) return null;
		for (var k in this.items) {
			if (this.items[k].isVisible) return k;
		}
		return null;
	},

	getLastVisibleId: function() {
		if ($.isEmptyObject(this.items)) return null;
		var i = 0;
		var id = null;
		for (var k in this.items) {
			if (i == this.maxVisibleItems) {
				break;
			}

			if (this.items[k].isVisible) {
				id = k;
				i++;
			}
		}
		return id;
	},

	getVisibleCount: function() {
		if ($.isEmptyObject(this.items)) return 0;
		var i = 0;
		for (var k in this.items) {
			if (this.items[k].isVisible) i++;
		}
		return i;
	},

	cartPage: function() {
		if (this.cart.getTotalCost() < this.minOrderCost) {
			alert(Lang.cart.minOrderCostAlert + ' ' + this.minOrderCost + ' ' + Lang.currency.grivna.shortUnit + '.');
			return false;
		}

		document.location.href = this.getUrl().cartPage;
	},

	renderItems: function(items) {
		if (!items) {
			items = this.items;
		}
		var i = this.maxVisibleItems - this.getVisibleCount();
		if (i > 0) {
			for (var index in items) {
				if (i-- <= 0) break;
				items[index].render();
			}
		}
	},

	unrenderItems: function() {
		if ($.isEmptyObject(this.items)) return false;
		for (var k in this.items) {
			this.items[k].unrender();
		}
	},

	refresh: function(added) {
		var items = added ? added : this.items;
		if ($.isEmptyObject(items)) {
			this.renderEmpty();
		} else {
			if (this.itemsBox.hasClass('cart-empty')) {
				this.itemsBox
						.removeClass('cart-empty')
						.empty();
			}
			this.renderItems(items);
		}
		this.refreshBottomPannel();
		this.refreshScroll();

	},

	refreshBottomPannel: function() {
		if (!this.bottomPannelE) {
			return false;
		}
		if (!this.bottomPannelIsRendered) {
			this.renderBottomPannel();
		}
		if (this.cart.itemsIndex.length > 0) {
			this.bottomPannelE.show();
			this.refreshTotalCost();
		} else {
			this.bottomPannelE.hide();
		}
	},

	refreshScroll:function() {
		if (this.cart.itemsIndex.length > this.maxVisibleItems) {
			this.scrollerUp.show();
			this.scrollerDown.show();
		} else {
			this.scrollerUp.hide();
			this.scrollerDown.hide();
		}
	},

	renderBottomPannel: function() {
		if (!this.bottomPannelE) {
			return false;
		}
		var ct = this;
		this.bottomPannelE.empty();
		this.bottomPannelE.hide();
		this.bottomPannelE
				.append($('<div/>', {'class':'separator2'}))
				.append($('<div/>', {'class':'cart-total'})
				.append($('<div/>', {'class':'cart-total-cost-title'}).html(Lang.cart.totalCost))
				.append($('<div/>', {'class':'cart-total-cost'})
				.append(
				this.totalCostE = $('<span/>', {'class':'cart-total-cost-value'})
				)
				.append($('<span/>', {'class':'cart-total-cost-currency'})
				.html(' ' + Lang.currency.grivna.shortUnit + '.')
				)
				)
				.append($('<div/>', {'class':'clear'}))
				)
				.append($('<div/>', {'class':'cart-buttons'})
				.append($('<div/>', {'class':'cart-buttons-scrollup'})
				.append($('<a/>', {'class':'linkUp', 'href':'#'})
				.html(Lang.cart.buttons.scrollUp)
				)
				)
				.append($('<div/>', {'class':'cart-buttons-cartpage'})
				.html(Lang.order.last.to_cart)
				.bind('click', function() {
			return ct.itemsToCart();
		})
				)
				.append($('<div/>', {'class':'clear'}))
				);
		this.bottomPannelIsRendered = true;
	},

  itemsToCart: function(){
		items = this.cart.items;
		for(var index in items){
      var item = this.items[index];
			this.cartBox.receiveItem({
        'id': parseInt(item.getId()),
        'ot_id': parseInt(item.getOtId()),
        'quantity': item.getQuantity()
      });
		}
  },
	render: function() {
		if (!this.container) return false;
		var ct = this;
		this.scrollerUp = $('<div/>', {'class': 'arrowTop' })
				.css('display', 'none')
				.bind('click', function() {
			ct.scrollUp();
		});

		this.scrollerDown = $('<div>', {'class': 'arrowBottom' })
				.css('display', 'none')
				.bind('click', function() {
			ct.scrollDown();
		});
		this.bottomPannelE = $('<div/>', {'class':'cart-bottom-pannel'});

		$('<div/>', {'id':'lastBlock'})
				.append($('<div/>', {'class':'shoppingTop'}))
				.append($('<div/>', {'class':'shoppingTitle'})
				.append($('<div/>', {'class':'cart-title'}).html(Lang.order.last.title))
				.append($('<div/>', {'class':'clear'}))
				)
				.append($('<div/>', {'class':'shoppingCenter'})
				.append(this.scrollerUp)
				.append((this.itemsBox = $('<div/>', {'class':'cart-items'})))
				.append(this.scrollerDown)
				.append(this.bottomPannelE)
				)
				.append($('<div/>', {'class':"shoppingBottom"}))
				.appendTo(this.container);
	},

	renderEmpty: function() {
		if (!this.itemsBox) return;
		this.itemsBox.html(Lang.cart.isEmpty);
		this.itemsBox.addClass('cart-empty')
	}
});

var LastBlockItem = $.inherit({
	__constructor: function(cfg) {
		this.item = cfg.item;
		this.cart = cfg.cart;
		this.E,
		this.priceE,
		this.quantityInput,
		this.isVisible = false;
	},
	getWeight: function(){
		return this.item.getWeight();
	},
	getName: function(){
		return this.item.getName();
	},
	getId: function(){
		return this.item.getId();
	},
	getOtId: function(){
		return this.item.getOtId();
	},
	getIdx: function(){
		return this.item.getIdx();
	},
	getUrl: function(){
		return this.item.getUrl();
	},
	getMediumImage: function(){
		return this.item.getMediumImage();
	},
	getNormalImage: function(){
		return this.item.getNormalImage();
	},
	getLargeImage: function(){
		return this.item.getLargeImage();
	},
	getLargestImage: function(){
		return this.item.getLargestImage();
	},
	getDescription: function(){
		return this.item.getDescription();
	},
	getUnionType: function(){
		return this.item.getUnionType();
	},
	getQuantity: function() {
		return this.item.getQuantity();
	},
	quantityIncrease: function(){
		this.quantityChange(this.getQuantity() + 1);
	},
	quantityDecrease: function(){
		if (this.getQuantity() < 2) {
			return false;
		}
		this.quantityChange(this.getQuantity() - 1);
	},
	quantityChange: function(val) {
		this.item.quantityChange(val);
	},
	quantityUpdate: function(val) {
		if (val == this.getQuantity()){
			return this.resetQuantityValues();
		}
		if (this.isVisible) {
			this.quantityInput.val(this.getQuantity());
		}
		this.priceUpdate();
		this.cart.quantityUpdate(this);
	},
	makeAlt: function(){
		return this.getName()+'. '+this.getWeight()+' '+this.getUnionType()+'. '+this.getPrice()+' '+Lang.currency.grivna.shortUnit+'.';
	},
	resetQuantityValues: function() {
		this.quantityInput.val(this.getQuantity());
		return true;
	},
	handleQuantInpChange: function(ev) {

		var inp = $(ev.target);
		var val = parseInt(inp.val());

		if (isNaN(val) || val < 1) {
			val = 1;
		}

		return this.quantityChange(val);
	},
	priceUpdate: function() {
		if (!this.priceE || !this.priceE.length)
			return false;
		this.priceE.html(parseFloat(this.getPrice() * this.getQuantity()).toFixed(2));
	},
	getPrice: function() {
		return this.item.getPrice();
	},
	getE: function() {
		return this.E;
	},
	deleteItem: function(){
		this.cart.confirmDelete(this.item);
	},
	getBox: function() {
		this.box = this.cart.getItemsBox()
		return this.box && this.box.length;
	},
	render: function(after, before) {
		if (!this.box && !this.getBox()) {
			return false;
		}
		var ct = this;
		this.priceE = $('<span/>', {'class':'item-price-value'});
		this.quantityInput = $('<span/>')
				.text(this.getQuantity());
		this.E = $('<div/>', {
			'class':'cart-item',
			'title': this.item.getDescriptionTagsFree()
		});
		this.E
			.append($('<h5>').html(this.getName()))
			.append($('<div class="quantity2">').text(this.getQuantity()))
			.append($('<div class="cost2">')
				.append(this.priceE)
				.append($('<span/>', {'class':'item-price-currency'}).html(' ' + Lang.currency.grivna.shortUnit + '.'))
			)
			.append($('<div class="clear">'));
		this.priceUpdate();
		if (after) {
			this.E.insertAfter(after);
		} else if (before) {
			this.E.insertBefore(before);
		} else {
			this.E.appendTo(this.box);
		}

		this.isVisible = true;
	},
	unrender: function() {
		this.isVisible = false;
		if (this.E && this.E.length) {
			this.E.remove()
		}

	}
});


