class Dashboard {
	//@TODO:
	// - Pouvoir indiquer que la dashboard à une taille dynamique :
	// 		- On laisse toujours 2-3 lignes de placeholder sous le dernier widget
	// 		- On recalcule le nb de lignes de placeholder en plus à afficher sous le dernier widget à chaque add / resize / move / delete d'un widget
	constructor(options) {
		this.options = $.extend({
			columnNumber : 1,
			lineNumber : 1,
			placeHolderPadding : 10
		},options);
		this.widgets = {};

	  	var grid = '<div class="dashboard-grid">';
		for(var u=0 ; u<options.lineNumber;u++){
			for(var i=0 ; i<options.columnNumber;i++){
				grid += '<div data-row="'+u+'" data-column="'+i+'" style="grid-area: '+(u+1)+" / "+(i+1)+" / "+(u+1)+" / "+(i+1)+';" class="dashboard-placeholder"><i class="fa fa-plus placeholder-add"></i></div>';
			}
		}
		grid += '</div>';

		this.grid = $(grid);
		this.options.element.addClass('dashboard-container');
		this.options.element.css({width:'100%',height:'100%'});
		this.options.element.append(this.grid);
		this.widgetTemplate = $('#dashboard-widget-template').html();
		this.placeHolders = $('.dashboard-placeholder');
		this.placeHolders.initialWidth = this.placeHolders.eq(0).outerWidth();
		this.placeHolders.initialHeight = this.placeHolders.eq(0).outerHeight();
		this.placeHolders.render = function(placeholder, offsets, delay){
			var delay = delay!=null ? delay : 200;
			var offsets = $.extend({
				rowStart: 0,
				rowEnd: 0,
				columnStart: 0,
				columnEnd: 0
			}, offsets);

			var rowStart = parseInt(placeholder.attr('data-row'))+1+parseInt(offsets.rowStart);
			var rowEnd = parseInt(placeholder.attr('data-row'))+1+parseInt(offsets.rowEnd);
			var columnStart = parseInt(placeholder.attr('data-column'))+1+parseInt(offsets.columnStart);
			var columnEnd = parseInt(placeholder.attr('data-column'))+1+parseInt(offsets.columnEnd);

			setTimeout(function(){
				placeholder.css({
					'grid-row': rowStart+'/'+rowEnd,
					'grid-column': columnStart+'/'+columnEnd,
				});
			}, delay);
		}

		this.triggers = [];

		var object = this;
		this.placeHolders.droppable({
			tolerance: 'pointer',
			classes: { "ui-droppable-hover": 'drag-over' },
			over: function(event, ui){
				//@TODO:
				// - Gérer les overflow de la grid => ex: lacher un widget en bas de gris doit recalculer le placeholder le plus bas possible sans sortir du cadre
				// - Ne pas pouvoir créer un widget dessous un widget existant
				// - Ne pas pouvoir superposer des widgets (ou en faire une option)
				var currentWidget = ui.draggable;
				var offsets = {
					rowEnd: currentWidget.attr('data-height'),
					columnEnd: currentWidget.attr('data-width')
				}
				//On custom la grid du placeholder avec la taille du widget
				object.placeHolders.render($(this), offsets, 0);
			},
			out: function(event, ui){
				//On reset la grid du placeholder
				object.placeHolders.render($(this));
			},
			drop: function(event, ui) {
				var placeholder = $(this);
				//On reset la grid du placeholder
				object.placeHolders.render(placeholder);

				var data = placeholder.data();
				var widgetId = ui.draggable.attr('data-id');

				object.widgets[widgetId].column = data.column;
				object.widgets[widgetId].row = data.row;
				object.renderPositions();
				object.trigger('move', object.widgetToArray(object.widgets[widgetId]));
			}
		});

		$(window).resize(function() {
			object.renderPositions();
		});

		$(window).mousemove(function(e){
			if(!object.resizing) return;
			$('.dashboard-widget').css('z-index', '');
			object.resizing.element.css('z-index', 1000);

			var objectPosition = object.resizing.element.position();
			object.resizing.element.css('width',(e.clientX - objectPosition.left)+'px');
			object.resizing.element.css('height',(e.clientY - objectPosition.top - 50)+'px');

			//On affiche la taille finale du widget avec de la couleur sur les placeholders pour guider le resize
 			object.placeHolders.removeClass('drag-over');
 			var width = Math.round(object.resizing.element.outerWidth() / object.placeHolders.initialWidth);
 			var height = Math.round(object.resizing.element.outerHeight() / object.placeHolders.initialHeight);
	 		var placeholder = $('.dashboard-placeholder[data-row="'+parseInt(object.resizing.row)+'"][data-column="'+parseInt(object.resizing.column)+'"]');
	 		var offsets = {
	 			rowEnd: height,
	 			columnEnd: width
	 		}
	 		object.placeHolders.render(placeholder, offsets, 0);
 			$(placeholder).addClass('drag-over');
		});
		$(window).mouseup(function(){
			if(!object.resizing) return;
			object.placeHolders.removeClass('drag-over');
			object.grid.removeClass('bordered');

			var width = Math.round(object.resizing.element.outerWidth() / object.placeHolders.initialWidth);
			var height = Math.round(object.resizing.element.outerHeight() / object.placeHolders.initialHeight);

			object.widgets[object.resizing.id].width = width;
			object.widgets[object.resizing.id].height = height;

			object.widgets[object.resizing.id].element.attr({
				'data-width': width,
				'data-height': height,
			});
			//On reset la grid du placeholder
			var placeholder = $('.dashboard-placeholder[data-row="'+parseInt(object.resizing.row)+'"][data-column="'+parseInt(object.resizing.column)+'"]');
			object.placeHolders.render(placeholder);

			object.renderPositions();
			object.trigger('resize', object.widgetToArray(object.widgets[object.resizing.id]));
			object.resizing = null;
		});

		$('.dashboard-placeholder').click(function(){
			var placeholder = $(this);
			object.trigger('placeholder-click',{
				element : placeholder,
				row: placeholder.attr('data-row'),
				column: placeholder.attr('data-column')
			});
		});
	}

	on(event,callback){
		if(!this.triggers[event]) this.triggers[event] = [];
		this.triggers[event].push(callback);

		return this;
	}

	trigger(event,data){
		if(!this.triggers[event]) return;
		if(!data) data = {};
		var abort = false;
		for(var k in this.triggers[event]){
			if(this.triggers[event][k](data) === true) abort = true;
		}
		return abort;
	}

	//Ajoute un ou plusieurs widgets
	addWidgets(widgets){
		var object = this;
		for(var k in widgets){
			var widgetOptions = $.extend({
				id: Math.floor(Math.random() * 100) + Date.now(),
				draggable: true,
				resizeable: true,
				removable: true,
				width: 1,
				height: 1,
				row: 0,
				column:0,
				options: [],
				label: 'Sans titre',
				content: "Aucun contenu"
			}, widgets[k]);

			widgetOptions.options.push({
				icon: 'fas fa-ellipsis-v',
				class: 'widget-option-configure',
				label: 'Configurer',
				click: function(element){
					object.configureWidget($(element).closest('.dashboard-widget').attr('data-id'));
				}
			});
			widgetOptions.options.push({
				icon: 'fa fa-times',
				class: 'widget-option-delete',
				label: 'Supprimer',
				click: function(element){
					object.deleteWidget($(element).closest('.dashboard-widget').attr('data-id'));
				}
			});
		  	object.addWidget(widgetOptions)
	 	}
	 	//Gestion de la disposition des widgets sur la dashboard
		this.renderPositions();
	}

	//Ajout d'un widget en fonction de paramètre
	addWidget(widgetOptions){
		var object = this;
		//Ajout du widget au tableau de widgets interne
		object.widgets[widgetOptions.id] = widgetOptions;

		//Render de la template pour les propriétés du widget courant
		object.renderContent(widgetOptions.id);

	  	var widgetElement = $(object.widgets[widgetOptions.id].element);
	  	object.grid.append(widgetElement);

	 	widgetElement.draggable({
 			handle: '.widget-header-icon, .widget-header-title',
 			containment: object.grid,
 			"ui-draggable-dragging" : "widget-dragging",
 			cursorAt: {
 				left: 7,
 				top: 10
 			},
 			start: function(event, ui){
 				var element = $(event.currentTarget);
 				if(!element.hasClass('widget-draggable')) return false;

 				$('.dashboard-widget').css('z-index','');
 				element.css('z-index',1000);
 			},
 		});
	 	widgetElement.find('.dashboard-widget-resize').mousedown(function(){
	 		var element = $(this).closest('.dashboard-widget');
	 		if(!element.hasClass('widget-resizeable')) return;
	 		object.resizing = object.widgets[element.attr('data-id')];

			//On affiche la taille finale du widget avec de la couleur sur les placeholders pour guider le resize
 			object.placeHolders.removeClass('drag-over');
 			var width = Math.round(object.resizing.element.outerWidth() / object.placeHolders.initialWidth);
 			var height = Math.round(object.resizing.element.outerHeight() / object.placeHolders.initialHeight);
	 		var placeHolder = $('.dashboard-placeholder[data-row="'+parseInt(object.resizing.row)+'"][data-column="'+parseInt(object.resizing.column)+'"]');
	 		var offsets = {
	 			rowEnd: height,
	 			columnEnd: width
	 		}
	 		object.placeHolders.render(placeHolder, offsets, 0);
 			$(placeHolder).addClass('drag-over');

	 		object.grid.addClass('bordered');
	 	});
	 	object.trigger('add', object.widgetToArray(widgetOptions));
	}

	//Supprime un widget en fonction de son id
	deleteWidget(id){
		var widget = this.widgets[id];
		if(this.trigger('delete',this.widgetToArray(widget))) return;
		this.widgets[id].element.remove();
	}

	configureWidget(id){
		
		var object = this;
		$('#dashboard-modal').off('shown.bs.modal').on('shown.bs.modal', function () {
			
			object.trigger('configure', id);
		}).modal('show');
	}

	widgetToArray(widget){
		if(!widget) return {};
		return {
		    id: widget.id,
		    draggable: widget.draggable,
		    resizeable: widget.resizeable,
		    removable: widget.removable,
		    width: widget.width,
		    height: widget.height,
		    row: widget.row,
		    column: widget.column,
		    label: widget.label,
		    content: widget.content,
		    icon: widget.icon,
		    headerBackground: widget.headerBackground
		};
	}

	//Render d'un widget en fonction de ses paramètres
	//Gère le refresh du widget si l'élément est déjà existant
	renderContent(id) {
		
		var widget = this.widgets[id];
		var widgetElement = widget.element!=null ? widget.element : $(Mustache.render(this.widgetTemplate, widget));
		if(widget.label !== null) widgetElement.find('.widget-header-title').html(widget.label);
		if(widget.icon !== null){
			widgetElement.find('.widget-header-icon i').attr('class', widget.icon);
		}
		if(widget.headerBackground !== null) widgetElement.find('.dashboard-widget-header').css('backgroundColor',widget.headerBackground);
		if(widget.bodyBackground !== null) widgetElement.find('.dashboard-widget-content').css('backgroundColor',widget.bodyBackground);
		if(widget.titleColor !== null) widgetElement.find('.widget-header-title,.widget-header-options').css('color',widget.titleColor);
		if(widget.iconColor !== null) widgetElement.find('.widget-header-icon i').css('color',widget.iconColor);

		if(widget.options !== null){
			var tpl = '<li class="{{class}}" title="{{label}}"><i class="{{icon}}"></i></li>';
			widgetElement.find('.widget-header-options').html('');
			for(var u in widget.options){
				var option = $(Mustache.render(tpl, widget.options[u]));

				if(widget.options[u].click){
					option.data('click',widget.options[u].click);
					option.click(function(){
						$(this).data('click')(this);
					});
				}
				widgetElement.find('.widget-header-options').append(option);
			}
		}
		widgetElement
			.toggleClass('widget-draggable', widget.draggable)
			.toggleClass('widget-resizeable', widget.resizeable)
			.toggleClass('widget-removable', widget.removable);
		if(widget.content !== null) widgetElement.find('.dashboard-widget-content').html(widget.content);

		widget.element = widgetElement;
	}

	//Rafraichit le contenu des widgets en fonction du tableau de widgets interne
	renderContents() {
		for(var k in this.widgets){
			var widget = this.widgets[k];
			this.renderContent(widget.id);
		}
	}

	//Resize / Replace les widgets en fonction de la taille de la fenetre et des cellules de grilles
	renderPositions(){
		var placeholderWidth = this.placeHolders.initialWidth;
		var placeholderHeight = this.placeHolders.initialHeight;
		for(var k in this.widgets){
			var widget = this.widgets[k];
			var cell = $('[data-row="'+widget.row+'"][data-column="'+widget.column+'"]').position();
			if(!cell) continue;
			widget.element.css({
				width: ((widget.width * placeholderWidth)-(this.options.placeHolderPadding*2))+'px',
				height: ((widget.height * placeholderHeight)-(this.options.placeHolderPadding*2))+'px',
				top: (cell.top+this.options.placeHolderPadding)+'px',
				left: (cell.left+this.options.placeHolderPadding)+'px'
			});
		}
	}
}