Cart = {
	TIMEOUT: 2000,// in milliseconds
	strAdded: "Товар добавлен в заказ",
	strRemoved: "Товар удален из заказа",
	strAdd: "Добавить в заказ",
	strRemove: "Удалить из заказа",
	/* whether Cart.init() has already been called */
	initialized: false,
	/* articles in the cart */
	list: [],
	fullInfo: [],
	periodicalUpdaterInterval: null,
	shippingPriceTable: [],
	/**
	 * add item 
	 * @param DOMNode trigger the trigger that has been clicked to invoke action
	 * @param int id
	 */
	add: function(trigger, id) {
		Cart.init();
		if (false === Cart.contains(id))
		{
			Cart.list.push({"id": id, "quantity": 1});
		}
		Cart.store();
		Cart.changeTriggerOnAdd(trigger, id);
	},
	/**
	 * Change trigger element to text upon add
	 */
	changeTriggerOnAdd: function(trigger, id) {
		var r = document.createElement('span');
		r.className = 'cart-info added';
		r.innerHTML = Cart.strAdded;
		trigger.parentNode.replaceChild(r, trigger);
		trigger.onclick = function(){
			Cart.remove(trigger, id);
			return false;
		};
		setTimeout(function(){Cart.changeTriggerOnAddFlip(trigger, r);}, Cart.TIMEOUT);
	},
	/**
	 * Change trigger element back to trigger, but now it should remove article from cart
	 */
	changeTriggerOnAddFlip: function(trigger, replacement) {
		trigger.innerHTML = Cart.strRemove;
		replacement.parentNode.replaceChild(trigger, replacement);
	},
	/**
	 * Change trigger element to text upon removal
	 */
	changeTriggerOnRemove: function(trigger, id) {
		var r = document.createElement('span', Cart.strRemoved);
		r.innerHTML = Cart.strRemoved;
		trigger.parentNode.replaceChild(r, trigger);
		trigger.onclick = function(){
			Cart.add(trigger, id);
			return false;
		};
		setTimeout(function(){Cart.changeTriggerOnRemoveFlip(trigger, r);}, Cart.TIMEOUT);
	},
	/**
	 * Change trigger element back to trigger, but now it should add article to cart
	 */
	changeTriggerOnRemoveFlip: function(trigger, replacement) {
		trigger.innerHTML = Cart.strAdd;
		replacement.parentNode.replaceChild(trigger, replacement);
	},
	/**
	 * remove item
	 * @param DOMNode trigger the trigger that has been clicked to invoke action
	 * @param int id
	 */
	remove: function(trigger, id) {
		
		Cart.init();
		
		var index = Cart.contains(id);
		
		if (false !== index)
		{
			var newList = [];
			var newFullInfo = [];
			for (var i = 0; i < Cart.list.length; ++i)
			{
				if (i != index)
				{
					newList.push(Cart.list[i]);
					if (i in Cart.fullInfo)
					{
						newFullInfo.push(Cart.fullInfo[i]);
					}
				}
			}
			Cart.list = newList;
			Cart.fullInfo = newFullInfo;
			Cart.store();
			Cart.changeTriggerOnRemove(trigger, id);
			return true;
		}
		
		return false;
	},
	removeFull: function(trigger, id) {
		if (Cart.remove(trigger, id))
		{
			Cart.removeTableRow('row-' + id);
			Cart.updateStatus();
		}
	},
	updateStatus: function() {
		var totalPrice = 0.0, totalShipping = 0.0, totalWeight = 0.0;
		for (var i = 0; i < Cart.fullInfo.length; ++i)
		{
			totalPrice += Cart.fullInfo[i].quantity * parseFloat(Cart.fullInfo[i].price);
			totalWeight += Cart.fullInfo[i].quantity * parseFloat(Cart.fullInfo[i].weight);
		}
		
		totalShipping = Cart.calculateShippingPrice(totalWeight);
		
		totalInvoice = totalPrice + totalShipping;
		totalInvoice = Cart.round(totalInvoice);
		totalPrice = Cart.round(totalPrice);
		totalShipping = Cart.round(totalShipping);
		document.getElementById('total-price').innerHTML = totalPrice;
		document.getElementById('total-shipping').innerHTML = totalShipping;
		document.getElementById('total-invoice').innerHTML = totalInvoice;
	},
	calculateShippingPrice: function(w)
	{
		var weightLeft = w;
		var shippingPrice = 0;
		var maxWeightInTable = 0;
		var maxWeightPrice = 0;
		var spec;
		for (var i = 0; i < Cart.shippingPriceTable.length; ++i) {
			spec = Cart.shippingPriceTable[i];
			if (spec.max > maxWeightInTable)
			{
				maxWeightInTable = spec.max;
				maxWeightPrice = spec.price;
			}
		}
		if (w > maxWeightInTable)
		{
			var n = Math.round(w / maxWeightInTable);
			shippingPrice = maxWeightPrice * n;
			weightLeft -= n * maxWeightInTable;
		}
		for (var i = 0; i < Cart.shippingPriceTable.length; ++i) {
			spec = Cart.shippingPriceTable[i];
			if ((weightLeft > spec.min) && (weightLeft <= spec.max))
			{
				shippingPrice += spec.price;
			}
		}
		return shippingPrice;
	},
	/**
	 * Remove a row from table - upon removal from order on /request/ page
	 * @param HTMLTableRowElement node (actually, node ID could be specified)
	 */
	removeTableRow: function(node) {
		// remove a table row?
		switch (typeof(node)) {
			case 'object':
				break;
			case 'string':
				node = document.getElementById(node);
				break;
			default:
				return ;
				break;
		}
		node.parentNode.removeChild(node);
	},
	importFullInfo: function(rows) {
		Cart.fullInfo = rows;
	},
	/**
	 * Clear cart
	 */
	clear: function(confirm) {
		confirm = arguments.length ? confirm : true;
		if (confirm && window.confirm("Подтвердите удаление заказа"))
		{
			Cart.list = [];
			Cart.fullInfo = [];
			Cart.store();
			var cleanUp = ['contacts', 'address', 'shipping', 'payment_type', 'juri_name', 'invoice_no'];
			for (var i = 0; i < cleanUp.length; ++i)
			{
				var formEl = document.getElementById(cleanUp[i]);
				if (formEl)
				{
					formEl.value = '';
				}
				Util.delCookie(cleanUp[i]);
			}
			location.reload();
		}
	},
	setQuantity: function(id, force) {
		
		force = (arguments.length > 1) ? force : false;
		
		var index = Cart.contains(id);
		var input = document.getElementById('quantity' + id);
		
		if (! force)
		{
			if (! input.value.length)
			{// value is empty: user is just thinking on the desired quantity
				return ;
			} else if (input.value.match(/^\s+$/)) {
				input.value = '';
				return ;
			}
		}
		
		var q = parseFloat(input.value);
		if ((false !== index) && (q > 0))
		{
			q = Math.round(q);
			input.value = q;
			document.getElementById('subtotal' + id).innerHTML = Cart.round(q * Cart.fullInfo[index].price);
			Cart.list[index].quantity = q;
			Cart.fullInfo[index].quantity = q;
			Cart.store();
			Cart.updateStatus();
		} else {
			input.value = 1;
		}
	},
	periodicalUpdaterId: null,
	startPeriodicalUpdater: function(id) {
		Cart.periodicalUpdaterId = id;
		/* watch quantity value for a given product, every 1000 ms */
		Cart.periodicalUpdaterInterval = setInterval(function(){Cart.setQuantity(id);}, 1000);
	},
	stopPeriodicalUpdater: function() {
		clearInterval(Cart.periodicalUpdaterInterval);
		Cart.setQuantity(Cart.periodicalUpdaterId, true);
		Cart.periodicalUpdaterId = null;
	},
	/**
	 * Initialize. Read cart from cookies.
	 */
	init: function() {
		if (! Cart.initialized)
		{
			var listSerialized = Util.getCookie('cart');
			if (listSerialized) {
				var s = listSerialized.split(/,/), pair, id, quantity;
				for (var i = 0; i < s.length; ++i)
				{
					pair = s[i].split(/\:/);
					id = pair.length ? 
						parseInt(pair[0]) : 
						null;
					quantity = (pair.length > 1) ? 
						parseInt(pair[1]) : 
						null;
					if (id && quantity) {
						/* id && quantity are valid; fill the list array: 
							IN REVERSE ORDER! (as a fix to periodical-quantity-updater receiving wrong price.
							Cart.list and Cart.fullInfo used to differ in items order but this has been fixed) */
						Cart.list[s.length - i - 1] = {"id": id, "quantity": quantity};
					}
				}
			}
			Cart.store();
			Cart.initialized = true;
		}
	},
	/**
	 * Whether the cart contains article id
	 * @param int id
	 * @return int found element index or bool FALSE if not found
	 */
	contains: function(id) {
		Cart.init();
		for (var i = 0; i < Cart.list.length; ++i)
		{
			if (id == Cart.list[i].id)
			{
				return i;
			}
		}
		
		return false;
	},
	/**
	 * Store current cart state
	 */
	store: function()
	{
		if (0 == Cart.list.length) 
		{
			Util.delCookie('cart');
			return ;
		}
		var pairs = [];
		for (var i = 0; i < Cart.list.length; ++i)
		{
			pairs.push(Cart.list[i].id + ":" + Cart.list[i].quantity);
		}
		pairs.reverse();
		Util.setCookie('cart', pairs.join(","), 365);
	},
	/**
	 * toggle date-time-master visibility
	 */
	toggleDTM: function()
	{
		if (jdom.toggle('date-time-master'))
		{
			var delimiter = document.getElementById('shipping-delimiter').value;
			var re = new RegExp(" " + delimiter + " ");
			var dates = document.getElementById('shipping').value.split(re);
			// parse 'shipping' input value for date/time range
			if (dates && dates.length)
			{
				var d1 = dates[0];
				var d2 = (dates.length > 1) ? dates[1] : "";
				var datetime1 = d1.split(/\s+/);
				var datetime2 = d2.split(/\s+/);
				if (datetime1 && (3 == datetime1.length)) {
					document.getElementById('shipping_date_from').value = datetime1[0] + " " + datetime1[1];
					document.getElementById('shipping_time_from').value = datetime1[2];
				}
				if (datetime2 && (3 == datetime2.length)) {
					document.getElementById('shipping_date_to').value = datetime2[0] + " " + datetime2[1];
					document.getElementById('shipping_time_to').value = datetime2[2];
				}
			}
		}
	},
	setDTRange: function()
	{
		var delimiter = document.getElementById('shipping-delimiter').value;
		var sh = document.getElementById('shipping');
		sh.value = document.getElementById('shipping_date_from').value + " " +
			document.getElementById('shipping_time_from').value + 
			" " + delimiter + " " +
			document.getElementById('shipping_date_to').value + " " +
			document.getElementById('shipping_time_to').value;
		jdom.event.fire(sh, 'change');
	},
	dateRangeGuard: function()
	{
		var s1 = document.getElementById('shipping_date_from');
		var s2 = document.getElementById('shipping_date_to');
		var s1arr = s1.value.split(/\s+/);
		var s2arr = s2.value.split(/\s+/);
		try {
			
			if (s1arr[1] != s2arr[1])
			{// the two datess differ in month: leave them as is
				return ;
			}
			else if (s1.value > s2.value)
			{
				s2.value = s1.value;
			} else {
				Cart.timeRangeGuard();
			}
			
		} catch (e) {}
	},
	timeRangeGuard: function()
	{
		var s1 = document.getElementById('shipping_date_from');
		var s2 = document.getElementById('shipping_date_to');
		if (s2.value != s1.value)
		{
			// 2nd date is not equal to the first: no limits to time required
			// (actually, we suppose that the s2.value is greater)
			return;
		}
		var t1 = document.getElementById('shipping_time_from');
		var t2 = document.getElementById('shipping_time_to');
		if (t1.value >= t2.value) {
			t2.value = (parseInt(t1.value) + 1) + ":00";
		}
	},
	toggleJuriDisplay: function(r, payment_type)
	{
		if ('wire' == payment_type)
		{
			jdom.show('juri');
		} else {
			jdom.hide('juri');
		}
		Util.setCookie('payment_type', payment_type, 90);
	},
	onOrderSubmit: function(data)
	{
		alert(data);
		/*jdom("success-message-text").innerHTML = data;
		jdom.show("success-message");*/
	},
	/**
	 * A utility function
	 */
	round: function(floatval)
	{
		var r = (Math.round(floatval * 100) / 100).toString();
		if (! r.match(/\./))
		{
			r += '.00';
		} else if (! r.match(/\.\d{2}/)) {
			r += '0';
		}
		return r;
	}
}