/*
//
// Base class for vanilla js webcomponents
//
*/
export class WebComponent extends HTMLElement {

    constructor() {
        super();
    }

    // to be overridden in subclass
    async init() {
    }

    render() {
    }

    definePublicMethods() {
    }

    attributeChangedCallback(name, oldVal, newVal) {
    }

    //

    connectedCallback() {
        let shadowRoot;
        if (!this.shadowRoot) {
            if (this.shadow) {
                shadowRoot = this.root = this.attachShadow({
                    mode: 'open'
                });
            } else {
                shadowRoot = this.root = this
            }
        } else {
            shadowRoot = this.root = this.shadowRoot;
        }
        shadowRoot.appendChild(this.template.content.cloneNode(true));
        this.el = this.root.querySelector('.content');
        this.data = {};
        // this.html = this.html.bind(this);
        this.getData = this.getData.bind(this);
        this.setData = this.setData.bind(this);
        if (this.definePublicMethods) {
            this.definePublicMethods();
        }
        if (this.init) {
            this.init = this.init.bind(this);
        }
        if (this.dataJson) {
            this.data = JSON.parse(this.dataJson);
        }
        if (this.init) {
            this.init().then(() => {
                this.render();
            });
        } else {
            this.render();
        }
    }

    set html(markup) {
        if (this.el && markup) {
            this.el.innerHTML = markup;
        }
    }

    get template() {
        if (this._template) {
            return this._template;
        }
        this._template = document.createElement('template');
        let styles = document.createElement('style');
        let content = document.createElement('div');
        let imports = document.createElement('head');
        imports.innerHTML = this.imports || ``;
        styles.innerHTML = this.styles || ``;
        content.innerHTML = this.htmlTemplate || ``;
        content.className = 'content';
        this._template.content.appendChild(styles);
        this._template.content.appendChild(imports);
        this._template.content.appendChild(content);
        return this._template;
    }

    declareProp(propName, getFn, setFn) {
        let obj = {};
        if (!getFn) {
            getFn = function () {
                if (this.getAttribute(propName) !== null) {
                    return this.getAttribute(propName);
                } else {
                    return '';
                }
            };
        }
        if (!setFn) {
            setFn = function (value) {
                this.setAttribute(propName, value);
            };
        }
        if (propName === 'data-json') {
            setFn = (value) => {
                let data = JSON.parse(value);
                Object.keys(data).forEach((k) => {
                    this.data[k] = data[k];
                });
                this.setAttribute(propName, value);
            };
        }
        obj[this.kebabToLowerCamelCase(propName)] = {get: getFn, set: setFn};
        Object.defineProperties(this, obj);
    }

    dispatch(eventName, detail) {
        this.dispatchEvent(new CustomEvent(eventName, {bubbles: true, detail: detail}));
    }

    setState(state) {
        if (typeof state === 'string' && !this.isJson(state)) {
            console.error('setState only accepts an object as argument');
            return;
        }
        if (typeof state === 'string' && this.isJson(state)) {
            state = JSON.parse(state);
        }
        this.state = {...this.state, ...state};
        this.render()
    }

    setData(object, extend) {
        if (extend) {
            Object.keys(object).forEach((k, i) => {
                this.data[k] = object[k];
            });
        } else {
            this.data = object;
        }
        this.setState({data: this.data});
        // this.render();
    }

    getData() {
        return this.data;
    }

    isJson(jsonString) {
        try {
            let o = JSON.parse(jsonString);
            if (o && typeof o === "object") {
                return o;
            }
        } catch (e) {
        }
        return false;
    }

    kebabToLowerCamelCase(str) {
        let string = str.charAt(0).toLowerCase() + str.slice(1);
        return string.replace(/(\-\w)/g, function (m) {
            return m[1].toUpperCase();
        });
    }

}
