const store = require('./store');

module.exports = class Component {

    constructor (name, model = { }) {
        this.kind = name;
        this.model = model;

        store.get('components').set(this, new WeakMap());
    }

    of (entity) {
        return store.get('components').get(this).get(entity);
    }

    validate (type, value) {
        switch (type) {
            case Array: return Array.isArray(value);
            case Boolean: return typeof value === 'boolean' || value instanceof Boolean;
            case Function: return typeof value === 'function' || value instanceof Function;
            case Map: return value instanceof Map;
            case Number: return typeof value === 'number' || value instanceof Number;
            case Object: return typeof value === 'object' || value instanceof Object;
            case Set: return value instanceof Set;
            case String: return typeof value === 'string' || value instanceof String;
            case Symbol: return typeof value === 'symbol';
            case WeakMap: return value instanceof WeakMap;
            case WeakSet: return value instanceof WeakSet;
            default: return false;
        }
    }

    create (entity, data = { }) {

        if (typeof this.model === 'function') {

            if (this.validate(this.model, data)) try {
                store.get('components').get(this).set(entity, new this.model(data));
            }
            catch (_) {
                store.get('components').get(this).set(entity, this.model(data));
            }
            finally {
                return data;
            }
            else {
                const expected = this.model.name.toLowerCase();
                const actual = typeof data;

                throw new TypeError(`Wrong type for component: expected ${ expected }, found ${ actual }`);
            }
        }
        else {
            const missing = [ ];
            const validated = { };

            for (const [ key, value ] of Object.entries(data)) {

                if (key in this.model && this.validate(this.model[ key ], value)) {
                    validated[ key ] = value;
                }
                else {
                    const expected = this.model[ key ].name.toLowerCase();
                    const actual = typeof value;

                    throw new TypeError(`Wrong type for property "${ key }": expected ${ expected }, found ${ actual }`);
                }
            }

            store.get('components').get(this).set(entity, validated);

            return validated;
        }
    }

    update (entity, model) {
        return Object.assign(store.get('components').get(this).get(entity), model);
    }

    extend (model) {
        Object.assign(this.model, model);
    }
}

Object.defineProperty(module.exports, 'kinds', {
    get () {
        return store.get('components').values();
    }
});

@@ -32,25 +32,8 @@
 );%0A%0A
-module.exports = 
 clas
@@ -46,16 +46,16 @@
 onent %7B%0A
+
 %0A    con
@@ -296,884 +296,8 @@
  %7D%0A%0A
-    validate (type, value) %7B%0A        switch (type) %7B%0A            case Array: return Array.isArray(value);%0A            case Boolean: return typeof value === 'boolean' %7C%7C value instanceof Boolean;%0A            case Function: return typeof value === 'function' %7C%7C value instanceof Function;%0A            case Map: return value instanceof Map;%0A            case Number: return typeof value === 'number' %7C%7C value instanceof Number;%0A            case Object: return typeof value === 'object' %7C%7C value instanceof Object;%0A            case Set: return value instanceof Set;%0A            case String: return typeof value === 'string' %7C%7C value instanceof String;%0A            case Symbol: return typeof value === 'symbol';%0A            case WeakMap: return value instanceof WeakMap;%0A            case WeakSet: return value instanceof WeakSet;%0A            default: return false;%0A        %7D%0A    %7D%0A%0A
     
@@ -392,20 +392,25 @@
     if (
-this
+Component
 .validat
@@ -1170,20 +1170,25 @@
 odel && 
-this
+Component
 .validat
@@ -1899,44 +1899,882 @@
 %0A%7D%0A%0A
-Object.defineProperty(module.exports
+Component.validate = function validate (type, value) %7B%0A    switch (type) %7B%0A        case Array: return Array.isArray(value);%0A        case Boolean: return typeof value === 'boolean' %7C%7C value instanceof Boolean;%0A        case Function: return typeof value === 'function' %7C%7C value instanceof Function;%0A        case Map: return value instanceof Map;%0A        case Number: return typeof value === 'number' %7C%7C value instanceof Number;%0A        case Object: return typeof value === 'object' %7C%7C value instanceof Object;%0A        case Set: return value instanceof Set;%0A        case String: return typeof value === 'string' %7C%7C value instanceof String;%0A        case Symbol: return typeof value === 'symbol';%0A        case WeakMap: return value instanceof WeakMap;%0A        case WeakSet: return value instanceof WeakSet;%0A        default: return false;%0A    %7D%0A%7D;%0A%0AObject.defineProperty(Component
 , 'k
@@ -2854,8 +2854,37 @@
   %7D%0A
-
 %7D);%0A
+%0Amodule.exports = Component;%0A

Clean up component