window.OBooks = window.OBooks || {};

(function ($, window, document, _OBooks, undefined) {

	var colors = ["#4285f4", "#ff007a"];

	var elemIndex = function(parent, elem) {
		return Array.prototype.indexOf.call(parent.childNodes, elem);
	};

	var toTag = function(obj, par) {
		if (obj && obj.tag) {
			var tag = document.createElement(obj.tag);
			if (obj.cls) {
				tag.className = obj.cls;
			}
			if (obj.id) {
				tag.setAttribute("id", obj.id);
			}

			if (obj.name) {
				tag.setAttribute("name", obj.name);
			}

			if (obj.attr && obj.attr.length > 0) {
				for (var j=0,jLen=obj.attr.length; j<jLen; j++) {
					tag.setAttribute(obj.attr[j].key, obj.attr[j].value);
				}
			}

			if (obj.text) {
				tag.appendChild(document.createTextNode(obj.text));
			}

			if (par) {
				par.appendChild(tag);
			}

			if (obj.child && obj.child.length > 0) {
				for (var i=0, iLen=obj.child.length; i<iLen; i++) {
					toTag(obj.child[i], tag);
				}
			}

			return tag;
		}
	};

	var currTable = null;

	var TableEditable = function(param) {
		var _this = this;
		_this.fname = "s" + Math.round(Math.random()*1000000);
		_this.parent = param.parent || null;
		_this.table = param.table || null;
		_this.thead = param.thead || null;
		_this.tbody = param.tbody || null;
		_this.tfoot = param.tfoot || null;
		_this.hidder = param.hidder || null;
		_this.textarea = null;
		_this.tabindex = param.tabindex === undefined ? 1 : param.tabindex;

		_this.currCell = null;
		_this.currRow = null;
		_this.currRowIdx = 0;
		_this.currColIdx = 0;

		var cellTop = null,
			cellRight = null,
			cellBottom = null,
			cellLeft = null,
			editText = null;

		var cellBound = {
			left: 0,
			top: 0,
			width: 0,
			height: 0
		};

		_this.selectElem = function(ev){
			_this.currRow = _this.tbody.rows[_this.currRowIdx];
			
			if (!_this.currRow) {
				return;
			}

			_this.currCell = _this.currRow.cells[_this.currColIdx];
			if (!_this.currCell) {
				return;
			}

			var parentBound = _this.parent.getBoundingClientRect();
			var bound = _this.currCell.getBoundingClientRect();
/*
			_this.currCell.offsetTop;
			_this.currCell.offsetLeft;
			_this.currCell.offsetWidth;
			_this.currCell.offsetHeight;
*/
			// top = _this.currCell.offsetTop + 9, //bond.y,
			cellBound.left = bound.x - parentBound.x;
			cellBound.top = bound.y - parentBound.y + _this.parent.scrollTop;	// bond.y
			cellBound.width = bound.width + 1;
			cellBound.height = bound.height;

			cellTop.style.left = cellBound.left + "px";
			cellTop.style.top = cellBound.top + "px";
			cellTop.style.width = cellBound.width + "px";
			cellTop.style.height = 1 + "px";

			cellRight.style.left = (cellBound.left + cellBound.width - 2) + "px";
			cellRight.style.top = cellBound.top + "px";
			cellRight.style.width = 1 + "px";
			cellRight.style.height = cellBound.height + "px";

			cellBottom.style.left = cellBound.left + "px";
			cellBottom.style.top = (cellBound.top + cellBound.height - 2) + "px";
			cellBottom.style.width = cellBound.width + "px";
			cellBottom.style.height = 1 + "px";

			cellLeft.style.left = cellBound.left + "px";
			cellLeft.style.top = cellBound.top + "px";
			cellLeft.style.width = 1 + "px";
			cellLeft.style.height = cellBound.height + "px";

			ev instanceof KeyboardEvent && _this.currCell.scrollIntoViewIfNeeded && _this.currCell.scrollIntoViewIfNeeded(false);
			typeof param.onCellChange === "function" && param.onCellChange({
				target: _this.currCell,
				rowIndex: _this.currRowIdx,
				columnIndex: _this.currColIdx,
				cellBound: cellBound,
				isClick: (ev instanceof MouseEvent),
				ev: ev
			});
		};

		_this.removeFocus = function(){
			cellTop.style.left = 0;
			cellRight.style.left = 0;
			cellBottom.style.left = 0;
			cellLeft.style.left = 0;

			cellTop.style.top = 0;
			cellRight.style.top = 0;
			cellBottom.style.top = 0;
			cellLeft.style.top = 0;

			cellTop.style.height = 0;
			cellRight.style.height = 0;
			cellBottom.style.height = 0;
			cellLeft.style.height = 0;

			cellTop.style.width = 0;
			cellRight.style.width = 0;
			cellBottom.style.width = 0;
			cellLeft.style.width = 0;
		};

		_this.createEditBox = function(){
			cellTop = toTag({tag: "span", cls:"cell-top" }, _this.parent);
			cellRight = toTag({tag: "span", cls:"cell-right" }, _this.parent);
			cellBottom = toTag({tag: "span", cls:"cell-bottom" }, _this.parent);
			cellLeft = toTag({tag: "span", cls:"cell-left" }, _this.parent);
			
			_this.textarea = toTag({
				tag: "textarea",
				cls: "copypaste",
				id: "copypaste",
				name: "copypaste",
				attr:[{
					key: "tabindex",
					value: _this.tabindex
				}]
			}, _this.parent);

			_this.textarea.onfocus = function(){
				// _this.selectElem();
				_this.selectNext();
			};

			// hidder = toTag({tag: "div", cls:"hidder" }, _this.parent);
			/*
			editText = toTag({tag: "input", cls:"hidder", attr:[
				{ key: "type", value: "text" },
				{ key:"type", value:"text" },
				{ key: "onfocus", value: "var a=this.value;this.value='';this.value=a;" },
				{ key: "style", value: "display:none;" }
			]}, hidder);
			*/
		};

		_this.selectNext = function(ev, isTab){
			_this.currRow = _this.currRow || _this.tbody.rows[_this.currRowIdx];

			if (!_this.currRow) {
				return false;
			}

			if (typeof param.onBeforeCellChange === "function" && param.onBeforeCellChange({
				target: _this.currCell,
				rowIndex: _this.currRowIdx,
				columnIndex: _this.currColIdx,
				cellBound: cellBound,
				isClick: (ev instanceof MouseEvent),
				ev: ev
			}) === false) {
				return false;
			}

			// var isLastCell = false;

			if (_this.currRow.cells[_this.currColIdx + 1]) {
				_this.currColIdx++;

				/*
				// Is Last Cell of Last Row
				if (_this.currRowIdx == _this.tbody.rows.length-1 && _this.currColIdx == _this.currRow.cells.length-1) {
					isLastCell = true;
				}
				*/
			} else {
				if (_this.tbody.rows[_this.currRowIdx + 1]) {
					_this.currRowIdx++;
				}
				_this.currColIdx = 0;
			}

			var nxtTd = _this.tbody.rows[_this.currRowIdx].cells[_this.currColIdx];
			if (nxtTd.getAttribute("skip") >= 2 || (nxtTd.getAttribute("skip") == 1 && isTab)) {
				_this.currCell = nxtTd;
				_this.selectNext(ev, isTab);
				return false;
			}

			_this.selectElem(ev);

			return true;
		};
		_this.focusEditGrid = function(ev, isTab){
			_this.currRow = _this.currRow || _this.tbody.rows[_this.currRowIdx];
			if (!_this.currRow) {
				return false;
			}
			if (typeof param.onBeforeCellChange === "function" && param.onBeforeCellChange({
				target: _this.currCell,
				rowIndex: _this.currRowIdx,
				columnIndex: _this.currColIdx,
				cellBound: cellBound,
				isClick: (ev instanceof MouseEvent),
				ev: ev
			}) === false) {
				return false;
			}
			_this.selectElem(ev);
			typeof param.onEdit === "function" && param.onEdit({
				target: _this.currCell,
				rowIndex: _this.currRowIdx,
				columnIndex: _this.currColIdx,
				cellBound: cellBound,
				isClick: (ev instanceof MouseEvent),
				ev: ev
			});
			return true;
		};
		
		_this.selectPrev = function(ev, isTab){
			
			_this.currRow = _this.currRow || _this.tbody.rows[_this.currRowIdx];

			if(_this.currColIdx == 1 && _this.currRowIdx == 0)
			{
				var par = $(_this.parent);
				var inp = $("input[type=text]:not([tabindex=-1]), input[type=search]:not([tabindex=-1],input[type=number]:not([tabindex=-1])", par.prev()).last();
				if (inp && inp.get(0))
				{
					inp.focus();
					_this.removeFocus();
					return false;
				} else {
					var inp2 = $("input[type=text]:not([tabindex=-1]), input[type=search]:not([tabindex=-1],input[type=number]:not([tabindex=-1])", par.prev().prev()).last();
					if (inp2 && inp2.get(0))
					{
						inp2.focus();
						_this.removeFocus();
						return false;
					}
				}
			}
/*
			if (_this.currColIdx == 0 && _this.currRowIdx == 0)
			{
				
			}
*/
			if (!_this.currRow) {
				return false;
			}

			if (_this.currRow.cells[_this.currColIdx - 1]) {
				_this.currColIdx--;
			} else {
				if (_this.tbody.rows[_this.currRowIdx - 1]) {
					_this.currRowIdx--;
				}
				_this.currColIdx = _this.tbody.rows[_this.currRowIdx].cells.length - 1;
			}

			var prevTd = _this.tbody.rows[_this.currRowIdx].cells[_this.currColIdx];
			if (prevTd.getAttribute("skip") >= 2 || (prevTd.getAttribute("skip") == 1 && isTab)) {
				_this.currCell = prevTd;
				_this.selectPrev(ev, isTab);
				return;
			}

			_this.selectElem(ev);

			return true;
		};

		_this.selectUp = function(ev){
			if (_this.tbody.rows[_this.currRowIdx - 1]) {
				_this.currRowIdx--;
			}

			_this.selectElem(ev);

			return true;
		};

		_this.selectDown = function(ev){
			if (_this.tbody.rows[_this.currRowIdx + 1]) {
				_this.currRowIdx++;
			}

			_this.selectElem(ev);

			return true;
		};

		_this.selectHome = function(ev){
			_this.currColIdx = 0;
			_this.selectElem(ev);
		};

		_this.selectEnd = function(ev){
			_this.currColIdx = _this.currRow.cells.length - 1;
			_this.selectElem(ev);
		};

		_this.selectPageUp = function(ev){
			_this.currRowIdx = 0;
			_this.selectElem(ev);
		};

		_this.selectPageDown = function(ev){
			_this.currRowIdx = _this.tbody.rows.length - 1;
			_this.selectElem(ev);
		};

		_this.keyHandlers = {};

		_this.keyHandlers["Tab"] = function(ev) {
			if (currTable != _this.parent) {
				return;
			}
// console.trace("Here 2", _this.fname, currTable);
			ev.preventDefault();

			if (ev.shiftKey) {
				_this.selectPrev(ev, true);
			} else {
				_this.selectNext(ev, true);
			}
		};
		_this.keyHandlers["ArrowUp"] = function(ev) {
			ev.preventDefault();
			_this.selectUp(ev);
		};
		_this.keyHandlers["ArrowDown"] = function(ev) {
			ev.preventDefault();
			_this.selectDown(ev);
		};
		_this.keyHandlers["ArrowLeft"] = function(ev) {
			ev.preventDefault();
			_this.selectPrev(ev);
		};
		_this.keyHandlers["ArrowRight"] = function(ev) {
			ev.preventDefault();
			_this.selectNext(ev);
		};
		_this.keyHandlers["Home"] = function(ev) {
			ev.preventDefault();
			_this.selectHome(ev);
		};
		_this.keyHandlers["End"] = function(ev) {
			ev.preventDefault();
			_this.selectEnd(ev);
		};
		_this.keyHandlers["PageUp"] = function(ev) {
			ev.preventDefault();
			_this.selectPageUp(ev);
		};
		_this.keyHandlers["PageDown"] = function(ev) {
			ev.preventDefault();
			_this.selectPageDown(ev);
		};

		_this.keyHandlers["Delete"] = function(ev) {
			typeof param.onDelete === "function" && param.onDelete({
				target: _this.currCell,
				rowIndex: _this.currRowIdx,
				columnIndex: _this.currColIdx,
				cellBound: cellBound,
				ev: ev
			});
		};

		_this.showEditable = function(){
			if (!_this.hidder) {
				_this.hidder = $(".hidder", _this.parent).get(0);

				if (!_this.hidder) {
					return;
				}
			}

			_this.hidder.style.top = cellBound.top;
			_this.hidder.style.left = cellBound.left;
			_this.hidder.style.width = cellBound.width;
			_this.hidder.style.height = cellBound.height;
		};

		_this.keyHandlers["Escape"] = function(ev){
			if((_this.parent && _this.parent.contains(ev.target)) || (_this.hidder && _this.hidder.contains(ev.target)) || (_this.tfoot && _this.tfoot.contains(ev.target)) ||
			(_this.thead && _this.thead.contains(ev.target))) {
				if (ev.target.tagName == "INPUT" || ev.target.tagName == "TEXTAREA") {
					typeof param.onEsc === "function" && param.onEsc(ev);
					ev.stopPropagation();
					return false;
				}
			}
		};

		// Edit the cell
		_this.keyHandlers["F2"] = function(ev) {
			// if (!_this.currCell) {return;}
			if(ev.keyCode != 13 && ev.keyCode != 9) {
				_this.currCell && _this.currCell.removeAttribute("suggested");
				typeof param.onRemoveSuggestion === "function" && param.onRemoveSuggestion({
					target: _this.currCell,
					rowIndex: _this.currRowIdx,
					columnIndex: _this.currColIdx,
					cellBound: cellBound,
					isClick: (ev instanceof MouseEvent),
					ev: ev
				})
			}
			typeof param.onEdit === "function" && param.onEdit({
				target: _this.currCell,
				rowIndex: _this.currRowIdx,
				columnIndex: _this.currColIdx,
				cellBound: cellBound,
				isClick: (ev instanceof MouseEvent),
				ev: ev
			});

			// if (ev.code == "Space")
			// {
			// 	return false;
			// }
			// _this.showEditable();
		};
		
		_this.keyHandlers["Space"] =  function(ev) {
			if(typeof param.onSpaceSuggestion === "function" && _this.currCell) {
				ev.preventDefault();
				_this.currCell.setAttribute("suggested",true);
				param.onSpaceSuggestion({
					target: _this.currCell,
					rowIndex: _this.currRowIdx,
					columnIndex: _this.currColIdx,
					cellBound: cellBound,
					isClick: (ev instanceof MouseEvent),
					ev: ev
				});
			} 
		};
		_this.keyHandlers["Enter"] = _this.keyHandlers["F2"];
		_this.keyHandlers["NumpadEnter"] = _this.keyHandlers["F2"];

		var reading = false;
		_this.keydownHandler = function(ev){
			if (reading && ev.keyCode === 13)
			{
				return false;
			}

			if (!reading)
			{
				reading = true;
				setTimeout(function(){
					reading = false;
				}, 200);
			}

			var ctrlDel = false;
			if ((ev.keyCode == 67) && ev.ctrlKey) {
				switch(ev.keyCode)
				{
					case 67:
						return true;
					break;
					case 46:
						ctrlDel = true;
					break;
				}
			}

			if (
				(ev.target.tagName != "BODY" &&
					(!_this.parent || !_this.parent.contains(ev.target)) &&
					(!_this.hidder || !_this.hidder.contains(ev.target))
				) ||
				(_this.tfoot && _this.tfoot.contains(ev.target)) ||
				(_this.thead && _this.thead.contains(ev.target))
			) {
				return;
			}

			if (currTable != _this.parent) {
				// ev.preventDefault();
				// ev.stopPropagation();
				// return false;
				return;
			}

			/*
			if (_this.body && ev.target == _this.body) {
				_this.selectElem(ev);
				// _this.keyHandlers["Tab"](ev);
				return false;
			}
			*/

			if (
				(ev.target.tagName == "INPUT" || ev.target.tagName == "TEXTAREA") &&
				ev.target.getAttribute("name") != "copypaste" && !ctrlDel
			) {
				/*
				ev.target.dispatchEvent(new Event("change", {
					bubbles: false,
					cancelable: true
				}));
				*/
				if (
					(ev.code == "Tab" || ev.code == "Enter" || ev.code == "NumpadEnter") &&
					!ev.shiftKey && !ev.metaKey && !ev.ctrlKey && !ev.altKey
				) {
					ev.isTabs = true;
					// ev.stopPropagation();
					var nev = new Event("change");
					nev.isGridify = true;
					ev.target.dispatchEvent(nev);

					if (typeof param.onLostFocus === "function")
					{
						var res = param.onLostFocus(ev);
						if (res !== true)
						{
							return !!(res);
						}
					}
					_this.keyHandlers["Tab"](ev);

					// ev.stopPropagation();
					// ev.preventDefault();
					// return false;
				}

				if (ev.code == "Escape") {
					_this.keyHandlers["Escape"](ev);
					ev.stopPropagation();
					return false;
				}

				return true;
			}

			if ((ev.keyCode == 46) && ev.ctrlKey) { 
				typeof param.onDeleteRow === "function" && param.onDeleteRow({
					rowIndex: _this.currRowIdx,
					columnIndex: _this.currColIdx,
					ev: ev
				});

				return;
			}
			if ((ev.keyCode == 120)) { 
				typeof param.onContactFocus === "function" && param.onContactFocus({
					rowIndex: _this.currRowIdx,
					columnIndex: _this.currColIdx,
					ev: ev
				});
				return;
			}
			// ev.which || ev.keyCode, ev.code

			if (_this.keyHandlers[ev.code]) {
				if(
					(_this.parent && _this.parent.contains(ev.target)) ||
					(_this.hidder && _this.hidder.contains(ev.target)) ||
					(_this.tfoot && _this.tfoot.contains(ev.target)) ||
					(_this.thead && _this.thead.contains(ev.target))
				) {
					var nev = new Event("change");
					nev.isGridify = true;
					ev.target.dispatchEvent(nev);
					_this.keyHandlers[ev.code](ev);
					ev.stopPropagation();
					return false;
				}

				// console.log("called 123",ev.target);
				_this.keyHandlers[ev.code](ev);
				ev.stopPropagation();
				return false;

			} else if (
				(ev.keyCode >= 48 && ev.keyCode <= 57) ||		// Number
				(ev.keyCode >= 96 && ev.keyCode <= 105) ||	// Number in num pad
				(ev.keyCode >= 65 && ev.keyCode <= 90)
			) {
				ev.isTyping = true;
				_this.keyHandlers["Enter"](ev);
				// ev.stopPropagation();
				// return false;
			}else if (ev.keyCode >= 187 && ev.keyCode <= 190) {// plus minus period
				ev.isTyping = true;
				_this.keyHandlers["Enter"](ev);
				// ev.stopPropagation();
				// return false;
			}

			return true;
		};

		_this.destroy = function(){
			document.removeEventListener("keydown", _this.keydownHandler);
			document.removeEventListener("mouseup", _this.mouseUpHandler);
		};

		var getClosest = function (elem, selector) {
			for ( ;elem && elem !== document; elem = elem.parentNode ) {
				if (elem.matches(selector)) return elem;
			}
			return null;
		};

		_this.mouseUpHandler = function (e) {
/*
			var selection = window.getSelection();
			if (selection.toString()) {
				e.preventDefault();
				e.stopPropagation();
console.log("Called");
				return false;
			}
			selection.empty();
*/
			if(!$(_this.parent).is(e.target) && $(_this.parent).has(e.target).length === 0){
				_this.removeFocus();
			}
		};
		_this.focusPatricularCel = function(e){
			param.initRow = e.rowIndex;
			param.initCol = e.colIndex;
			_this.focusGrid(e);
		}

		_this.focusGrid = function(e){
			if (e.target) {
				var _parent = $(e.target).parents(".editgrid.parent").get(0);
				if(!_parent && ($(e.target)[0].classList.contains('editgrid') && $(e.target)[0].classList.contains('parent'))) {
					_parent = e.target;
				}
				if (_parent != currTable) {
					currTable = _parent;
				}
				_this.currRowIdx = param.initRow === undefined ? 0 : param.initRow;
				_this.currColIdx = param.initCol === undefined ? 1 : param.initCol;
				_this.selectElem(e);
				return;
			} else {
				var _parent = $(e).parents(".editgrid.parent").get(0);
				if(!_parent && ($(e)[0].classList.contains('editgrid') && $(e)[0].classList.contains('parent'))) {
					_parent = e;
				}
				if (_parent != currTable) {
					currTable = _parent;
				}
				_this.currRowIdx = param.initRow === undefined ? 0 : param.initRow;
				_this.currColIdx = param.initCol === undefined ? 1 : param.initCol;
				_this.selectElem(e);
				return true;
			}			
		};

		_this.init = function(){
			_this.createEditBox();

			if (!_this.table) {
				return;
			}

			let timeoutHandle = null;
			_this.tbody.addEventListener("click", function(e){
				if (!e.target) {
					return;
				}

				if (timeoutHandle) {
					clearTimeout(timeoutHandle);
					timeoutHandle = null;
				}

				let target = e.target;

				currTable = _this.parent;

				if (target.tagName != "TD") {
					target = getClosest(e.target, "td, th");
				}

				if (!target || target.tagName != "TD") {
					return;
				}

				if (target.getAttribute("skip") == 3) {
					return;
				}

				_this.currColIdx = target.cellIndex;
				_this.currRowIdx = target.parentElement.rowIndex-1;

				_this.selectElem(e);
			});

			_this.tbody.addEventListener("dblclick", function(e){
				_this.keyHandlers["Enter"](e);
			});

			_this.tbody.addEventListener("focus", function(e){
				timeoutHandle = setTimeout(function(){
					_this.focusGrid(e);
					timeoutHandle = null;
				}, 200);
			});

			_this.parent.addEventListener("focus", function(e){
				if (e && e.relatedTarget && !_this.parent.contains(e.relatedTarget)) {
					_this.focusGrid(e);
				}
			});

			_this.table.onunload = _this.destroy;

			document.removeEventListener("keydown", _this.keydownHandler);
			document.addEventListener("keydown", _this.keydownHandler);
			// _this.parent.removeEventListener("keydown", _this.keydownHandler);
			// _this.parent.addEventListener("keydown", _this.keydownHandler);

			// _this.selectElem();

			document.removeEventListener("mouseup", _this.mouseUpHandler);
			document.addEventListener("mouseup", _this.mouseUpHandler);

			currTable = _this.parent;
		};

	};

	_OBooks.Gridify = TableEditable;

})(jQuery, window, document, window.OBooks);

