
Hedera.ShelvesReport = new Class
({
	Extends: Hedera.Report

	,nItem: -1
	,nColors: 5
	,trayThickness: 2
	,trayMargin: 5
	
	,activate: function (lot)
	{
		var params = lot.params;
		Object.assign (this, {
			title: params.reportTitle,
			maxAmount: params.maxAmount,
			showPacking: params.showPacking,
			stack: params.stack,
			useIds: params.useIds
		});

		var query =
			'SELECT id, name, nTrays, topTrayHeight, trayHeight, width, depth '+
				'FROM shelf WHERE id = #shelf; '+
			'CALL itemAllocator (#warehouse, #date, #family, #namePrefix, #useIds)';
		this.conn.execQuery (query,
			this.onQueryExec.bind (this), params);
	}
	
	,onQueryExec: function (resultSet)
	{
		// Fetch query data

		var row = resultSet.fetchObject ();
		
		// Calculates the scale
		
		var maxWidth = 160;
		var maxHeight = 160;
		
		var shelfWidth = row.width;
		var shelfHeight = row.trayHeight * (row.nTrays - 1) + row.topTrayHeight;
		
		var scale = maxWidth / shelfWidth;
		
		if (shelfHeight * scale > maxHeight)
			scale = maxHeight / shelfHeight;
			
		// Calculates the shelf dimensions
		
		var shelf = this.shelf =
		{
			 nTrays: row.nTrays
			,trayHeight: row.trayHeight * scale
			,topTrayHeight: row.topTrayHeight * scale
			,width: row.width * scale
			,depth: row.depth * scale
		};

		// Gets the items
		
		var items = this.items = [];
		var remainings = this.remainings = [];
		var res = resultSet.fetchResult ();
		
		if (res.data.length == 0)
		{
			Htk.Toast.showError (_('No items found, check that all fields are correct'));
			return;
		}
		
		var boxScale = scale * 10;
		
		while (row = res.fetchObject ())
		if (!this.maxAmount || row.etiquetas <= this.maxAmount)
		{
			items.push ({
				 id: row.Id_Article
				,name: row.Article
				,packing: row.packing
				,amount: row.etiquetas
				,boxHeight: row.z * boxScale
				,boxWidth: row.x * boxScale
				,boxDepth: row.y * boxScale
			});
		}
		else
		{
			remainings.push ({
				 id: row.Id_Article
				,name: row.Article
				,packing: row.packing
				,amount: row.etiquetas
			});
		}

		// Intializes the allocator
			
		alloc = this.alloc = new Vn.Allocator ();
		Object.assign (alloc, {
			items: items,
			shelfFunc: this.drawShelf.bind (this),
			boxFunc: this.drawBox.bind (this),
			stack: this.stack,
			nTrays: shelf.nTrays,
			width: shelf.width,
			depth: shelf.depth,
			trayHeight: shelf.trayHeight,
			topTrayHeight: shelf.topTrayHeight,
		});
		
		// Opens the report
		
		this.renderReport ();
	}
	
	,renderReport: function ()
	{
		// Remaining amount
		
		var remainings = this.remainings;
		
		if (remainings.length > 0)
		{
			var sheet = this.doc.createElement ('div');
			sheet.className = 'sheet remaining';
			this.body.appendChild (sheet);
			
			var title = this.doc.createElement ('h1');
			title.className = 'title';
			title.appendChild (this.doc.createTextNode (this.title));
			sheet.appendChild (title);
		
			var subtitle = this.doc.createElement ('h2');
			subtitle.className = 'subtitle';
			subtitle.appendChild (this.doc.createTextNode (_('Pallets')));
			sheet.appendChild (subtitle);
			
			var ul = this.doc.createElement ('table');
			sheet.appendChild (ul);
	
			for (var i = 0; i < remainings.length; i++)
			{
				var li = this.doc.createElement ('tr');
				ul.appendChild (li);

				var span = this.doc.createElement ('td');
				span.className = 'item-id';
				span.appendChild (this.doc.createTextNode (remainings[i].id.toLocaleString ()));
				li.appendChild (span);
			
				var span = this.doc.createElement ('td');
				span.className = 'item';
				span.appendChild (this.doc.createTextNode (remainings[i].name));
				li.appendChild (span);
				
				if (this.showPacking)
					span.appendChild (this.doc.createTextNode (' '+ remainings[i].packing));

				var span = this.doc.createElement ('td');
				span.className = 'amount';
				span.appendChild (this.doc.createTextNode (remainings[i].amount));
				li.appendChild (span);
			}
		}
		
		// Draws the shelves

		this.alloc.run ();
		this.drawShelfRange (this.lastItem, false);
	}

	,drawShelf: function (allocator, item)
	{
		var shelf = this.shelf;

		var sheet = this.doc.createElement ('div');
		sheet.className = 'sheet';
		this.body.appendChild (sheet);
		
		// Draws the title
		
		var pageNumber = this.doc.createElement ('h1');
		pageNumber.className = 'page-number';
		pageNumber.appendChild (this.doc.createTextNode (allocator.currentShelf + 1));
		sheet.appendChild (pageNumber);
		
		var title = this.doc.createElement ('h1');
		title.className = 'title';
		title.appendChild (this.doc.createTextNode (this.title));
		sheet.appendChild (title);
	
		if (this.subtitles)
			this.drawShelfRange (this.lastItem, false);

		this.subtitles = this.doc.createElement ('div');
		sheet.appendChild (this.subtitles);
		
		this.drawShelfRange (item, true);
		this.lastSubtitles = this.subtitles;

		// Draws the shelf
		
		var trayWidth = shelf.width + this.trayMargin * 2;
		var shelfHeight = shelf.trayHeight * (shelf.nTrays - 1) + shelf.topTrayHeight
			+ (this.trayThickness + this.trayMargin) * shelf.nTrays;
		
		var shelfDiv = this.shelfDiv = this.doc.createElement ('div');
		shelfDiv.className = 'shelf';
		shelfDiv.style.width = this.mm (trayWidth);
		shelfDiv.style.height = this.mm (shelfHeight);
		sheet.appendChild (shelfDiv);

		// Draws trays

		for (var i = 0; i < shelf.nTrays; i++)
		{
			var tray = this.doc.createElement ('div');
			tray.className = 'tray';
			tray.style.bottom = this.mm ((shelf.trayHeight + this.trayThickness + this.trayMargin) * i);
			tray.style.width = this.mm (trayWidth);
			tray.style.height = this.mm (this.trayThickness);
			shelfDiv.appendChild (tray);
		}
	}
	
	,drawShelfRange: function (item, isFirst)
	{
		var labelText = isFirst ? _('Start') : _('End');
	
		var label = this.doc.createElement ('label');
		label.className = 'range-label';
		label.appendChild (this.doc.createTextNode (labelText));
		this.subtitles.appendChild (label);

		var subtitle = this.doc.createElement ('h2');
		subtitle.className = 'subtitle';
		subtitle.appendChild (this.doc.createTextNode (this.getItemLabel (item)));
		this.subtitles.appendChild (subtitle);
	}
	
	,getItemLabel: function (item)
	{
		if (!this.useIds)
		{
			var packing = this.showPacking ? (' x'+ item.packing) : '';
			return item.name + packing;
		}
		else
			return item.id.toLocaleString ();
	}

	,mm: function (size)
	{
		size *= 0.24;
		return size.toFixed (2) +'em';
	}

	,drawBox: function (allocator, item, amount)
	{
		if (item.boxWidth == 0 || item.boxHeight == 0)
			return;

		var shelf = this.shelf;

		var x = allocator.trayX + this.trayMargin;
		var y = allocator.trayY + this.trayThickness
			+ this.trayMargin * allocator.currentTray
			+ allocator.currentTray * (shelf.trayHeight + this.trayThickness);

		var box = this.doc.createElement ('div');
		box.className = 'box';
		this.shelfDiv.appendChild (box);
		
		box.style.left = this.mm (x);
		box.style.bottom = this.mm (y);
		box.style.width = this.mm (item.boxWidth);
		box.style.height = this.mm (item.boxHeight);
	
		if (amount == 0)
			this.nItem++;

		var nColor = this.nItem % this.nColors;
		Vn.Node.addClass (box, 'color'+ nColor);

		if (amount == 0 || allocator.firstShelfBox)
		{	
			var boxLabel = this.doc.createElement ('div');
			
			if (this.useIds)
			{
				var fontSize = item.boxWidth / 5.2;
			
				if (fontSize > item.boxHeight - 1)
					fontSize = item.boxHeight - 1;
		
				boxLabel.style.fontSize = this.mm (fontSize);

				var cssClass = 'id';			
			}
			else
				var cssClass = 'name';

			boxLabel.className = 'box-label '+ cssClass;

			var labelText = this.doc.createTextNode (this.getItemLabel (item));
			boxLabel.appendChild (labelText);
			
			box.appendChild (boxLabel);
		}

		this.lastItem = item;
	}
});

Vn.Allocator = new Class
({
	addShelf: function (item)
	{
		this.currentShelf++;
		this.firstShelfBox = true;
	
		if (this.shelfFunc)
			this.shelfFunc (this, item);
	}

	,addTray: function (item)
	{
		if (this.currentTray <= 0)
		{
			this.addShelf (item);
			this.currentTray = this.nTrays - 1;
		}
		else
			this.currentTray--;
		
		this.trayX = 0;
	}

	,addColumn: function (item)
	{
		if (this.trayX + this.columnWidth + item.boxWidth > this.width
		|| this.currentTray == -1)
			this.addTray (item);
		else
			this.trayX += this.columnWidth;

		this.trayY = 0;
		this.columnWidth = item.boxWidth;
		this.lastBoxWidth = item.boxWidth;
	}

	,addBox: function (item, amount)
	{
		var trayHeight = this.trayHeight;
	
		if (this.currentTray == this.nTrays - 1)
			trayHeight = this.topTrayHeight;

		if (this.trayY + item.boxHeight > trayHeight
		|| item.boxWidth > this.lastBoxWidth
		|| (!this.stack && amount == 0))
			this.addColumn (item);

		if (this.boxFunc)
			this.boxFunc (this, item, amount);

		this.trayY += item.boxHeight;
	
		if (item.boxWidth < this.lastBoxWidth)
			this.lastBoxWidth = item.boxWidth;
	}

	,run: function ()
	{
		this.firstShelfBox = false;
		this.currentShelf = -1;
		this.currentTray = -1;
		this.columnWidth = 0;
		this.lastBoxWidth = 0;
		this.trayX = 0;
		this.trayY = 0;
		this.remaining = false;

		for (var i = 0; i < this.items.length; i++)
		{
			var item = this.items[i];
			var boxIncrement = Math.floor (this.depth / item.boxDepth);
			
			if (boxIncrement < 1)
				boxIncrement = 1;
		
			for (var amount = 0; amount < item.amount; amount += boxIncrement)
			{
				this.addBox (item, amount);
				this.firstShelfBox = false;
			}
		}
	
		return this.currentShelf + 1;
	}
	
});
