import { IgniteProperty, IgniteAttribute } from './ignite-html.js';

class IgniteTemplate {
    constructor(items) {
        this.siblings = [];
        this.children = [];
        this.attributes = {};
        this.classes = [];
        this.tagName = null;
        this.element = null;
        this.properties = {};

        if (items) {
            for (var i = 0; i < items.length; i++) {
                if (items[i] instanceof IgniteAttribute) {
                    this.attributes.push(items[i]);
                } else if (items[i] instanceof IgniteProperty) {
                    this.children.push(new propertyObserver(items[i]));
                } else {
                    this.children.push(items[i]);
                }
            }
        }
    }

    class(...items) {
        for (var i = 0; i < items.length; i++) {
            if (items[i] instanceof IgniteProperty) {
                items[i].onPropertyChange.push((oldValue, newValue) => this.onClassChanged(oldValue, newValue));
                this.classes.push(items[i].value);
            } else {
                this.classes.push(items[i]);
            }
        }

        return this;
    }

    attribute(name, value) {
        if (value instanceof IgniteProperty) {
            value.onPropertyChange.push((oldValue, newValue) => this.onAttributeChanged(oldValue, newValue, name));
            this.attributes[name] = value.value;
        } else {
            this.attributes[name] = value;
        }

        return this;
    }

    property(name, value) {
        if (value instanceof IgniteProperty) {
            value.onPropertyChange.push((oldValue, newValue) => this.onPropertyChanged(oldValue, newValue, name));
            this.properties[name] = value.value;
        } else {
            this.properties[name] = value;
        }

        return this;
    }

    child(...items) {
        this.children = this.children.concat(items);

        return this;
    }

    construct(parent) {
        //Construct this element if we haven't already
        if (!this.element) {
            this.element = window.document.createElement(this.tagName);
            parent.appendChild(this.element);
        }

        //Set the classes on this element
        for (var i = 0; i < this.classes.length; i++) {
            if (this.classes[i] !== null && this.classes[i] !== undefined) {
                this.element.classList.add(this.classes[i]);
            }
        }

        //Set the attributes on this element
        var keys = Object.keys(this.attributes);
        for (var i = 0; i < keys.length; i++) {
            if (this.attributes[keys[i]] !== null && this.attributes[keys[i]] !== undefined) {
                this.element.setAttribute(keys[i], this.attributes[keys[i]]);
            }
        }

        //Set the properties on this element
        var keys = Object.keys(this.properties);
        for (var i = 0; i < keys.length; i++) {
            this.element[keys[i]] = this.properties[keys[i]];
        }

        //Construct the children under this element
        for (var i = 0; i < this.children.length; i++) {
            if (this.children[i] instanceof String || typeof this.children[i] === 'string') {
                this.element.appendChild(document.createTextNode(this.children[i]));
            } else if (this.children[i] instanceof IgniteTemplate || this.children[i].prototype instanceof IgniteTemplate) {
                this.children[i].construct(this.element);
            }
        }
    }

    onClassChanged(oldValue, newValue) {
        console.log(`Class changed, oldValue: ${oldValue} newValue: ${newValue}`);

        if (oldValue !== null && oldValue !== undefined && oldValue !== "" && oldValue !== " ") {
            this.element.classList.remove(oldValue);
        }

        if (newValue !== null && newValue !== undefined && newValue !== "" && newValue !== " ") {
            this.element.classList.add(newValue);
        }
    }

    onAttributeChanged(oldValue, newValue, attributeName) {
        console.log(`Attribute changed, oldValue: ${oldValue} newValue: ${newValue} attribute: ${attributeName}`);

        if (newValue == null || newValue == undefined) {
            this.element.removeAttribute(attributeName);
        } else {
            this.element.setAttribute(attributeName, newValue);
        }
    }

    onPropertyChanged(oldValue, newValue, propertyName) {
        console.log(`Property changed, oldValue: ${oldValue} newValue: ${newValue} property: ${propertyName}`);
        this.properties[propertyName] = newValue;
        this.element[propertyName] = newValue;
    }
}

class div extends IgniteTemplate {
    constructor(...items) {
        super(items);

        this.tagName = "div";
    }
}

class a extends IgniteTemplate {
    constructor(...items) {
        super(items);

        this.tagName = "a";
    }
}

class html extends IgniteTemplate {
    constructor(code) {
        super([]);
        this.code = code;
    }

    construct(parent) {
        if (!parent) {
            parent = window.document.body;
        }

        parent.insertAdjacentHTML('beforeend', this.code);
    }
}

class list extends IgniteTemplate {
    constructor(list, forEach) {
        super([]);

        if (list instanceof IgniteProperty) {
            list.onPropertyChange.push((oldValue, newValue) => {
                this.list = list.value;
                this.construct(null); //If the list changed, reconstruct this template
            });

            this.list = list.value;
        } else {
            this.list = list;
        }

        this.forEach = forEach;
        this.elements = [];
    }

    construct(parent) {
        if (!this.element) {
            this.element = window.document.createTextNode(""); //Use a textnode as our placeholder
            parent.appendChild(this.element);
        }

        //If we already have elements we created, destroy them.
        if (this.elements.length > 0) {
            for (var i = 0; i < this.elements.length; i++) {
                this.elements[i].remove();
            }
            this.elements = [];
        }

        //Create a temporary container
        var container = window.document.createElement("div");

        //Construct all the items in our list and use the container
        if (this.list) {
            for (var i = 0; i < this.list.length; i++) {
                this.forEach(this.list[i]).construct(container);
            }
        }

        //If we have any child nodes in the container, save the element, and add it after our placeholder
        while (container.childNodes.length > 0) {
            this.elements.push(container.childNodes[0]);
            this.element.parentElement.insertBefore(container.childNodes[0], this.element);
        }

        //Make sure we cleanup the container to be safe.
        container.remove();
        container = null;
    }
}

export {
    IgniteTemplate,
    div,
    html,
    list,
    a
};