"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular-devkit/schematics");
const util_1 = require("../../lib/util");
const core_1 = require("@angular-devkit/core");
const angular_utility_1 = require("../../lib/angular-utility");
const lib_1 = require("../../lib");
const debug = console.debug; // TODO fix
// import * as test from "../page/extensions/MonitoringDashboardPage";
const sections = ['init', 'declaration'];
class PageRenderEngine {
    constructor(project) {
        this.project = project;
    }
    static getTemplatePath(type) {
        return `../page/files/${type}`;
    }
    render(pages) {
        return this.renderPages(pages, undefined);
    }
    renderPage(page, _options = {}) {
        debug(`***** Rendering page "${page.pageTitle}" [${page.type}] *****`);
        if (page.type === "TapConnectionPage") {
            return schematics_1.schematic("page-tap-connection", _options);
        }
        let rules = [];
        let templatePath = PageRenderEngine.getTemplatePath(page.type);
        let sourceTemplates = schematics_1.url(templatePath);
        let pageRenderEngine = new PageContentRenderEngine(this.project.context);
        let sourceTemplateTree = sourceTemplates(this.project.context);
        let templateFileCount = 0;
        sourceTemplateTree.visit(visitor => {
            templateFileCount++;
        });
        if (templateFileCount === 0) {
            throw new Error(`Cannot find any template file for "${page.type}" in ${templatePath}`);
        }
        let routes = this.project.createRoutesForPages(page, pagesToArray(page.children));
        let routingScope = 'Child';
        let templateSpecifics;
        try {
            let extension = require(`../page/extensions/${page.type}/index`);
            if (extension.toTemplate) {
                templateSpecifics = extension.toTemplate(this.project, page);
            }
            // console.info('templateSpecifics', templateSpecifics);
        }
        catch (err) {
            // console.warn('NOT FOUND', err);
        }
        let relativePath = page.projectPath;
        const { name, path } = lib_1.getAngularProjectPath(relativePath, this.project.tree, _options);
        page.url = this._getPageUrl(page);
        let mainRule = angular_utility_1.applyWithOverwriteRule(sourceTemplates, [
            schematics_1.template(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, page), { name,
                page }), this.project.toTemplate()), pageRenderEngine.toTemplate(page)), { routes,
                routingScope }), templateSpecifics), { childrenRoutes: this.project.createRoutesForPages(page, pagesToArray(page.children)) })),
            schematics_1.move(path)
        ], {
            overwrite: _options.overwrite,
            format: true
        });
        rules.push(mainRule);
        if (page.children) {
            rules.push(this.renderPages(page.children, page));
        }
        return schematics_1.chain(rules);
    }
    _getPageUrl(page) {
        let parentUrl = page.__parent ? `${this._getPageUrl(page.__parent)}` : '';
        return `${parentUrl}/${page.path}`;
    }
    renderPages(pages, parent) {
        let rules = [];
        let iterablePages = pagesToArray(pages);
        for (let page of iterablePages) {
            page.__parent = parent;
            if (!page.type) {
                throw new Error(`Page type is missing for ${page.pageTitle}`);
            }
            rules.push(this.renderPage(page));
        }
        return schematics_1.chain(rules);
    }
}
exports.PageRenderEngine = PageRenderEngine;
function pagesToArray(pages) {
    return !Array.isArray(pages) ? Object.values(pages || {}) : pages;
}
function codify(input) {
    return input.replace(/\\n/g, '');
}
class PageContentRenderEngine {
    constructor(context) {
        this.context = context;
        this.componentContent = {
            'init': '',
            'declaration': ''
        };
    }
    toTemplate(element) {
        return Object.assign(Object.assign(Object.assign({ __element__: element }, element), core_1.strings), { renderEngine: this, variableInput: (data) => {
                if (data.variableIndex !== undefined) {
                    return `subVariable(variables.${util_1.variablenamify(data.variable)}, ${data.variableIndex})`;
                }
                else {
                    return `variables['${util_1.variablenamify(data.variable)}']`;
                }
            }, jsonify: util_1.jsonify,
            variablenamify: util_1.variablenamify,
            codify });
    }
    renderHTML(element) {
        try {
            let html = this._render(element, '/content.html', false);
            for (let section of sections) {
                let ts = this._render(element, `/${section}.ts`, true);
                if (ts) {
                    this.componentContent[section] += ts + `\r\n`;
                }
            }
            return html;
        }
        catch (err) {
            // let templatePath = this._resolveTemplatePath(element);
            throw new Error(`Cannot render template "${element.type}". ${err.message}`);
        }
    }
    renderTS(section, element) {
        return this.componentContent[section];
    }
    renderHtmlAttributes(obj) {
        if (!obj) {
            return '';
        }
        let result = '';
        for (let key in obj) {
            let value = obj[key];
            if (value === undefined) {
                continue;
            }
            result += ` ${key}="`;
            if (typeof value === "string") {
                result += `${value}`;
            }
            else if (typeof value === "boolean" || typeof value === "number") {
                result += value.toString();
            }
            else {
                throw new Error(`Invalid value for key "${key}" in renderHtmlAttributes()`);
            }
            result += `"`;
        }
        return result;
    }
    _render(element, filename, allowMissingTemplate) {
        if (!element) {
            throw new schematics_1.SchematicsException(`Missing data to render`);
        }
        if (!element.type) {
            throw new schematics_1.SchematicsException(`Element to render does not have a "type" field. ${JSON.stringify(element)}`);
        }
        let templatePath = this._resolveTemplatePath(element);
        // debug(`rendering: "${element.type}" path: ${templatePath}`)//, 'data', element);
        const source = schematics_1.url(templatePath);
        let tree = source(this.context);
        // console.log('TREE: ', tree);
        if (!tree.exists(filename)) {
            if (allowMissingTemplate) {
                return '';
            }
            throw new schematics_1.SchematicsException(`Please create template file "${filename}" in "${templatePath}"`);
        }
        let templateData = Object.assign({}, this.toTemplate(element));
        let result = schematics_1.applyContentTemplate(templateData)(tree.get(filename));
        if (!result) {
            throw new schematics_1.SchematicsException(`applyContentTemplate returned null.`);
        }
        let fileContent = result.content.toString();
        // console.info(`Template result: `, fileContent);
        // let templateRule = template(templateData);
        // let exec = templateRule(tree, this.context);
        // let exec = rule(this.context);
        // if (exec instanceof Observable) {
        //     throw new SchematicsException('Async is not supported in render function');
        //     // tree = await exec.toPromise();
        // }
        // else {
        //     tree = exec as any;
        // }
        // // tree.visit((path) => {
        // //     console.info('Tree', path);
        // // })
        // let fileContentBuffer = tree.read(FILE_NAME);
        // if (!fileContentBuffer) {
        //     throw new SchematicsException(
        //         `Please create template file "${FILE_NAME}" in "${templatePath}"`
        //     )
        // }
        // let fileContent = fileContentBuffer.toString();
        // console.log('RENDERED SOURCE CONTENT: ', fileContent);
        return fileContent;
    }
    _resolveTemplatePath(element) {
        return `../app-page-render-engine/files-includes/layout-builder/v1/components/${element.type}`;
    }
}
exports.PageContentRenderEngine = PageContentRenderEngine;
//# sourceMappingURL=render-engine.js.map