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

	,nItem: -1
	,nColors: 5
	,trayThickness: 2
	,trayMargin: 5
	
	,open: function(batch) {
		this.batch = batch;
		this.title = batch.getValue('reportTitle');
		this.maxAmount = batch.getValue('maxAmount');
		this.showPacking = batch.getValue('showPacking');
		this.stack = batch.getValue('stack');
		this.useIds = batch.getValue('useIds');
	
		var query =
			'SELECT id, name, nTrays, topTrayHeight, trayHeight, width, depth '+
				'FROM shelf WHERE id = #shelf; '+
			'CALL item_listAllocation(#warehouse, #date, #family, #namePrefix, #useIds)';
		
		this.conn.execQuery(query, this.onQueryExec.bind(this), this.batch);
	}
	
	,onQueryExec: function(resultSet) {
		// Fetch query data

		var res = resultSet.fetchResult();
		res.next();
		
		// Calculates the scale
		
		var maxWidth = 160;
		var maxHeight = 160;
		
		var shelfWidth = res.get('width');
		var shelfHeight = res.get('trayHeight') * (res.get('nTrays') - 1) + res.get('topTrayHeight');
		
		var scale = maxWidth / shelfWidth;
		
		if (shelfHeight * scale > maxHeight)
			scale = maxHeight / shelfHeight;
			
		// Calculates the shelf dimensions
		
		var shelf = this.shelf =
		{
			 nTrays: res.get('nTrays')
			,trayHeight: res.get('trayHeight') * scale
			,topTrayHeight: res.get('topTrayHeight') * scale
			,width: res.get('width') * scale
			,depth: res.get('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 (res.next())
		if (!this.maxAmount || res.get('etiquetas') <= this.maxAmount) {
			items.push({
				 id: res.get('Id_Article')
				,name: res.get('Article')
				,packing: res.get('packing')
				,amount: res.get('etiquetas')
				,boxHeight: res.get('height') * boxScale
				,boxWidth: res.get('width') * boxScale
				,boxDepth: res.get('depth') * boxScale
			});
		} else {
			remainings.push({
				 id: res.get('Id_Article')
				,name: res.get('Article')
				,packing: res.get('packing')
				,amount: res.get('etiquetas')
			});
		}

		// Intializes the allocator
			
		alloc = this.alloc = new Vn.Allocator();
		alloc.items = items;
		alloc.shelfFunc = this.drawShelf.bind(this);
		alloc.boxFunc = this.drawBox.bind(this);
		alloc.stack = this.stack;
		alloc.nTrays = shelf.nTrays;
		alloc.width = shelf.width;
		alloc.depth = shelf.depth;
		alloc.trayHeight = shelf.trayHeight;
		alloc.topTrayHeight = shelf.topTrayHeight;
		
		// Opens the report
		
		this.createWindow();
	}
	
	,onWindowCreate: function() {	
		// Remaining amount
		
		var remainings = this.remainings;
		
		if (remainings.length > 0) {
			var sheet = this.doc.createElement('div');
			sheet.className = 'sheet';
			this.doc.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('ul');
			sheet.appendChild(ul);
	
			for (var i = 0; i < remainings.length; i++) {
				var li = this.doc.createElement('li');
				ul.appendChild(li);

				var span = this.doc.createElement('span');
				span.className = 'item-id';
				span.appendChild(this.doc.createTextNode(remainings[i].id.toLocaleString()));
				li.appendChild(span);
			
				var span = this.doc.createElement('span');
				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('span');
				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.doc.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) {
		return size.toFixed(2) +'mm';
	}

	,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;
	}
});