const NodeBuilder = require('./node-builder');

const Klass = new Class();
module.exports = Klass;

Klass.extend({Classes: ''});

const ComponentClass = {
	Extends: NodeBuilder,
	Tag: 'vn-component',
	Properties: {
		/**
		 * Main HTML node that represents the component
		 */
		node: {
			type: Object
			,get: function() {
				this.renderBase();
				return this._node;
			}
		},
		/**
		 * CSS syle.
		 */
		style: {
			type: String
			,set: function(x) {
				this.node.style = x;
			}
			,get: function() {
				return this._node.style;
			}
		},
		/**
		 * CSS classes to be appendend to the node classes.
		 */
		class: {
			type: String
			,set: function(x) {
				this._className = x;
				this._refreshClass();
			}
			,get: function() {
				return this._className;
			}
		},
		/**
		 * CSS classes to be appendend to the node classes.
		 */
		className: {
			type: String
			,set: function(x) {
				this._className = x;
				this._refreshClass();
			}
			,get: function() {
				return this._className;
			}
		},
		/**
		 * CSS class list.
		 */
		classList: {
			type: Object
			,get: function() {
				return this._node.classList;
			}
		},
		/**
		 * Title of the element.
		 */
		title: {
			type: String
			,set: function(x) {
				this._node.title = x;
			}
			,get: function() {
				return this._node.title;
			}
		},
		/**
		 * The HTML id of the element.
		 */
		htmlId:
		{
			type: String
			,set: function(x) {
				this._htmlId = x;
				if (this._node)
					this._node.id = x;
			}
			,get: function() {
				return this._htmlId;
			}
		},
	}

	,_node: null
	,scope: null
	
	,initialize: function(props) {
		this.doc = document;
		this.renderBase();
		NodeBuilder.prototype.initialize.call(this, props);
	}
	
	,createRoot: function(tagName) {
		const node = this._node = this.createElement(tagName);
		node.$ctrl = this;
		if (this._htmlId)
			node.id = this._htmlId;
		if (this.$constructor.Classes)
			node.className = this.$constructor.Classes;
		return node;
	}
	
	,appendChild: function(child) {
		if (child instanceof Klass)
			this._node.appendChild(child.node);
		else if (child instanceof Element)
			this._node.appendChild(child);
	}
	
	,renderBase: function() {
		if (this._node)
			return;

		this.render();
		this._refreshClass();
	}

	,_refreshClass: function() {
		if (this._node && this._className)
			this._node.className = this._className +' '+ (this._node.className || '');
	}
	
	,remove: function() {
		Vn.Node.remove(this._node);
	}

	,on: function(id, callback, instance) {
		if (htmlEventMap[id]) {
			this.addEventListener(id,
				callback.bind(instance, this));
		} else
			NodeBuilder.prototype.on.call(this, id, callback, instance);
	}

	,loadTemplateFromFile: function(path) {
		const builder = new Vn.Builder();
		builder.compileFile(path);
		this.loadScope(builder);
	}
	
	,loadTemplateFromString: function(xmlString) {
		const builder = new Vn.Builder();
		builder.compileString(xmlString);
		this.loadScope(builder);
	}
	
	,loadScope: function(builder) {
		const scope = this.scope = builder.load(this.doc, this);
		scope.link();

		this.$ = scope.$;
		this._node = scope.$.main;
	}

	,_destroy: function() {
		if (this.scope)
			this.scope.unref();

		NodeBuilder.prototype._destroy.call(this, );
	}
};

htmlEventMap = {};
htmlEvents = [
	'click',
	'dblclick',
	'keydown',
	'keypress',
	'keyup',
	'mousedown',
	'mousemove',
	'mouseout',
	'mouseover',
	'mouseup',
	'mousewheel',
	'wheel',
	'focus',
	'focusout',
	'focusin'
];
htmlEvents.forEach(x => htmlEventMap[x] = true);

htmlMethods = [
	'addEventListener'
];
htmlMethods.forEach(method => {
	ComponentClass[method] = function() {
		this.node[method].apply(this.node, arguments);
	};
});

Klass.implement(ComponentClass);