var ResponsiveLayout = function(table){
	this.table = table; //hold Tabulator object
	this.columns = [];
	this.hiddenColumns = [];
	this.mode = "";
	this.index = 0;
	this.collapseFormatter = [];
	this.collapseStartOpen = true;
};

//generate resposive columns list
ResponsiveLayout.prototype.initialize = function(){
	var self = this,
	    columns = [];

	this.mode = this.table.options.responsiveLayout;
	this.collapseFormatter = this.table.options.responsiveLayoutCollapseFormatter || this.formatCollapsedData;
	this.collapseStartOpen = this.table.options.responsiveLayoutCollapseStartOpen;
	this.hiddenColumns = [];

	//detemine level of responsivity for each column
	this.table.columnManager.columnsByIndex.forEach(function(column, i){
		if(column.modules.responsive){
			if(column.modules.responsive.order && column.modules.responsive.visible){
				column.modules.responsive.index = i;
				columns.push(column);

				if(!column.visible && self.mode === "collapse"){
					self.hiddenColumns.push(column);
				}
			}
		}
	});

	//sort list by responsivity
	columns = columns.reverse();
	columns = columns.sort(function(a, b){
		var diff = b.modules.responsive.order - a.modules.responsive.order;
		return diff || (b.modules.responsive.index - a.modules.responsive.index);
	});

	this.columns = columns;

	if(this.mode === "collapse"){
		this.generateCollapsedContent();
	}
};

//define layout information
ResponsiveLayout.prototype.initializeColumn = function(column){
	var def = column.getDefinition();

	column.modules.responsive = {order: typeof def.responsive === "undefined" ? 1 : def.responsive, visible:def.visible === false ? false : true};
};

ResponsiveLayout.prototype.layoutRow = function(row){
	var rowEl = row.getElement(),
	el = document.createElement("div");

	el.classList.add("tabulator-responsive-collapse");

	if(!rowEl.classList.contains("tabulator-calcs")){
		row.modules.responsiveLayout = {
			element:el,
		};

		if(!this.collapseStartOpen){
			el.style.display = 'none';
		}

		rowEl.appendChild(el);

		this.generateCollapsedRowContent(row);
	}
};

//update column visibility
ResponsiveLayout.prototype.updateColumnVisibility = function(column, visible){
	var index;
	if(column.modules.responsive){
		column.modules.responsive.visible = visible;
		this.initialize();
	}
};

ResponsiveLayout.prototype.hideColumn = function(column){
	column.hide(false, true);

	if(this.mode === "collapse"){
		this.hiddenColumns.unshift(column);
		this.generateCollapsedContent();
	}
};

ResponsiveLayout.prototype.showColumn = function(column){
	var index;

	column.show(false, true);
	//set column width to prevent calculation loops on uninitialized columns
	column.setWidth(column.getWidth());

	if(this.mode === "collapse"){
		index = this.hiddenColumns.indexOf(column);

		if(index > -1){
			this.hiddenColumns.splice(index, 1);
		}

		this.generateCollapsedContent();
	}
};

//redraw columns to fit space
ResponsiveLayout.prototype.update = function(){
	var self = this,
	working = true;

	while(working){

		let width = self.table.modules.layout.getMode() == "fitColumns" ? self.table.columnManager.getFlexBaseWidth() : self.table.columnManager.getWidth();

		let diff = (self.table.options.headerVisible ? self.table.columnManager.element.clientWidth : self.table.element.clientWidth) - width;

		if(diff < 0){
			//table is too wide
			let column = self.columns[self.index];

			if(column){
				self.hideColumn(column);
				self.index ++;
			}else{
				working = false;
			}

		}else{

			//table has spare space
			let column = self.columns[self.index -1];

			if(column){
				if(diff > 0){
					if(diff >= column.getWidth()){
						self.showColumn(column);
						self.index --;
					}else{
						working = false;
					}
				}else{
					working = false;
				}
			}else{
				working = false;
			}
		}

		if(!self.table.rowManager.activeRowsCount){
			self.table.rowManager.renderEmptyScroll();
		}
	}
};

ResponsiveLayout.prototype.generateCollapsedContent = function(){
	var self = this,
	rows = this.table.rowManager.getDisplayRows();

	rows.forEach(function(row){
		self.generateCollapsedRowContent(row);
	});
};

ResponsiveLayout.prototype.generateCollapsedRowContent = function(row){
	var el, contents;

	if(row.modules.responsiveLayout){
		el = row.modules.responsiveLayout.element;

		while(el.firstChild) el.removeChild(el.firstChild);

		contents = this.collapseFormatter(this.generateCollapsedRowData(row));
		if(contents){
			el.appendChild(contents);
		}
	}
};

ResponsiveLayout.prototype.generateCollapsedRowData = function(row){
	var self = this,
	data = row.getData(),
	output = [],
	mockCellComponent;

	this.hiddenColumns.forEach(function(column){
		var value = column.getFieldValue(data);

		if(column.definition.title && column.field){
			if(column.modules.format && self.table.options.responsiveLayoutCollapseUseFormatters){

				mockCellComponent = {
					value:false,
					data:{},
					getValue:function(){
						return value;
					},
					getData:function(){
						return data;
					},
					getElement:function(){
						return document.createElement("div");
					},
					getRow:function(){
						return row.getComponent();
					},
					getColumn:function(){
						return column.getComponent();
					},
				};

				output.push({
					title: column.definition.title,
					value: column.modules.format.formatter.call(self.table.modules.format, mockCellComponent, column.modules.format.params)
				});
			}else{
				output.push({
					title: column.definition.title,
					value: value
				});
			}
		}
	});

	return output;
};

ResponsiveLayout.prototype.formatCollapsedData = function(data){
	var list = document.createElement("table"),
	listContents = "";

	data.forEach(function(item){
		var div = document.createElement("div");

		if(item.value instanceof Node){
			div.appendChild(item.value);
			item.value = div.innerHTML;
		}

		listContents += "<tr><td><strong>" + item.title + "</strong></td><td>" + item.value + "</td></tr>";
	});

	list.innerHTML = listContents;

	return Object.keys(data).length ? list : "";
};

Tabulator.prototype.registerModule("responsiveLayout", ResponsiveLayout);
