text: 'use strict';
  
  var assert = require('assert');
  
  var ElementWriter = require('../../js/ElementWriter').default;
  
  describe('ElementWriter', function () {
  	var ew, ctx, page, fakePosition;
  
  	beforeEach(function () {
  		fakePosition = { fake: 'position' };
  		page = { items: [] };
  		ctx = {
  			x: 10,
  			y: 20,
  			availableWidth: 100,
  			availableHeight: 100,
  			getCurrentPage: function () {
  				return page;
  			},
  			getCurrentPosition: function () {
  				return fakePosition;
  			},
  			moveDown: function (offset) {
  				ctx.y += offset;
  				ctx.availableHeight -= offset;
  			}
  		};
  		ew = new ElementWriter(ctx);
  
  	});
  
  	function buildLine(height, alignment, x, y) {
  		return {
  			getHeight: function () {
  				return height;
  			},
  			getWidth: function () {
  				return 60;
  			},
  			clone: function () {
  				let result = {};
  
  				for (let key in this) {
  					if (this.hasOwnProperty(key)) {
  						result[key] = this[key];
  					}
  				}
  
  				return result;
  			},
  			inlines: [
  				{
  					alignment: alignment,
  					x: 0,
  				},
  				{
  					x: 30,
  				},
  				{
  					x: 50
  				}
  			],
  			x: x,
  			y: y
  		};
  	}
  
  	describe('addLine', function () {
  		it('should add lines to the current page if there\'s enough space', function () {
  			var line = buildLine(20);
  
  			var position = ew.addLine(line);
  
  			assert.equal(page.items.length, 1);
  			assert.equal(position, fakePosition);
  		});
  
  		it('should return position on page', function () {
  			var line = buildLine(20);
  
  			ew.pushContext(50, 50);
  			ew.pushContext(20, 30);
  			ew.pushContext(11, 40);
  			var position = ew.addLine(line);
  
  			assert.equal(position, fakePosition);
  		});
  
  		it('should not add line and return false if there\'s not enough space', function () {
  			var line = buildLine(120);
  
  			assert(!ew.addLine(line));
  			assert.equal(page.items.length, 0);
  		});
  
  		it('should set line.x and line.y to current context\'s values', function () {
  			var line = buildLine(30);
  
  			ew.addLine(line);
  			assert.equal(line.x, 10);
  			assert.equal(line.y, 20);
  		});
  
  		it('should update context.y and context.availableHeight', function () {
  			ew.addLine(buildLine(30));
  			assert.equal(ctx.y, 20 + 30);
  			assert.equal(ctx.availableHeight, 100 - 30);
  		});
  
  		describe('should support line alignment', function () {
  			it('right', function () {
  				var line = buildLine(30, 'right');
  				ew.addLine(line);
  				assert.equal(line.x, 10 + 100 - line.getWidth());
  			});
  
  			it('center', function () {
  				var line = buildLine(30, 'center');
  				ew.addLine(line);
  				assert.equal(line.x, 10 + (100 - line.getWidth()) / 2);
  			});
  
  			it('justify', function () {
  				var line = buildLine(30, 'justify');
  				ew.addLine(line);
  				assert.equal(line.x, 10);
  
  				var additionalSpacing = (100 - 60) / 2;
  
  				assert.equal(line.inlines[1].x, 30 + additionalSpacing);
  				assert.equal(line.inlines[2].x, 50 + 2 * additionalSpacing);
  			});
  		});
  	});
  
  	describe('addVector', function () {
  		it('should add vectors to the current page', function () {
  			ew.addVector({ type: 'rect', x: 10, y: 10 });
  			assert.equal(page.items.length, 1);
  		});
  
  		it('should offset vectors to the current position', function () {
  			var rect = { type: 'rect', x: 10, y: 10 };
  			var ellipse = { type: 'ellipse', x: 10, y: 10 };
  			var line = { type: 'line', x1: 10, x2: 50, y1: 10, y2: 20 };
  			var polyline = { type: 'polyline', points: [{ x: 0, y: 0 }, { x: 20, y: 20 }] };
  
  			ew.addVector(rect);
  			ew.addVector(ellipse);
  			ew.addVector(line);
  			ew.addVector(polyline);
  
  			assert.equal(rect.x, 20);
  			assert.equal(rect.y, 30);
  
  			assert.equal(ellipse.x, 20);
  			assert.equal(ellipse.y, 30);
  
  			assert.equal(line.x1, 20);
  			assert.equal(line.x2, 60);
  			assert.equal(line.y1, 30);
  			assert.equal(line.y2, 40);
  
  			assert.equal(polyline.points[0].x, 10);
  			assert.equal(polyline.points[0].y, 20);
  			assert.equal(polyline.points[1].x, 30);
  			assert.equal(polyline.points[1].y, 40);
  		});
  	});
  
  	describe('addFragment', function () {
  		var fragment;
  
  		beforeEach(function () {
  			fragment = {
  				items: [
  					{
  						type: 'line',
  						item: buildLine(30, 'left', 10, 10)
  					},
  					{
  						type: 'line',
  						item: buildLine(30, 'left', 10, 50)
  					},
  					{
  						type: 'vector',
  						item: { type: 'rect', x: 10, y: 20 }
  					},
  					{
  						type: 'vector',
  						item: { type: 'rect', x: 40, y: 60 }
  					}
  				]
  			};
  		});
  
  		it('should add all fragment vectors and lines', function () {
  			ew.addFragment(fragment);
  
  			assert.equal(page.items.length, 4);
  		});
  
  		it('should return false if fragment height is larger than available space', function () {
  			fragment.height = 120;
  
  			assert(!ew.addFragment(fragment));
  		});
  
  		it('should update current position', function () {
  			fragment.height = 50;
  			ew.addFragment(fragment);
  
  			assert.equal(ctx.y, 20 + 50);
  		});
  
  		it('should offset lines and vectors', function () {
  			ew.addFragment(fragment);
  
  			assert.equal(page.items[0].item.x, 20);
  			assert.equal(page.items[0].item.y, 30);
  			assert.equal(page.items[1].item.x, 20);
  			assert.equal(page.items[1].item.y, 70);
  
  			assert.equal(page.items[2].item.x, 20);
  			assert.equal(page.items[2].item.y, 40);
  			assert.equal(page.items[3].item.x, 50);
  			assert.equal(page.items[3].item.y, 80);
  		});
  
  		it('should not modify original line/vector positions', function () {
  			ew.addFragment(fragment);
  
  			assert.equal(fragment.items[0].item.x, 10);
  			assert.equal(fragment.items[0].item.y, 10);
  
  			assert.equal(fragment.items[3].item.x, 40);
  			assert.equal(fragment.items[3].item.y, 60);
  		});
  	});
  });
  