
class CommonComponentBase {

    renderReplace(element, content) { CommonComponentBase.renderReplace(element, content); }

    // FIXME: Deprecate these static functions.
    static renderReplace(element, content)
    {
        element.textContent = '';
        if (content)
            ComponentBase._addContentToElement(element, content);
    }

    _recursivelyUpgradeUnknownElements(parent, findUpgrade, didConstructComponent = () => { })
    {
        let nextSibling;
        for (let child of parent.childNodes) {
            const componentClass = findUpgrade(child);
            if (componentClass) {
                const intance = this._upgradeUnknownElement(parent, child, componentClass);
                didConstructComponent(intance);
            }
            if (child.childNodes)
                this._recursivelyUpgradeUnknownElements(child, findUpgrade, didConstructComponent);
        }
    }

    _upgradeUnknownElement(parent, unknownElement, componentClass)
    {
        const instance = new componentClass;
        const newElement = instance.element();

        for (let i = 0; i < unknownElement.attributes.length; i++) {
            const attr = unknownElement.attributes[i];
            newElement.setAttribute(attr.name, attr.value);
        }
        parent.replaceChild(newElement, unknownElement);

        for (const child of Array.from(unknownElement.childNodes))
            newElement.appendChild(child);

        return instance;
    }

    static _constructStylesheetFromTemplate(styleTemplate, didCreateRule = (selector, rule) => selector)
    {
        let stylesheet = '';
        for (const selector in styleTemplate) {
            const rules = styleTemplate[selector];

            let ruleText = '';
            for (const property in rules) {
                const value = rules[property];
                ruleText += `    ${property}: ${value};\n`;
            }

            const modifiedSelector = didCreateRule(selector, ruleText);

            stylesheet += modifiedSelector + ' {\n' + ruleText + '}\n\n';
        }
        return stylesheet;
    }

    static _constructNodeTreeFromTemplate(template, didCreateElement = (element) => { })
    {
        if (typeof(template) == 'string')
            return [CommonComponentBase._context.createTextNode(template)];
        console.assert(Array.isArray(template));
        if (typeof(template[0]) == 'string') {
            const tagName = template[0];
            let attributes = {};
            let content = null;
            if (Array.isArray(template[1])) {
                content = template[1];
            } else {
                attributes = template[1];
                content = template[2];
            }
            const element = this.createElement(tagName, attributes);
            didCreateElement(element);
            const children = content && content.length ? this._constructNodeTreeFromTemplate(content, didCreateElement) : [];
            for (const child of children)
                element.appendChild(child);
            return [element];
        } else {
            let result = [];
            for (const item of template) {
                if (typeof(item) == 'string')
                    result.push(CommonComponentBase._context.createTextNode(item));
                else
                    result = result.concat(this._constructNodeTreeFromTemplate(item, didCreateElement));
            }
            return result;
        }
    }

    createElement(name, attributes, content) { return CommonComponentBase.createElement(name, attributes, content); }

    static createElement(name, attributes, content)
    {
        const element = CommonComponentBase._context.createElement(name);
        if (!content && (Array.isArray(attributes) || CommonComponentBase._isNode(attributes)
            || attributes instanceof CommonComponentBase._baseClass || typeof(attributes) != 'object')) {
            content = attributes;
            attributes = {};
        }

        if (attributes) {
            for (const name in attributes) {
                if (name.startsWith('on'))
                    element.addEventListener(name.substring(2), attributes[name]);
                else if (attributes[name] === true)
                    element.setAttribute(name, '');
                else if (attributes[name] !== false)
                    element.setAttribute(name, attributes[name]);
            }
        }
        
        if (content)
            CommonComponentBase._addContentToElement(element, content);

        return element;
    }

    static _addContentToElement(element, content)
    {
        if (Array.isArray(content)) {
            for (var nestedChild of content)
                this._addContentToElement(element, nestedChild);
        } else if (CommonComponentBase._isNode(content))
            element.appendChild(content);
         else if (content instanceof CommonComponentBase._baseClass)
            element.appendChild(content.element());
        else
            element.appendChild(CommonComponentBase._context.createTextNode(content));
    }

    createLink(content, titleOrCallback, callback, isExternal, tabIndex=null)
    {
        return CommonComponentBase.createLink(content, titleOrCallback, callback, isExternal, tabIndex);
    }

    static createLink(content, titleOrCallback, callback, isExternal, tabIndex=null)
    {
        var title = titleOrCallback;
        if (callback === undefined) {
            title = content;
            callback = titleOrCallback;
        }

        var attributes = {
            href: '#',
            title: title,
        };

        if (tabIndex)
            attributes['tabindex'] = tabIndex;

        if (typeof(callback) === 'string')
            attributes['href'] = callback;
        else
            attributes['onclick'] = CommonComponentBase._baseClass.createEventHandler(callback);

        if (isExternal)
            attributes['target'] = '_blank';
        return CommonComponentBase.createElement('a', attributes, content);
    }
};

CommonComponentBase._context = null;
CommonComponentBase._isNode = null;
CommonComponentBase._baseClass = null;

if (typeof module != 'undefined')
    module.exports.CommonComponentBase = CommonComponentBase;
