(function () {

var maxFilters = 5;

var View = {
	LIST: 0,
	GRID: 1
};

var orderBy = [
	{way: 'DESC', id: 'relevancy', name: 'Relevancy'},
	{way: 'ASC', id: 'name', name: 'Name'},
	{way: 'ASC', id: 'price', name: 'Lower price'},
	{way: 'DESC', id: 'price', name: 'Higher price'},
	{way: 'ASC', id: 'available', name: 'Available'},
	{way: 'ASC', id: 'size', name: 'Lower size'},
	{way: 'DESC', id: 'size', name: 'Higher size'},
	{way: 'ASC', id: 'color', name: 'Color'},
	{way: 'ASC', id: 'producer', name: 'Producer'},
	{way: 'ASC', id: 'origin', name: 'Origin'},
	{way: 'ASC', id: 'category', name: 'Category'}
];

Hedera.Catalog = new Class
({
	Extends: Hedera.Form
	
	,_menuShown: false

	,open: function ()
	{
		this.close ();
		this.isOpen = true;
	
		if (!localStorage.getItem ('hederaGuest'))
		{		
			Hedera.BasketChecker.check (this.conn, this.hash,
				this.onBasketCheck.bind (this));
		}
		else
		{
			var query = 'CALL basket_configure_for_guest ()';
			this.conn.execQuery (query, this.loadUi.bind (this));
		}
	}

	,onBasketCheck: function (isOk)
	{
		if (isOk)
			this.loadUi ();
	}
	
	,activate: function ()
	{
		this.$.items.setInfo ('i', 'item', 'vn', ['id']);
		document.body.appendChild (this.$.rightPanel);
	
		if (localStorage.getItem ('hederaView'))
			this.setView (parseInt (localStorage.getItem ('hederaView')));
		else
			this.setView (View.GRID);

		this.$.orderBy.model = new Vn.Model ({
			data: orderBy
		});

		this.onCategoryChange ();
		this.refreshTitle ();
		this.onParamsChange ();
	}

	,deactivate: function ()
	{
		this.hideMenu ();
		this.gui.$.navbar.style.backgroundColor = '';
		Vn.Node.remove (this.$.rightPanel);
	}

	,setView: function (view)
	{
		if (view === View.GRID)
		{
			this.$.viewButton.setProperties ({
				icon: 'view-list',
				tip: _('List view')
			});
			var className = 'grid-view';
		}
		else
		{
			this.$.viewButton.setProperties ({
				icon: 'view-grid',
				tip: _('Grid view')
			});
			var className = 'list-view';
		}
		
		this.view = view;
		var node = this.$.gridView.node;
		node.className = className;
		localStorage.setItem ('hederaView', this.view);
	}
	
	,onSwitchViewClick: function ()
	{
		this.setView (this.view === View.GRID ?
			View.LIST : View.GRID);
	}
	
	,onBasketReady: function (form)
	{
		if (form.$.method != 'PICKUP')
			Vn.Node.setText (this.$.method, _('Agency'));
		else
			Vn.Node.setText (this.$.method, _('Store'));
	}
	
	,onOrderChange: function (combo)
	{
		var sortField = combo.$.id;
		var sortWay = combo.$.way === 'ASC' ?
			Db.Model.SortWay.ASC : Db.Model.SortWay.DESC;
		
		if (sortField)
			this.$.items.sort (sortField, sortWay);
		
		this.hideMenu ();
	}

	,onParamsChange: function ()
	{
		var params = this.params.$;
		var shouldRefresh = params.search ||
			params.category && params.type;
			
		Vn.Node.removeChilds (this.$.suggestedFilters);

		if (shouldRefresh)
		{
			this.$.items.query = this.buildQuery ('CALL catalogGetItems');
			this.$.items.refresh ();

			var nTags = maxFilters - this.nFilters;

			if (nTags > 0)
			{
				var tagsQuery = this.buildQuery (
					'CALL catalogGetTags (#nTags)', {nTags: nTags});
				this.conn.execQuery (tagsQuery, this.onTagsReady.bind (this));
			}

			this.hideMenu ();
		}
		else
			this.$.items.clean ();

		this.showFilters (params.search || params.category);
	}
	
	,showFilters: function (show)
	{
		this.$.filters.style.display = show ? 'block' : 'none';
		this.$.categoryMsg.style.display = show ? 'none' : 'block';
	}

	,onRemoveFiltersClick: function ()
	{
		this.params.$ = {};
		this.tagFilter = {};
	}

	,filters: {}
	,nFilters: 0
	
	,buildQuery: function (query, params, excludeTag)
	{
		var query = new Sql.MultiStmt ({
			stmts: [
				this.$.preQuery,
				new Sql.String ({query: query}),
				this.$.postQuery
			]
		});
		var qParams = {
			joins: this.buildTagFilter (excludeTag),
			filter: this.buildMainFilter ()
		};
		Object.assign (qParams, params);
		return this.conn.renderStmt (query, qParams)
	}

	,buildMainFilter: function ()
	{
		var filterSql = this.$.filter.render (this.params.$);
		return new Sql.String ({query: filterSql});
	}

	,buildTagFilter: function (excludeTag)
	{
		var Type = Sql.Operation.Type;

		var join = new Sql.Join ({
			target: new Sql.Table ({
				schema: 'vn',
				name: 'item',
				alias: 'i'
			})
		});

		join.push (new Sql.JoinItem ({
			target: new Sql.Table ({
				schema: 'vn',
				name: 'itemType',
				alias: 't'
			}),
			condition: new Sql.Operation ({
				type: Type.EQUAL,
				exprs: [
					new Sql.Field ({
						target: 't',
						name: 'id'
					}),
					new Sql.Field ({
						target: 'i',
						name: 'typeFk'
					})
				]
			})
		}));

		var i = -1;

		for (var tagId in this.filters)
		{
			var tagId = parseInt (tagId);
			var tagValue = this.filters[tagId].field.value;

			if (tagId === excludeTag)
				continue;
	
			i++;
			var tAlias = 'it'+ i;

			var joinItem = new Sql.JoinItem ({
				target: new Sql.Table ({
					schema: 'vn',
					name: 'itemTag',
					alias: tAlias
				}),
				condition: new Sql.Operation ({
					type: Type.AND
				})
			});
			join.push (joinItem);

			joinItem.condition.exprs = [
				new Sql.Operation ({
					type: Type.EQUAL,
					exprs: [
						new Sql.Field ({
							target: tAlias,
							name: 'itemFk'
						}),
						new Sql.Field ({
							target: 'i',
							name: 'id'
						})
					]
				}),
				new Sql.Operation ({
					type: Type.EQUAL,
					exprs: [
						new Sql.Field ({
							target: tAlias,
							name: 'tagFk'
						}),
						new Sql.Value ({
							value: tagId
						})
					]
				}),
				new Sql.Operation ({
					type: Type.EQUAL,
					exprs: [
						new Sql.Field ({
							target: tAlias,
							name: 'value'
						}),
						new Sql.Value ({
							value: tagValue
						})
					]
				})
			];
		}

		return join;
	}
	
	,onTagsReady: function (resultSet)
	{
		var tags = resultSet.results[2].data;

		tags.forEach (function (tag) {
			if (this.filters[tag.id] !== undefined)
				return;

			var query = this.buildQuery (
				'CALL catalogGetTagValues (#tag)', {tag: tag.id}, tag.id);

			var filter = this.createElement ('div');
			this.$.suggestedFilters.appendChild (filter);

			var label = this.createElement ('label');
			label.appendChild (this.createTextNode (tag.name));
			filter.appendChild (label);

			var combo = new Htk.Combo ({
				valueField: 'value',
				showField: 'value'
			});
			filter.appendChild (combo.node);

			var model = new Db.Model ({
				autoLoad: false,
				resultIndex: 2,
				query: query,
				conn: this.conn
			});
			combo.model = model;

			var filterData = {
				filter: filter,
				tagId: tag.id,
				field: combo,
				model: model
			};
			combo.on ('changed',
				this.onComboChange.bind (this, filterData), this);
		}, this);
	}

	,onComboChange: function (filterData, _, value)
	{
		var filter = filterData.filter;
		var tagId = filterData.tagId;

		if (value == null)
		{
			this.$.currentFilters.removeChild (filter);
			delete this.filters[tagId];
			this.nFilters--;
		}
		else if (this.filters[tagId] === undefined)
		{
			this.nFilters++;
			this.filters[tagId] = filterData;
			this.$.suggestedFilters.removeChild (filter);
			this.$.currentFilters.appendChild (filter);
		}

		for (var tid in this.filters)
		if (parseInt (tid) !== tagId)
		{
			var query = this.buildQuery (
				'CALL catalogGetTagValues (#tag)', {tag: tid}, tid);
			this.filters[tid].model.query = query;
		}

		this.onParamsChange ();
	}

	,onCategoryChange: function ()
	{
		this.refreshTitleColor ();
	}

	,refreshTitleColor: function ()
	{
		var categories = this.$.categories;
		var category = this.params.$.category;
		var color = null;

		if (category)
		{
			var row = categories.search ('id', category);

			if (row != -1)
				color = '#'+ categories.get (row, 'color');
		}

		this.gui.$.navbar.style.backgroundColor = color;
	}
	
	,refreshTitle: function ()
	{
		var type = this.$.type.$.name;
		var title = type ? type : _('Catalog');
		Vn.Node.setText (this.$.title, title);
	}

	,onRightPanelClick: function (event)
	{
		event.stopPropagation ();
	}

	,onShowMenuClick: function (event)
	{
		this._menuShown = true;
		event.stopPropagation ();
		this.gui.showBackground ();
		Vn.Node.addClass (this.$.rightPanel, 'show');
		this.hideMenuCallback = this.hideMenu.bind (this);
		document.addEventListener ('click', this.hideMenuCallback);
	}

	,hideMenu: function ()
	{
		if (!this._menuShown)
			return;

		this.gui.hideBackground ();
		Vn.Node.removeClass (this.$.rightPanel, 'show');
		document.removeEventListener ('click', this.hideMenuCallback);
		this.hideMenuCallback = null;
	}
	
	,isGuest: function ()
	{
		if (localStorage.getItem ('hederaGuest'))
		{
			Htk.Toast.showError (_('YouMustBeLoggedIn'));
			return true;
		}
		
		return false;
	}
	
	,onBasketClick: function ()
	{
		if (this.isGuest ())
			return;

		this.hash.$ = {form: 'ecomerce/basket'};
	}
	
	,onConfigureClick: function ()
	{
		if (this.isGuest ())
			return;

		this.hash.$ = {form: 'ecomerce/checkout'};
	}

	,onAddItemClick: function (button)
	{
		if (this.isGuest ())
			return;

		this.onEraseClick ();
		var lot = button.lot;
		this.$.card.row = lot.row;
		this.$.cardLot.assign ({item: lot.$.id});
		this.$.cardPopup.show ();
	}
	
	,onAddLotClick: function (column, value, rowIndex)
	{
		var row = this.$.itemLots.getObject (rowIndex);
		var lotAmount = this.items[row.warehouse_id];

		if (lotAmount === undefined)
			lotAmount = 0;
		
		if (lotAmount < row.available)
		{
			var newAmount = lotAmount + row.grouping;
		
			if (newAmount > row.available)
				newAmount = row.available;
		
			this.items[row.warehouse_id] = newAmount;
			this.$.amount.value += newAmount - lotAmount;
		}
		else
			Htk.Toast.showError (_('NoMoreAmountAvailable'));
	}
	
	,onConfirmClick: function ()
	{
		var sql = '';
		var query = 'CALL basket_item_add (#warehouse, #item, #amount);';
		var amountSum = 0;

		for (var warehouse in this.items)
		{
			var amount = this.items[warehouse];
			amountSum += amount;
			
			var params = {
				item: this.$.cardLot.$.item,
				warehouse: parseInt (warehouse),
				amount: amount
			};
			sql += this.conn.renderQuery (query, params);
		}

		if (amountSum > 0)
		{
			this.conn.execQuery (sql);

			var itemName = this.$.card.$.name;
			Htk.Toast.showMessage (
				Vn.Value.sprintf (_('Added%dOf%s'), amountSum, itemName));
		}

		this.$.cardPopup.hide ();
	}
	
	,onEraseClick: function ()
	{
		this.$.amount.value = 0;
		this.items = {};
	}
	
	,onPopupClose: function ()
	{
		this.onEraseClick ();
		this.$.card.row = -1;
		this.$.cardLot.assign ({item: undefined});
	}
});

})();
