/*
 * codepunch-datatable
 *
 * Copyright (c) 2020-2021, CodePunch Solutions.
 * https://codepunch.com
 * Author: Anil Kumar
 * 
 */

class DataTableView {

	static _DATATABLES = {};
	static _tableInFocus = '';
	static _filterInFocus = '';

	static getTable(tableid) {
		if(DataTableView._DATATABLES.hasOwnProperty(tableid)) 
			return DataTableView._DATATABLES[tableid];
		return undefined;
	}

	static removeTable(tableid) {
		if(DataTableView._DATATABLES.hasOwnProperty(tableid)) {
			delete DataTableView._DATATABLES[tableid];
			return true;
		}
		return false;
	}

	static setTheme(theme) {
		for(var tableid in DataTableView._DATATABLES) {
			if( DataTableView._DATATABLES.hasOwnProperty(tableid)) {
				DataTableView._DATATABLES[tableid].setOption('thememode', theme);
				DataTableView._DATATABLES[tableid].themeChanged();
			}
		}
	}

	constructor(elem, options) {
		this.options = { 
			table: elem,
			idcolumn: 'id',
			parent: '',
			sortorder:'asc', 
			sort: null,
			data: null,
			totalrows: 0,
			start: 0,
			count: 500,
			page: 0,
			totalpages: 0,
			columns: null,
			footer: [],
			filters: {},
			source: null,
			handlers: {},
			thememode: current_theme_name,		// dark or light mode
			outerparent: 'body'  // an outer element id
		};
		DataTableView._DATATABLES[elem] = this;
		this.last_checked_index = -1;
		this.last_highlighted_rowid = -1;

		for(var opt in options) {
			if(options.hasOwnProperty(opt)) {
				this.setOption(opt, options[opt]);
			}
		}

		var dtv = this;
		$(this.options.outerparent).off('click', '#'+ elem + ' .th-sortable');
		$(this.options.outerparent).on('click', '#'+ elem + ' .th-sortable', function(event) {
			var column = $(this).attr("data-column");
			dtv.sort(column);
		});

		$(this.options.outerparent).off('click', '#'+ elem + ' .th-cb-select-all');
		$(this.options.outerparent).on('click', '#'+ elem + ' .th-cb-select-all', function(event) {
			$(".tcb-" + dtv.options.table).prop('checked', $(this).is(":checked"));
		});

		$(this.options.outerparent).off('click', '#'+ elem + ' > .tr-rowid');
		$(this.options.outerparent).on('click', '#'+ elem + ' > .tr-rowid', function(event) {
			event.stopPropagation();
			//var rowid = parseInt($(this).attr("data-id"));
			var rowid = $(this).attr("data-id");
			if(dtv.options.handlers && dtv.options.handlers.select)
				dtv.options.handlers.select(rowid);
			var table = dtv.options.table;
			$('#' + table + ' .tr-rowid').removeClass('tr-selected');
			$(this).addClass('tr-selected');
			var serialid = $(this).data("serial");
			if(!event.shiftKey && !event.ctrlKey) {
				$(".tcb-" + dtv.options.table).prop('checked', false);
				$("#tcb-" + dtv.options.table + "-did-" + rowid).prop('checked', true);
			}
			else if(event.shiftKey) {
				var start = (dtv.last_checked_index < serialid) ? dtv.last_checked_index : serialid;
				var end = (dtv.last_checked_index > serialid) ? dtv.last_checked_index : serialid;
				if(start >= 0 && end > start) {
					$(".tcb-" + dtv.options.table).prop('checked', false);
					for(var i = start; i <= end; i++) {
						var id = $("#"+dtv.options.table).find(`[data-serial='${i}']`).data('id');
						$("#tcb-" + dtv.options.table + "-did-" + id).prop('checked', true);
					}
				}
			}
			else {
				if(event.ctrlKey) {
					if ($("#tcb-" + dtv.options.table + "-did-" + rowid).is(':checked'))
						$("#tcb-" + dtv.options.table + "-did-" + rowid).prop('checked', false);
					else
						$("#tcb-" + dtv.options.table + "-did-" + rowid).prop('checked', true);
				}
			}
			if ($("#tcb-" + dtv.options.table + "-did-" + rowid).is(':checked'))
				dtv.last_checked_index = serialid;
			dtv.last_highlighted_rowid = rowid;
		});

		var wto;
		$(this.options.outerparent).off('keyup', '#'+ elem + ' .filter-input');
		$(this.options.outerparent).on('keyup', '#'+ elem + ' .filter-input', function(event) {
			var column = $(this).attr("data-column");
			var tableid = dtv.options.table;
			var word = $(this).val();
			clearTimeout(wto);
			wto = setTimeout(function() {
				var changed = false;
				if (dtv.options.filters.hasOwnProperty(column)) {
					if(word == "") {
						delete dtv.options.filters[column];
						changed = true;
					}
					else if(dtv.options.filters[column] != word) {
						dtv.options.filters[column] = word;
						changed = true;
					}
				}
				else if(word !== "") {
					dtv.options.filters[column] = word;
					changed = true;
				}
				DataTableView._tableInFocus = tableid;
				DataTableView._filterInFocus = column;
				if(changed) {
					dtv.reload();
				}
			}, 600);
		});

		if(Object.keys(DataTableView._DATATABLES).length == 1) {
			$(this.options.outerparent).off('click', 'btn-datatable');
			$(this.options.outerparent).on('click', '.btn-datatable', function(event) {
				var id = $(this).attr('data-id');
				var parts = id.split(':');
				if(parts.length == 2) {
					var command = parts[0];
					if(command == 'popup') {
						new PopupPanel(parts[1]);
					}
					else if(command == "event") {
						var fnName = parts[1];
						try {
							if(typeof window[fnName] == "function")
								return window[fnName]();
						}
						catch(err) {
							console.log('Error: '+ fnName + ': ' + err);
						}
					}
					else {
						var tableid = parts[1];
						var thetable = DataTableView.getTable(tableid);
						if(thetable) {
							if(command == "reload" || command == 'refresh')
								thetable.reload();
							else if(command == "copy")
								thetable.copy();
							else if(command == "download")
								thetable.download();
							else if(command.indexOf('nav-') == 0)
								thetable.navigate(command.substr(4));
						}
					}
				}
			});
		}

		if(this.options.handlers['columns']) {
			this.getColumns();
		}
		
		//$(window).bind('resize', function() {dtv.reload()});
	}
	
	setFilter(column, value, refresh, setfocus=true) {
		this.options.filters[column] = value;
		if(refresh) {
			if(setfocus)
				DataTableView._tableInFocus = this.options.table;
			DataTableView._filterInFocus = column;
			this.reload();
		}
	}

	setOption(key, value) {
        this.options[key] = value;
    }

	setHandler(key, handler) {
		if(!this.options.handlers)
			this.options.handlers = {[key]:handler};
		else
			this.options.handlers[key] = handler;
	}

	themeChanged() {
		this._createFooter();
	}

	navigate(command) {
		if(command == 'next')
			this.navToPage(1);
		else if(command == 'last')
			this.navToPage("last");
		else if(command == 'previous')
			this.navToPage(-1);
		else if(command == 'first')
			this.navToPage(0);
		else if(command == 'top')
			this.navToTop();
		else if(command == 'bottom')
			this.navToBottom();
	}

	navToPage(pi) {
		var cpage = this.options.page;
		var total = this.options.totalrows;
		var current = this.options.start;
		var rowsperpage = this.options.count;
		if(rowsperpage) {
			var newpage = 0;
			if(pi == 'last')
				newpage = this.options.totalpages-1;
			else if(pi == 0)
				newpage = 0;
			else
				newpage = this.options.page+pi;
			if(newpage >= 0 && newpage < this.options.totalpages) {
				this.options.page = newpage;
				this.options.start = newpage*this.options.count;
			}
		}
		if(this.options.page != cpage)
			this.reload('',false);
	}
	
	navToBottom() {
		var parent = $('#'+this.options.table).parent();
		if(parent.hasClass('dtcard-body')) {
			var elem = parent.get(0);
			elem.scrollTop = elem.scrollHeight;
		}
	}
	
	navToTop() {
		var parent = $('#'+this.options.table).parent();
		if(parent.hasClass('dtcard-body')) {
			var elem = parent.get(0);
			elem.scrollTop = 0;
		}
	}

	_createFooter() {
		var htmlbuttons = '';
		for(var i = 0; i < this.options.footer.length; i++) {
			var btn = this.options.footer[i];
			var action = btn['action'] ? btn.action : '';
			var icon = btn['icon'] ? btn.icon : '';
			var role = btn['role'] ? btn.role : '';
			if(action != '') {
				var btnclass = 'btn-dt-footer btn-datatable';
				var bg = 'background-image: url(' + this.iconPath(icon) + ');';
				var tooltip = btn['tooltip'] ? btn['tooltip'] : role;
				htmlbuttons += this.wrap('div', '&nbsp;', {'data-icon': icon, 'data-id': action, class: btnclass, style:bg, title: tooltip});
			}
			else if(role == "separator") {
				htmlbuttons += this.wrap('div', '', {class: 'btn-dt-separator'});
			}
			else {
				if(role == 'copy' && icon == '')
					icon = 'clipboard-copy';
				else if(role == 'download' && icon == '')
					icon = 'button-download';
				else if(role == 'refresh' && icon == '')
					icon = 'symbol-refresh';
				else if(role == 'delete' && icon == '')
					icon = 'trash';
				else if(role == 'add' && icon == '')
					icon = 'button-add';
				var tooltip = btn['tooltip'] ? btn['tooltip'] : role;
				var btnclass = 'btn-dt-footer btn-datatable';
				var bg = 'background-image: url(' + this.iconPath(icon) + ');';
				htmlbuttons += this.wrap('div', '&nbsp;', {'data-icon': icon, 'data-id': role+':'+this.options.table, class: btnclass, style:bg, title: tooltip});
			}
		}

		var htmlnav = '';
		var nav = [
			{icon:'first-page', role: 'nav-first', tooltip: 'First Page'},
			{icon:'chevron-left', role: 'nav-previous', tooltip: 'Previous Page'},
			{icon:'chevron-right', role: 'nav-next', tooltip: 'Next Page'},
			{icon:'last-page', role: 'nav-last', tooltip: 'Last Page'},
			{icon:'expand-less', role: 'nav-top', tooltip: 'Scroll To Top'},
			{icon:'expand-more', role: 'nav-bottom', tooltip: 'Scroll To Bottom'}
		];
		var btnclass = 'btn-dt-footer btn-datatable';
		for(var i = 0; i < nav.length; i++) {
			let nicon = nav[i]['icon'];
			let nrole = nav[i]['role'];
			let tooltip = nav[i].tooltip;
			let bg = 'background-image: url(' + this.iconPath(nicon) + ');';
			htmlnav += this.wrap('div', '&nbsp;', {'data-icon': nicon, 'data-id': nrole+':'+this.options.table, class: btnclass, style:bg, title: tooltip});
		}

		var parent = $('#'+this.options.table).parent();
		if(parent.hasClass('dtcard-body')) {
			parent = parent.parent();
			if(parent.hasClass('dtcard')) {
				var cf = parent.find('.dtcard-footer');
				if(cf) {
					var divs = '<div class"left">' + htmlbuttons + '</div>';
					divs += '<div class="mid">' + htmlnav + '</div>';
					divs += '<div class="right"></div>';
					cf.html(divs);
				}
			}
		}
		this.showStats();
	}
	
	iconPath(nicon) {
		if(this.options.handlers && this.options.handlers.iconPath)
			return this.options.handlers.iconPath(nicon);
		else
			return '/images/icons/' + this.options.thememode + '/128/' + nicon + '@128px.png';
	}

	_showStats(msg, pos='right') {
		var parent = $('#'+this.options.table).parent();
		if(parent.hasClass('dtcard-body') && (pos == 'mid' || pos == 'right')) {
			parent = parent.parent();
			if(parent.hasClass('dtcard')) {
				var cf = parent.find('.dtcard-footer');
				if(cf) {
					cf.find('.'+pos).html(msg);
				}
			}
		}
	}

	hideNav() {
		if(this.options.count >= this.options.totalrows || !this.options.totalrows)
			this._showStats('', 'mid');
	}

	showStats() {
		var msg = '';
		if(this.options.totalrows) {
			let endcount = this.options.start+this.options.count;
			endcount = endcount > this.options.totalrows ? this.options.totalrows : endcount;
			msg = (this.options.start+1) + '-' + endcount + ' of ' + this.options.totalrows;
		}
		this._showStats(msg);
		this.hideNav();
	}

	copy() {
		var csvdata = this.getCSV();
		this._clipboardCopy(csvdata);
	}

	download() {
		var csvdata = this.getCSV();
		this._download(csvdata);
	}

	_clipboardCopy(text) {
		var textArea = document.createElement("textarea");
		textArea.value = text;
		// Avoid scrolling to bottom
		textArea.style.top = "0";
		textArea.style.left = "0";
		textArea.style.position = "fixed";
		document.body.appendChild(textArea);
		textArea.focus();
		textArea.select();
		try {
			document.execCommand('copy');
		} 
		catch (err) {
			console.error('Unable to copy', err);
		}
		document.body.removeChild(textArea);
	}

	_download(csvdata) {
		var posturl = this.options.source.params.url + "?c=download&t=post";
		posturl += "&filename=" + this.options.table;
		posturl += ".csv";
		$('body').append('<form id="exportform" action="' + posturl + '" method="post"><input type="hidden" id="' + "export" + '" name="' + "export" + '"></form>');
		$("#" + "export").val(csvdata);
		$("#exportform").submit().remove();
	}

	reload(extraparam='',redraw=true) {
		if(redraw) {
			this.show("wait");
			this._showStats('');
		}
		if(this.options.source.type == 'ajax') {
			var page = (this.options.start/this.options.count) + 1;
			var datastr = "c=grid&t=" + encodeURIComponent(this.options.table) + this.options.source.params.data;
			datastr += "&sord=" + this.options.sortorder;
			datastr += "&sidx=" + this.options.sort;
			datastr += "&start=" + this.options.start;
			datastr += "&page=" + page;
			datastr += "&total=" + this.options.totalpages;
			datastr += "&count=" + this.options.totalrows;
			datastr += "&rows=" + this.options.count;
			var jqgridfilter = {groupOp: 'AND', 'rules':[]};
			for(var field in this.options.filters) {
				if(this.options.filters.hasOwnProperty(field)) {
					var rule = {op: 'bw'};
					var value = this.options.filters[field];
					var fl = value.substring(0,1);
					if(fl == '=') {
						rule['op'] = 'eq';
						value = value.substring(1);
					}
					else if(fl == '!') {
						rule['op'] = 'ne';
						value = value.substring(1);
					}
					rule['data'] = value;
					rule['field'] = field;
					jqgridfilter['rules'].push(rule);
				}
				datastr += "&_search=1";
			}
			datastr += "&filters=" + encodeURIComponent(JSON.stringify(jqgridfilter));
			if(this.options.source.params.extra)
				datastr += this.options.source.params.extra;
			if(extraparam)
				datastr += "&" + extraparam;
			//console.log(this.options.source.params.url + "?" + datastr);
			var request = $.ajax({type: "POST",	url: this.options.source.params.url, data: datastr});
			var dtv = this;
			request.done(function(msg) {  
				var x = ajax_parse(msg);
				dtv.ajaxData(x, null, null, this.options);
			});
			request.fail(function(jqXHR, textStatus) {
				dtv.ajaxData(null, jqXHR, textStatus, this.options);
			});
		}
	}

	ajaxData(x, jqXHR, textStatus, params) {
		if(x != null) {
			if(x.total >= 0 || x.status == 'ok') {
				this.options.totalrows = parseInt(x.records);
				if(this.options.count <= 0)
					this.options.count = 500;
				this.options.totalpages = parseInt(this.options.totalrows/this.options.count);
				if(this.options.totalrows%this.options.count)
					this.options.totalpages++;
				this.options.start = this.options.start < this.options.totalrows ? this.options.start : 0;
				this.options.page = this.options.page < this.options.totalpages ? this.options.page : 0;
				this.show(x.rows);
			}
			else {
				this.show(x.error);
			}
		}
		else
			this.show(jqXHR.responseText);
		if(this.options.handlers && this.options.handlers.ajaxData)
			this.options.handlers.ajaxData(x);
	}

	sort(column) {
		if(this.options.sort == column)
			this.options.sortorder = this.options.sortorder == "asc" ? "desc" : "asc";
		else
			this.options.sort = column;
    	this.reload();
	}

	setData(tabledata) {
		this.options.data = tabledata;
	}
	
	getOptions() {
		return this.options;
	}

	getHeader() {
		var table = "<tr>";
		this.options.min_width = 0;
		for(var i = 0; i < this.options.columns.length; i++) {
			var cd = this.options.columns[i];
			var sortorder = this.options.sortorder;
			var label = cd.label;
			var classname = 'th-' + cd.name;
			if(typeof cd.resize !== 'undefined' && !cd.resize)
				classname += " noresize";
			var style = '';
			if(typeof cd.width.default !== 'undefined') {
				style = 'width:' + cd.width.default + (cd.width.default == "auto" ? ';' : 'px' + ';');
				this.options.min_width += cd.width.default == "auto" ? (cd.width.min !== 'undefined' ? cd.width.min : 0) : cd.width.default;
			}
			if(typeof cd.type !== 'undefined' && cd.type == "cb") {
				var content = this.wrap('input', '', {class: 'th-cb-select-all th-cb-' + this.options.table, id:'th-cb-'+ this.options.table, type:'checkbox'});
			}
			else if(typeof cd.sortable !== 'undefined' && cd.sortable === true) {
				if(this.options.sort == null)
					this.options.sort = cd.name;
				if(this.options.sort == cd.name)
					var contentclassname = 'th-content th-sortable th-sorted th-sorted-' + sortorder;
				else
					var contentclassname = 'th-content th-sortable';
				var sortcontent = this.wrap('div', '', {class: 'icon-sort-' + sortorder + ' icon-16'});
				var content = this.wrap('div', label + sortcontent, {class: contentclassname, 'data-column': cd.name});
			}
			else
				var content = this.wrap('div', label, {class: 'th-content'});
	
			if(typeof cd.search !== 'undefined' && cd.search && cd.search.type && cd.search.type == 'text') {
				var value = this.options.filters[cd.name] ? this.options.filters[cd.name] : '';
				var filter = this.wrap('input', '', {type: 'text', id: 'th-filter-'+this.options.table+'-'+cd.name, class: 'filter-input', 'data-column': cd.name,  placeholder: 'Filter', value: value});
				var inputelem = this.wrap('div', filter, {class:'th-column-filter'});
				table += this.wrap('th', content + inputelem, {class:classname, style:style});
			}
			else
				table += this.wrap('th', content, {class:classname, style:style});
		}
		table += '</tr>';
		return table;
	}

	getRandomMessage(msgs) {
		return msgs[Math.floor((Math.random() * msgs.length))];
	}

	getWaitRow() {
		var waitmsgs = ['Loading'];/* ['Hold On', 'Please Wait', 'המתן בבקשה', 'Veuillez patienter !', 'कृपया प्रतीक्षा करें', 
						'placere expectabo', 'Loading', 'Hang On', 'Let me check', 'Sit Tight!', 'കാത്തിരിക്കൂ',
						'Подождите, пожалуйста', '请稍等', 'espere por favor',
						'Hold your horses', 'Not so fast!']; */
		var waitmsg = this.getRandomMessage(waitmsgs);
		var html = "<tr>";
		html += "<td class=\"wait\" colspan=\"" + this.options.columns.length + "\">";
		html += "<div class=\"lds-dual-ring\">&nbsp;</div>";
		html += "<div>" + waitmsg + "</div>";
		html += "</td>";
		html += "</tr>";
		return html;
	}

	getMessageRow(msg) {
		if(typeof msg == 'undefined')
			msg = "Nothing found";
		var html = "<tr>";
		html += "<td class=\"wait multiline\" colspan=\"" + this.options.columns.length + "\">";
		html += "<div class=\"p-2 text-justify mb-0\">" + msg + "</div>";
		html += "</td>";
		html += "</tr>";
		return html;
	}

	getBody() {
		var html = this.getHeader();

		if(this.options.data == "wait")
			return html + this.getWaitRow();
		else if(!Array.isArray(this.options.data))
			return html + this.getMessageRow(this.options.data);
		else if(!this.options.data.length) {
			if(Object.keys(this.options.filters).length)
				return html + this.getMessageRow("No Results. Try clearing the filters on top.");
			else
				return html + this.getMessageRow("No Results");
		}

		for(var row = 0; row < this.options.data.length; row++) {
			var rowid = this.options.data[row][this.options.idcolumn];
			html += "<tr data-serial=\"" + row + "\" data-id=\"" + rowid + "\" class=\"tr-rowid\">";
			for(var i = 0; i < this.options.columns.length; i++) {
				var cd = this.options.columns[i];
				var serial = row+this.options.start+1;
				if(cd.name == "serial")
					html += "<td><div class=\"td-content\">" + serial + "</div></td>";
				else if(cd.name == "cb") {
					let checked = "";
					html += "<td class=\"cb-col\"><input class=\"tcb-" + this.options.table + "\" id=\"tcb-" + this.options.table + "-did-" + rowid + "\" type=\"checkbox\"" + checked + "></td>";
				}
				else {
					let value = this.options.data[row][cd.name];
					var tdclass = 'td-content';
					if(cd.multiline)
						tdclass += ' multiline';
					if(cd.class)
						tdclass += ' ' + cd.class;
					if(cd.linkify)
						value = this.linkify(value);
					html += "<td><div class=\"" + tdclass + "\">" + value + "</div></td>";
				}
			}
			html += "</tr>";
		}
		return html;
	}

	linkify(inputText) {
		var replacedText, replacePattern1, replacePattern2, replacePattern3;
	
		//URLs starting with http://, https://, or ftp://
		replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
		replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');
	
		//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
		replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
		replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');
	
		//Change email addresses to mailto:: links.
		replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
		replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
	
		return replacedText;
	}

	getCSV() {
		var csvrows = [];
		var header = '';
		for(var i = 0; i < this.options.columns.length; i++) {
		}
		for(var row = 0; row < this.options.data.length; row++) {
			var datarow = '';
			for(var i = 0; i < this.options.columns.length; i++) {
				var cd = this.options.columns[i];
				if(cd.name == "serial" || cd.name == "cb")
					continue;
				else {
					if(!row) {
						var label = this.csvQuote(this.options.columns[i].label);
						header += (header == '') ? label : ','+ label;
					}
					let value = this.csvQuote(this.options.data[row][cd.name]);
					datarow += (datarow == '') ? value : ',' + value;
				}
			}
			if(!row)
				csvrows.push(header);
			csvrows.push(datarow);
		}
		return csvrows.join("\n");
	}

	csvQuote(term) {
		if(typeof term != "string")
			return term;
		var result = term.replace(/"/g, '""');
		if (result.search(/("|,|\n)/g) >= 0)
			result = '"' + result + '"';
		return result;
	}


	show(data) {
		this.setData(data);
		var html = this.getBody();

		if(this.options.parent != '') {
			var divs = '' +
				'<div class="dtcard">' +
				'<div class="dtcard-body">' +
				'<table id="' + this.options.table + '" class="datatable resizable">' +
				'</table>' + 
				'</div>' +
				'<div class="dtcard-footer dtcard-footer-dt">' +
				'</div>' +
				'</div>';
			$('#' + this.options.parent).html(divs);
			if(!$('#'+this.options.parent).hasClass('datatable-wrapper'))
				$('#'+this.options.parent).addClass('datatable-wrapper');
		}
		$('#' + this.options.table).html(html);
		this._createFooter();

		var tables = document.getElementsByClassName('resizable');
		for (var i = 0; i < tables.length; i++) {
			resizableGrid(tables[i], this.options.table, {});
		}
		if(this.options.data && Array.isArray(this.options.data) && this.options.data.length) {
			var rowid = this.last_highlighted_rowid;
			if(rowid < 0 || !$("#"+this.options.table).find(`[data-id='${rowid}']`)) {
				rowid = this.options.data[0].id;
			}
			if(rowid > 0)
				$("#"+this.options.table).find(`[data-id='${rowid}']`).click();
		}
		if(this.options.handlers && this.options.handlers.resize)
			this.options.handlers.resize();

		if(DataTableView._filterInFocus && DataTableView._tableInFocus == this.options.table) {
			var elem = $("#th-filter-" + this.options.table + '-'+ DataTableView._filterInFocus);
			if(elem) {
				var strLength = elem.val().length * 2;
				elem.focus();
				elem[0].setSelectionRange(strLength, strLength);
			}
		}
		
		//$('.datatable-wrapper .dtcard').css('max-width', $('.main h1').width());
		document.getElementById(this.options.table).style.minWidth = this.options.min_width + "px";
	}

	getColumns() {
		if(this.options.source.type == 'ajax') {
			var datastr = '&c=columns&o=get&t=' + encodeURIComponent(this.options.table);
			//datastr += "&data=" + encodeURIComponent(JSON.stringify(this.options.columns));
			//console.log(datastr);
			var request = $.ajax({type: "POST",	url: this.options.source.params.url, data: datastr});
			var dtv = this;
			request.done(function(msg) {  
				var x = ajax_parse(msg);
				if(x.status == 'ok' && x.data) {
					dtv.setOption('columns', x.data);
				}
				if(dtv.options.handlers.columns && typeof dtv.options.handlers.columns == 'function')
					dtv.options.handlers.columns(x.data);
			});
			request.fail(function(jqXHR, textStatus) {
			});
		}
	}

	saveColumns() {
		if(this.options.source.type == 'ajax') {
			var datastr = '&c=columns&o=set&t=' + encodeURIComponent(this.options.table);
			datastr += "&data=" + encodeURIComponent(JSON.stringify(this.options.columns));
			var request = $.ajax({type: "POST",	url: this.options.source.params.url, data: datastr});
			var dtv = this;
			request.done(function(msg) {  
				var x = ajax_parse(msg);
				dtv.ajaxSettings(x, null, null, this.options);
			});
			request.fail(function(jqXHR, textStatus) {
				dtv.ajaxData(null, jqXHR, textStatus, this.options);
			});
		}
		//if(this.options.handlers && this.options.handlers.resize)
		//	this.options.handlers.resize();
	}

	ajaxSettings(x, jqXHR, textStatus, params) {
		if(x != null) {
			if(x.status == 'ok') {
			}
			else {
			}
		}
	}

	wrap(elem, content, props) {
		var inner = '';
		for(var propname in props) {
			if(props.hasOwnProperty(propname)) {
				inner += ' ' + propname + '="' + props[propname] + '"';
			}
		}
		return '<' + elem + inner + '>' + content + '</' + elem + '>';
	}

	getSelected(column) {
		var selected = [];
		var dtv = this;
		$('.tcb-' + dtv.options.table + ':checkbox:checked').each(function() {
			var rowid = $(this).attr('id').replace("tcb-" + dtv.options.table + "-did-", "");
			for(var i = 0; i < dtv.options.data.length; i++) {
				if(dtv.options.data[i].id == rowid)
					selected.push(dtv.options.data[i][column]);
			}
		});
		return selected;
	}

	getSelectedIds() {
		var selected = [];
		var dtv = this;
		$('.tcb-' + dtv.options.table + ':checkbox:checked').each(function() {
			var rowid = $(this).attr('id').replace("tcb-" + dtv.options.table + "-did-", "");
			selected.push(rowid);
		});
		return selected;
	}

	getHighlightedId() {
		return this.last_highlighted_rowid;
	}

	selectAll() {
		$(".tcb-" + dtv.options.table).prop('checked', true);
	}

	unSelectAll() {
		$(".tcb-" + dtv.options.table).prop('checked', false);
	}
	
}


//export default DataTableView;


function resizableGrid(table, tablename, widths) {
	var row = table.getElementsByTagName('tr')[0],
	cols = row ? row.children : undefined;
		if (!cols) return;

	var tableHeight = table.offsetHeight;

	for (var i = 0; i < cols.length; i++) {
		if(!$(cols[i]).hasClass('noresize')) {
			var div = createDiv(24);
			cols[i].appendChild(div);
			setListeners(div);
		}
	}

	function setListeners(div) {
		var pageX, curCol, nxtCol, curColWidth, nxtColWidth, tableWidth;

		$(div).on('mousedown', function(e) {
			tableWidth = document.getElementById(tablename).offsetWidth;
			curCol = e.target.parentElement;
			nxtCol = curCol.nextElementSibling;
			pageX = e.pageX;
			var padding = paddingDiff(curCol);
			curColWidth = curCol.offsetWidth - padding;
		});

		$(div).on('mouseover', function(e) {
			e.target.style.borderRight = '1px solid var(--body-text-color)';
		})

		$(div).on('mouseout', function(e) {
			e.target.style.borderRight = '';
		})

		$(document).on('mousemove', $(div), function(e) {
			if (curCol) {
				var diffX = e.pageX - pageX;
				//curCol.style.width = (curColWidth + diffX) + 'px'; 
				//document.getElementById(tablename).style.width = tableWidth + diffX + "px";
				var columnname = $(curCol).attr('class');
				columnname = columnname.replace("th-", "").trim();
				var minw = getMinimumWidth(columnname);
				var thisw = curColWidth + diffX
				if(minw && (curColWidth + diffX) < minw)
					thisw = minw;
				widths[columnname] = thisw;
				curCol.style.width = thisw + 'px';
				var diff = thisw - curColWidth;
				document.getElementById(tablename).style.width = tableWidth + diff + "px";
			}
		});

		$(document).on('mouseup', $(div), function(e) {
			curCol = undefined;
			nxtCol = undefined;
			pageX = undefined;
			nxtColWidth = undefined;
			curColWidth = undefined;
			// save column widths
			var columndata = DataTableView.getTable(tablename).options.columns;
			for(var column in widths) {
				if(widths.hasOwnProperty(column)) {
					for(var i = 0; i < columndata.length; i++) {
						if(columndata[i].name && columndata[i].name == column) {
							var cwidth = columndata[i].width.default;
							if(cwidth && cwidth !== "auto")
								columndata[i].width.default = widths[column];
							break;
						}
					}
					DataTableView.getTable(tablename).saveColumns();
				}
			}
		});
	}
	
	function getMinimumWidth(column) {
		var cd = findColumnData(column);
		if(cd != null) {
			var minw = cd.width.min;
			if(minw != 'undefined')
				return minw;
		}
		return 0;
	}
	
	function findColumnData(column) {
		var columndata = DataTableView.getTable(tablename).options.columns;
		for(var i = 0; i < columndata.length; i++) {
			if(columndata[i].name && columndata[i].name == column) {
				return columndata[i];
			}
		}
		return null;
	}

	function createDiv(height) {
		var div = document.createElement('div');
		div.style.top = 0;
		div.style.right = 0;
		div.style.width = '5px';
		div.style.position = 'absolute';
		div.style.cursor = 'ew-resize';
		div.style.userSelect = 'none';
		div.style.height = height + 'px';
		return div;
	}

	function paddingDiff(col) {
		if (getStyleVal(col, 'box-sizing') == 'border-box') {
			return 0;
		}
		var padLeft = getStyleVal(col, 'padding-left');
		var padRight = getStyleVal(col, 'padding-right');
		return (parseInt(padLeft) + parseInt(padRight));
	}

	function getStyleVal(elm, css) {
		return (window.getComputedStyle(elm, null).getPropertyValue(css))
	}
};
