var State = require('./state');
var Builder = require('./builder');
var Adapter = require('./adapter');

function Input () {
	if (!(this instanceof Input)) return new Input();

	this._state = new State();
	this._bindings = [];
	this._adapter = new Adapter(this);
	this._listening = true;

	// NOTE: Define some default connector and parser for generic usage.
	//       Remark that no listener are attached.
	this._adapter
		.connector(function (element) {
			element.addEventListener('keypress', function (e) { this.keydown(e); }.bind(this));
			element.addEventListener('keyup', function (e) { this.keyup(e); }.bind(this));
		})
		.parser(function (e) {
			var stroke = this.stroke();
			stroke.event(e);
			stroke.code(e.keyCode || e.which);
			stroke.shift(e.shiftKey ? true : false);
			stroke.ctrl(e.ctrlKey ? true : false);
			stroke.alt(e.altKey ? true : false);
			return stroke;
		});
}

Input.prototype.keydown = function (stroke) {
	if (!this._listening) return false;

	this._state.down(stroke);
	this.digest();
};

Input.prototype.keyup = function (stroke) {
	if (!this._listening) return false;

	this._state.up(stroke);
	this.digest();
};

Input.prototype.digest = function () {
	for (var i in this._bindings) {
		var event = this._bindings[i].probe(this._state);
		if (!event) continue;
		this.trigger(event);
	}
};

Input.prototype.trigger = function (event) {
	return this._adapter.trigger(event);
};

Input.prototype.state = function (state) {
	if (state === undefined) return this._state;
	this._state = state;
	return this;
};

Input.prototype.bindings = function (bindings) {
	if (bindings === undefined) return this._bindings;
	this._bindings = bindings;
	return this;
};

Input.prototype.adapter = function (adapter) {
	if (adapter === undefined) return this._adapter;
	this._adapter = adapter;
	return this;
};

Input.prototype.listen = function (element) {
	this._adapter.listen(element);
	return this;
};

Input.prototype.fire = function (event) {
	var builder = new Builder(event);
	this._bindings.push(builder.binding());
	return builder;
};

Input.prototype.on = function () {
	this._listening = true;
	return this;
};

Input.prototype.off = function () {
	this._listening = false;
	return this;
};

module.exports = Input;
