define([ 'jquery', 'tools/tools', 'tools/validate', 'tnc/tnc-border', 'tnc/tnc-transition', 'tnc/tnc-position', 'tnc/tnc-widget', 'tools/jq-tools',
		'tools/urls', 'tools/tools-3d', 'jqDragAndMove', 'tools/numbers', 'bluebird' ], function() {
	'use strict';
	var $ = require('jquery');
	var tools = require('tools/tools');
	var urls = require('tools/urls');
	var validate = require('tools/validate');
	var numbers = require('tools/numbers');
	var TncBorder = require('tnc/tnc-border');
	var TncTransition = require('tnc/tnc-transition');
	var TncWidget = require('tnc/tnc-widget');
	var TncPosition = require('tnc/tnc-position');
	var jqTools = require('tools/jq-tools');
	// var tools3d = require('tools/tools-3d');
	var jqDrag = require('jqDragAndMove');
	var Promise = require('bluebird');

	var log = tools.log;
	// var format = tools.format;

	var getStr = validate.getStr;
	var getColor = validate.getColor;
	var getNum = validate.getNum;
	var limitOpacity = tools.limitOpacity;
	var $new = jqTools.$new;
	var del = tools.del;
	var preventEvent = tools.preventEvent;
	var round100 = numbers.round100;

	// =======
	// Layer
	function TncLayer(template, settings) {
		this.init(template, settings);
	}

	TncLayer.prototype.init = function(scope, settings) {
		var self = this;
		self.scope = scope;
		self.template = scope.template;

		self.settings = settings || {};

		self.id = getStr(self.settings.id, '');
		self.name = getStr(self.settings.name, '');
		self.backgroundColor = getColor(self.settings.backgroundColor, 'transparent');
		self.border = new TncBorder(self.settings.border);
		self.opacity = limitOpacity(getNum(self.settings.opacity, 1));
		self.repeating = self.settings.repeating || false;
		self.transition = new TncTransition(self.settings.transition, self);

		var params = urls.getQueryParams();
		self.settings.enableEdit = params['edit'] ? true : false;

		self.settings.widgets = self.settings.widgets || [];

		self.widgets = [];

		for (var i = 0; i < self.settings.widgets.length; i += 1) {
			var widgetScope = { template: scope.template, layer: self };
			var widget = new TncWidget(widgetScope, self.settings.widgets[i]);
			self.widgets.push(widget);
		}

		self.widgets.sort(function(a, b) {
			return (a.sorting - b.sorting);
		});

		self.position = new TncPosition(self.settings.position);

		self.defaultWidgetDuration = getNum(self.settings.defaultWidgetDuration, 0);
		// self.margin = new TncMargin(self.settings.margin); // LAYER
		// MARGIN ON PURPOSE DISABLED

		self.paused = false;
		self.ready = false;
		self.index = 0;
		self.widgetCounter = 0;
	};

	TncLayer.prototype.load = function($parent, reload) {
		var self = this;

		// force reload whole widget
		if (reload && self.$element) {
			self.$element.remove();
			self.$element = null;
		}

		// create layer
		if (!self.$element) {
			self.$element = $new('div', $parent);
			self.$element.addClass('tncLayerParent');

			self.$layer = $new('div', self.$element);
			self.$layer.addClass('tncLayer');
			self.$layer.addClass(self.id);

			self.$overlay = $new('div', self.$element);
			self.$overlay.addClass('tncLayerOverlay');
			if (!self.template.enableEdit) {
				self.$overlay.css('display','none');
			}

			self.$perspective = $new('div', self.$layer);
			self.$perspective.addClass('tncLayerPerspective');

			self.$container = $new('div', self.$perspective);
			self.$container.addClass('tncLayerContainer');

			self.$panelParent = $new('div', self.$container);
			self.$panelParent.addClass('tncLayerPanelParent');

			self.$panel = $new('div', self.$panelParent);
			self.$panel.addClass('tncLayerPanel');
			self.$panel.css('box-sizing', 'border-box');

			self.$content = $new('div', self.$panel);
			self.$content.addClass('tncLayerContent');

			if (self.settings.enableEdit) {
				self.$overlay.click(function(e) {
					self.setActive();
					e.preventDefault();
					return false;
				});
			}

			self.$element.click(tools.preventEvent);

			self.$panel.data('transitionType', self.transition.transitionType);
//			self.$panel.on('beforeTransition', function() {
//				var $this = $(this);
//				var vertical = false;
//				switch ($this.data('transitionType')) {
//				case 'rotate3d-top':
//				case 'rotate3d-bottom':
//					vertical = true;
//					break;
//				}
//				tools3d.create3dpanel($this, 4, vertical);
//			});

		}

		// Apply all settings
		self.applySettings();
		// self.margin.applyMargin(self.$content); // LAYER MARGIN ON
		// PURPOSE DISABLED

		self.hide();

		/*
		 * widget loading disabled for(var i=0;i<self.widgets.length;i+=1) {
		 * var widget = self.widgets[i]; widget.load(self.$content); // force
		 * reload }
		 */
	};

	TncLayer.prototype.applySettings = function() {
		var self = this;

		self.$layer.css({
			opacity : self.opacity
		});
		self.$panel.css({
			backgroundColor : self.backgroundColor
		});
		self.position.applyPosition(self.$element);
		self.border.applyBorder(self.$panel);
	};

	TncLayer.prototype.getPreloadTime = function() {
		var self = this;

		var preloadTime = 0;

		for (var i = 0; i < self.widgets.length; i += 1) {
			var widget = self.widgets[i];

			preloadTime = Math.max(widget.preloadTime, preloadTime);
		}

		return preloadTime;
	};

	TncLayer.prototype.show = function() {
		var self = this;
		self.$panel.css({
			opacity : limitOpacity(1)
		});
	};

	TncLayer.prototype.hide = function() {
		var self = this;
		self.$panel.css({
			opacity : limitOpacity(0)
		});
	};

	TncLayer.prototype.setActive = function() {
		var self = this;
		log('setactive', self.id);
		if (TncLayer.prototype.activeLayer) {
			if (TncLayer.prototype.activeLayer !== self) {
				TncLayer.prototype.activeLayer.deactivate(true);
				TncLayer.prototype.activeLayer = self;
				self.registerDragMove();

				self.template.scope.sendMessageCefhost('selection', self.id);
			}
		} else {
			TncLayer.prototype.activeLayer = self;
			self.registerDragMove();
			self.template.scope.sendMessageCefhost('selection', self.id);
		}
	};

	TncLayer.prototype.deactivate = function(newSelection) {
		var self = this;
		if (TncLayer.prototype.activeLayer === self) {
			TncLayer.prototype.activeLayer.unregisterDragMove();
			TncLayer.prototype.activeLayer = null;

			if (!newSelection) {
				self.template.scope.sendMessageCefhost('selection', '');
			}
		}
	};

	TncLayer.prototype.getSettings = function() {
		var self = this;

		function getWidgetSettings() {
			var widgetSettings = [];
			var i;
			for (i = 0; i < self.widgets.length; i += 1) {
				widgetSettings.push(self.widgets[i].getSettings());
			}
			return widgetSettings;
		}

		// Return (updated) settings from elements
		return {
			id : self.id,
			name : self.name,
			backgroundColor : self.backgroundColor,
			border : self.border.getSettings(),
			position : self.position.getSettings(),
			opacity : self.opacity,
			repeating : self.repeating,
			widgets : getWidgetSettings(),
			transition : self.transition.getSettings()
		};
	};

	TncLayer.prototype.getDuration = function() {
		var self = this;

		var duration = 0;
		duration += self.transition.duration;

		var i;
		for (i = 0; i < self.widgets.length; i += 1) {
			duration += self.widgets[i].getDuration();
		}

		return duration;
	};

	TncLayer.prototype.registerDragMove = function() {
		var self = this;

		var $target = self.$element;
		var $dragHandle = $new('div', $target).addClass('jqHandle').addClass('jqDrag');

		var $dragSE = $new('div', $target).addClass('sizeHandle').addClass('rsSE');
		var $dragS = $new('div', $target).addClass('sizeHandle').addClass('rsS');
		var $dragSW = $new('div', $target).addClass('sizeHandle').addClass('rsSW');
		var $dragW = $new('div', $target).addClass('sizeHandle').addClass('rsW');
		var $dragNW = $new('div', $target).addClass('sizeHandle').addClass('rsNW');
		var $dragN = $new('div', $target).addClass('sizeHandle').addClass('rsN');
		var $dragNE = $new('div', $target).addClass('sizeHandle').addClass('rsNE');
		var $dragE = $new('div', $target).addClass('sizeHandle').addClass('rsE');

		var handles = [];
		handles.push({
			$e : $dragHandle,
			move : jqDrag.handleDrag
		});

		handles.push({
			$e : $dragSE,
			move : jqDrag.handleResize_SouthEast
		});
		handles.push({
			$e : $dragS,
			move : jqDrag.handleResize_South
		});
		handles.push({
			$e : $dragSW,
			move : jqDrag.handleResize_SouthWest
		});
		handles.push({
			$e : $dragW,
			move : jqDrag.handleResize_West
		});
		handles.push({
			$e : $dragNW,
			move : jqDrag.handleResize_NorthWest
		});
		handles.push({
			$e : $dragN,
			move : jqDrag.handleResize_North
		});
		handles.push({
			$e : $dragNE,
			move : jqDrag.handleResize_NorthEast
		});
		handles.push({
			$e : $dragE,
			move : jqDrag.handleResize_East
		});

		function callback() {
			var parentWidth = self.$element.parent().width();
			var parentHeight = self.$element.parent().height();

			var position = self.$element.position();
			var selfWidth = self.$element.width();
			var selfHeight = self.$element.height();

			var percentageLeft = round100((position.left / parentWidth) * 100);
			var percentageTop = round100((position.top / parentHeight) * 100);
			var percentageWidth = round100((selfWidth / parentWidth) * 100);
			var percentageHeight = round100((selfHeight / parentHeight) * 100);

			self.position.fromTopLeft(percentageLeft, percentageTop, percentageWidth, percentageHeight);
			self.position.applyPosition(self.$element);

			self.template.scope.sendMessageCefhost('position', self.position.getSettings(), 'layer', self.id);

			log({
				layer : self.id,
				position : self.position.getSettings()
			});
		}

		self.$actions = $new('div', $target);
		self.$actions.addClass('layerActions');

		var $action, $icon;

		self.$actions.mouseup(preventEvent);
		self.$actions.mousemove(preventEvent);
		self.$actions.mousedown(preventEvent);

		$action = $new('div', self.$actions);
		$action.addClass('layerAction');
		$icon = $new('span', $action);
		$icon.addClass('glyphicon').addClass('glyphicon-plus');
		$action.click(function(e) {
			e.preventDefault();
			self.template.scope.sendMessageCefhost('add', 'widget');
		});

		$action = $new('div', self.$actions);
		$action.addClass('layerAction');
		$icon = $new('span', $action);
		$icon.addClass('glyphicon').addClass('glyphicon-arrow-up');
		$action.click(function(e) {
			e.preventDefault();
			self.template.scope.sendMessageCefhost('zindex', 'up');
		});
		$action.mouseup(function(e) {
			e.preventDefault();
		});

		$action = $new('div', self.$actions);
		$action.addClass('layerAction');
		$icon = $new('span', $action);
		$icon.addClass('glyphicon').addClass('glyphicon-arrow-down');
		$action.click(function(e) {
			e.preventDefault();
			self.template.scope.sendMessageCefhost('zindex', 'down');
		});
		$action.mouseup(function(e) {
			e.preventDefault();
		});

		var $container = $('.tncTemplateContent', self.$element.parent().parent());
		self.interactiveBox = new jqDrag.InteractiveBox($target, handles, callback, $container);
	};

	TncLayer.prototype.unregisterDragMove = function() {
		var self = this;

		if (self.interactiveBox) {
			self.interactiveBox.unbind();
		}

		if (self.$actions) {
			self.$actions.remove();
		}
	};

	TncLayer.prototype.pause = function() {
		var self = this;

		if (self.settings.enableEdit) {
			log('paused');
			self.paused = true;
		}
	};

	TncLayer.prototype.beforePlay = function() {
		var self = this;
		self.resetPlayList();
		return self.transition.run(self.$panel, null);
	};

	TncLayer.prototype.play = function(resume, callback) {
		var self = this;
		self.paused = false;
		self.playWidget(callback);
	};

	TncLayer.prototype.checkIfReady = function() {
		var self = this;
		if (!self.ready) {
			log('layer \'' + self.id + '\' ready!');
			self.ready = true;
			if (self.playCallback) {
				self.playCallback();
			}
		}
		setTimeout(function() {
			//if(self.template.isPlaying) {
				if (self.repeating && self.widgets.length > 0) {
					log('layer \'' + self.id + '\' repeating .. ');
					self.resetPlayList();
					self.playWidget();
				}
			//}
		}, 300);
	};

	TncLayer.prototype.getWidgetInstance = function() {
		var self = this;
		var currentWidgetIndex = self.index;
		if (currentWidgetIndex < self.widgets.length) {
			var currentWidget = self.widgets[currentWidgetIndex];
			currentWidget.widgetIndex = currentWidgetIndex;
			if (!currentWidget.data) {
				return; // widget is not loaded
			}

			var widgetInstance = currentWidget.getWidgetInstance();
			currentWidget = undefined;

			var timeoutForPreload = 0;
			var extraPreloadTime = 0;
			if (self.widgetCounter === 0) {
				timeoutForPreload = self.template.preloadTime - widgetInstance.preloadTime;
			} else {
				extraPreloadTime = widgetInstance.preloadTime;
			}

			Promise.delay(timeoutForPreload + extraPreloadTime).then(function() {
				widgetInstance.load(self.$content); // start loading
			});

			return widgetInstance;
		} else {
			self.checkIfReady();
			return null;
		}
	};

	TncLayer.prototype.playWidget = function(callback) {
		var self = this;
		if (callback) {
			self.playCallback = callback;
		}

		if (!self.widgets) {
			return;
		}

		if (self.paused) {
			return;
		}

		if (!self.widgetInstance) {
			self.widgetInstance = self.getWidgetInstance();
		}

		if (self.widgetInstance) {
			self.widgetInstance.load(self.$content)
				.then(function() {
					self.index += 1;
					self.widgetCounter += 1;
					self.widgetInstance.play(self.prevWidget).then(function() {
						setTimeout(function() {
							self.widgetInstance = null;
							self.playWidget(callback);
						}, 0);
					});
					self.prevWidget = self.widgetInstance;
				})
				.catch(function() {
					// problem while loading widget, skip playing
					// load+play next widget
					log('problem loading widget, loading next widget');
					self.index += 1;
					self.widgetInstance = null;
					self.widgetCounter += 1;
					self.playWidget(callback);
				});
		}
	};

	TncLayer.prototype.resetPlayList = function() {
		var self = this;
		self.index = 0;
	};

	TncLayer.prototype.unload = function() {
		var self = this;

		self.deactivate();

		for (var i = 0; i < self.widgets.length; i += 1) {
			self.widgets[i].unload();
			self.widgets[i] = null;
		}

		delete self.settings;
		delete self.widgets;
		delete self.playCallback;

		del(self, 'border');
		del(self, 'position');
		del(self, 'margin');
		del(self, 'transition');

		self.$element.remove();
		delete self.$element;
		self.$layer.remove();
		delete self.$layer;
		self.$overlay.remove();
		delete self.$overlay;
		self.$perspective.remove();
		delete self.$perspective;
		self.$container.remove();
		delete self.$container;
		self.$panel.remove();
		delete self.$panel;
		self.$content.remove();
		delete self.$content;

		self.prevWidget = null;

		self.unloaded = true;

		log('Layer unloaded', self);
		self = null;
	};

	return TncLayer;
});
