var Keybindings = function(table){
	this.table = table; //hold Tabulator object
	this.watchKeys = null;
	this.pressedKeys = null;
	this.keyupBinding = false;
	this.keydownBinding = false;
};

Keybindings.prototype.initialize = function(){
	var bindings = this.table.options.keybindings,
	mergedBindings = {};

	this.watchKeys = {};
	this.pressedKeys = [];

	if(bindings !== false){

		for(let key in this.bindings){
			mergedBindings[key] = this.bindings[key];
		}

		if(Object.keys(bindings).length){

			for(let key in bindings){
				mergedBindings[key] = bindings[key];
			}
		}

		this.mapBindings(mergedBindings);
		this.bindEvents();
	}
};

Keybindings.prototype.mapBindings = function(bindings){
	var self = this;

	for(let key in bindings){

		if(this.actions[key]){

			if(bindings[key]){

				if(typeof bindings[key] !== "object"){
					bindings[key] = [bindings[key]];
				}

				bindings[key].forEach(function(binding){
					self.mapBinding(key, binding);
				});
			}

		}else{
			console.warn("Key Binding Error - no such action:", key);
		}
	}
};

Keybindings.prototype.mapBinding = function(action, symbolsList){
	var self = this;

	var binding = {
		action: this.actions[action],
		keys: [],
		ctrl: false,
		shift: false,
		meta: false,
	};

	var symbols = symbolsList.toString().toLowerCase().split(" ").join("").split("+");

	symbols.forEach(function(symbol){
		switch(symbol){
			case "ctrl":
			binding.ctrl = true;
			break;

			case "shift":
			binding.shift = true;
			break;

			case "meta":
			binding.meta = true;
			break;

			default:
			symbol = parseInt(symbol);
			binding.keys.push(symbol);

			if(!self.watchKeys[symbol]){
				self.watchKeys[symbol] = [];
			}

			self.watchKeys[symbol].push(binding);
		}
	});
};

Keybindings.prototype.bindEvents = function(){
	var self = this;

	this.keyupBinding = function(e){
		var code = e.keyCode;
		var bindings = self.watchKeys[code];

		if(bindings){

			self.pressedKeys.push(code);

			bindings.forEach(function(binding){
				self.checkBinding(e, binding);
			});
		}
	};

	this.keydownBinding = function(e){
		var code = e.keyCode;
		var bindings = self.watchKeys[code];

		if(bindings){

			var index = self.pressedKeys.indexOf(code);

			if(index > -1){
				self.pressedKeys.splice(index, 1);
			}
		}
	};

	this.table.element.addEventListener("keydown", this.keyupBinding);

	this.table.element.addEventListener("keyup", this.keydownBinding);
};

Keybindings.prototype.clearBindings = function(){
	if(this.keyupBinding){
		this.table.element.removeEventListener("keydown", this.keyupBinding);
	}

	if(this.keydownBinding){
		this.table.element.removeEventListener("keyup", this.keydownBinding);
	}
};


Keybindings.prototype.checkBinding = function(e, binding){
	var self = this,
	match = true;

	if(e.ctrlKey == binding.ctrl && e.shiftKey == binding.shift && e.metaKey == binding.meta){
		binding.keys.forEach(function(key){
			var index = self.pressedKeys.indexOf(key);

			if(index == -1){
				match = false;
			}
		});

		if(match){
			binding.action.call(self, e);
		}

		return true;
	}

	return false;
};

//default bindings
Keybindings.prototype.bindings = {
	navPrev:"shift + 9",
	navNext:9,
	navUp:38,
	navDown:40,
	scrollPageUp:33,
	scrollPageDown:34,
	scrollToStart:36,
	scrollToEnd:35,
	undo:"ctrl + 90",
	redo:"ctrl + 89",
	copyToClipboard:"ctrl + 67",
};

//default actions
Keybindings.prototype.actions = {
	keyBlock:function(e){
		e.stopPropagation();
		e.preventDefault();
	},
	scrollPageUp:function(e){
		var rowManager = this.table.rowManager,
		newPos = rowManager.scrollTop - rowManager.height,
		scrollMax = rowManager.element.scrollHeight;

		e.preventDefault();

		if(rowManager.displayRowsCount){
			if(newPos >= 0){
				rowManager.element.scrollTop = newPos;
			}else{
				rowManager.scrollToRow(rowManager.getDisplayRows()[0]);
			}
		}

		this.table.element.focus();
	},
	scrollPageDown:function(e){
		var rowManager = this.table.rowManager,
		newPos = rowManager.scrollTop + rowManager.height,
		scrollMax = rowManager.element.scrollHeight;

		e.preventDefault();

		if(rowManager.displayRowsCount){
			if(newPos <= scrollMax){
				rowManager.element.scrollTop = newPos;
			}else{
				rowManager.scrollToRow(rowManager.getDisplayRows()[rowManager.displayRowsCount - 1]);
			}
		}

		this.table.element.focus();

	},
	scrollToStart:function(e){
		var rowManager = this.table.rowManager;

		e.preventDefault();

		if(rowManager.displayRowsCount){
			rowManager.scrollToRow(rowManager.getDisplayRows()[0]);
		}

		this.table.element.focus();
	},
	scrollToEnd:function(e){
		var rowManager = this.table.rowManager;

		e.preventDefault();

		if(rowManager.displayRowsCount){
			rowManager.scrollToRow(rowManager.getDisplayRows()[rowManager.displayRowsCount - 1]);
		}

		this.table.element.focus();
	},
	navPrev:function(e){
		var cell = false;

		if(this.table.modExists("edit")){
			cell = this.table.modules.edit.currentCell;

			if(cell){
				e.preventDefault();
				cell.nav().prev();
			}
		}
	},

	navNext:function(e){
		var cell = false;
		var newRow = this.table.options.tabEndNewRow;
		var nav;

		if(this.table.modExists("edit")){
			cell = this.table.modules.edit.currentCell;

			if(cell){
				e.preventDefault();

				nav = cell.nav();

				if(!nav.next()){
					if(newRow){

						cell.getElement().firstChild.blur();

						if(newRow === true){
							newRow = this.table.addRow({})
						}else{
							if(typeof newRow == "function"){
								newRow = this.table.addRow(newRow(cell.row.getComponent()))
							}else{
								newRow = this.table.addRow(Object.assign({}, newRow));
							}
						}

						newRow.then(() => {
							setTimeout(() => {
								nav.next();
							})
						});
					}
				}
			}
		}
	},

	navLeft:function(e){
		var cell = false;

		if(this.table.modExists("edit")){
			cell = this.table.modules.edit.currentCell;

			if(cell){
				e.preventDefault();
				cell.nav().left();
			}
		}
	},

	navRight:function(e){
		var cell = false;

		if(this.table.modExists("edit")){
			cell = this.table.modules.edit.currentCell;

			if(cell){
				e.preventDefault();
				cell.nav().right();
			}
		}
	},

	navUp:function(e){
		var cell = false;

		if(this.table.modExists("edit")){
			cell = this.table.modules.edit.currentCell;

			if(cell){
				e.preventDefault();
				cell.nav().up();
			}
		}
	},

	navDown:function(e){
		var cell = false;

		if(this.table.modExists("edit")){
			cell = this.table.modules.edit.currentCell;

			if(cell){
				e.preventDefault();
				cell.nav().down();
			}
		}
	},

	undo:function(e){
		var cell = false;
		if(this.table.options.history && this.table.modExists("history") && this.table.modExists("edit")){

			cell = this.table.modules.edit.currentCell;

			if(!cell){
				e.preventDefault();
				this.table.modules.history.undo();
			}
		}
	},

	redo:function(e){
		var cell = false;
		if(this.table.options.history && this.table.modExists("history") && this.table.modExists("edit")){

			cell = this.table.modules.edit.currentCell;

			if(!cell){
				e.preventDefault();
				this.table.modules.history.redo();
			}
		}
	},

	copyToClipboard:function(e){
		if(!this.table.modules.edit.currentCell){
			if(this.table.modExists("clipboard", true)){
				this.table.modules.clipboard.copy(false, true);
			}
		}
	},
};


Tabulator.prototype.registerModule("keybindings", Keybindings);