"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
var DescribeView_1;
const ejs = require("ejs");
const fs = require("fs");
const path = require("path");
const server_1 = require("@methodus/server");
const clientDir = path.resolve(path.join(__dirname, '../client'));
var urlBuilder = require('url');
function fullUrl(req) {
    const originalUrl = req.originalUrl.split('/describe')[0];
    return '//' + req.headers['host'] + originalUrl + '/describe/';
}
const prefix = process.env.describe_route || '';
let DescribeView = DescribeView_1 = class DescribeView {
    constructor(expressInstance) {
        this.expressInstance = expressInstance;
        // this._app.use(describe.init());
    }
    static maybeMethodus(object) {
        let proto = object.prototype;
        if (proto && proto.constructor && proto.constructor.methodus) {
            return proto.constructor.methodus[object.name];
        }
        if (!proto && object.__proto__ && object.__proto__.methodus) {
            return object.__proto__.methodus[object.name];
        }
        if (object.methodus) {
            return object.methodus[object.name];
        }
        return proto.methodus[object.name];
    }
    getMethodusData() {
        const data = global.METHODUS_BRIDGE;
        let routes = [];
        Object.keys(data.classes).forEach((cls) => {
            const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
            let pj = null;
            try {
                pj = require(path.join(process.cwd(), 'node_modules', methodus.name, 'package.json'));
            }
            catch (error) {
                pj = { 'version': 'NA' };
            }
            routes.push({ name: cls, methodus: methodus, info: pj });
        });
        return new server_1.MethodResult(routes);
    }
    getMethodusDataClass(className) {
        const data = global.METHODUS_BRIDGE;
        let routes = [];
        const methodus = DescribeView_1.maybeMethodus(data.classes[className].classType);
        let pj = null;
        try {
            pj = require(path.join(process.cwd(), 'node_modules', methodus.name, 'package.json'));
        }
        catch (error) {
            pj = { 'version': 'NA' };
        }
        routes.push({ name: className, methodus: methodus, info: pj });
        return new server_1.MethodResult(routes);
    }
    describeproxy(application_endpoint, applicationName, req, res) {
        //
        // Create a proxy server with custom application logic
        //
        // if (!proxies[application_endpoint]) {
        //     const proxy = httpProxy.createProxyServer({ target: application_endpoint });
        //     proxies[application_endpoint] = proxy;
        // }
        // console.log('--==>>', req.url);
        // // You can define here your custom logic to handle the request
        // // and then proxy the  request.
        // proxies[application_endpoint].web(req, res, { target: application_endpoint }, (e) => {
        //     res.send(e);
        // });
        return new server_1.MethodResult({});
    }
    info(req) {
        let str = fs.readFileSync(path.join(clientDir, 'views/describe.ejs'), 'utf-8');
        var template = ejs.compile(str, { filename: path.join(clientDir, 'views/describe.ejs') });
        const data = global.METHODUS_BRIDGE;
        const packageJson = require(path.join(process.cwd(), 'package.json'));
        let routes = [];
        Object.keys(data.classes).forEach((cls) => {
            if (data.classes[cls].methodType === "Local" /* Local */) {
                const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
                routes.push({ active: true, methodus: methodus, name: cls });
            }
        });
        let result = template(Object.assign({}, global.METHODUS_BRIDGE, { routes: routes }, 
        // { remoteRoutes: remoteRoutes },
        { app: packageJson }, {
            makeFrameName: (route) => {
                return (route + '_Frame').replace(/\//g, '_').replace(/:/g, '');
            },
            cleanID: (route) => {
                return (route.name + '__' + route.methodus.name).replace(/\//, '').replace('@', '');
            },
            adaptResolver: (url) => {
                if (url.indexOf('127.0.0.1') > 0) {
                    url = url.replace('127.0.0.1', req.host);
                }
                if (url.indexOf('localhost') > 0) {
                    url = url.replace('localhost', req.host);
                }
                return url;
            }
        }));
        return new server_1.MethodResult(result);
    }
    swaggerize(env, req) {
        const data = global.METHODUS_BRIDGE;
        const packageJson = require(path.join(process.cwd(), 'package.json'));
        let routes = [];
        let swagger = {
            "swagger": "2.0",
            "info": {
                "title": packageJson.name,
                "description": packageJson.description,
                "version": packageJson.version
            },
            "host": req.headers.host,
            "basePath": "/",
            "schemes": [req.protocol],
            "paths": {}
        };
        Object.keys(data.classes).forEach((cls) => {
            if (data.classes[cls].methodType === "Local" /* Local */) {
                const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
                Object.keys(methodus._descriptors).forEach((descriptorKey) => {
                    const descriptor = methodus._descriptors[descriptorKey];
                    let route = descriptor.route;
                    if (route.indexOf(':') > -1) {
                        descriptor.params.filter(item => item.from === 'params').forEach((param) => {
                            route = route.replace(`:${param.name}`, `{${param.name}}`);
                        });
                    }
                    swagger.paths[route] = {
                        [descriptor.verb.toLowerCase()]: {
                            "description": descriptor.comment,
                            "responses": {},
                            "parameters": descriptor.params.filter(item => item.from === 'query' || item.from === 'params').map((param) => {
                                return {
                                    "name": param.name,
                                    "in": "path",
                                    "description": param,
                                    "required": true,
                                    "schema": {
                                        "type": param.type,
                                    },
                                    "style": "simple"
                                };
                            })
                        }
                    };
                });
                // routes.push({ methodus: methodus, name: cls });
            }
        });
        // let remoteRoutes = [];
        // Object.keys(data.classes).map((cls) => {
        //     if (data.classes[cls].methodType !== MethodType.Local) {
        //         const methodus = DescribeView.maybeMethodus(data.classes[cls].classType);
        //         let pj = { 'version': 'NA' }
        //         try {
        //             pj = require(path.join(process.cwd(), 'node_modules', methodus.name, 'package.json'));
        //         } catch (error) {
        //         }
        //         remoteRoutes.push({ info: pj, active: true, methodus: methodus, configuration: data.classes[cls], name: cls });
        //     }
        // });
        return new server_1.MethodResult(swagger);
    }
    dashboard(req, res) {
        let str = fs.readFileSync(path.join(clientDir, 'tabs/dashboard_tabs.ejs'), 'utf-8');
        var template = ejs.compile(str, { filename: path.join(clientDir, 'tabs/dashboard_tabs.ejs') });
        const data = global.METHODUS_BRIDGE;
        // <%-include('tabs/dashboard_tabs', {routes: routes,remoteRoutes:remoteRoutes}); %>
        const packageJson = require(path.join(process.cwd(), 'package.json'));
        let routes = [];
        Object.keys(data.classes).forEach((cls) => {
            if (data.classes[cls].methodType === "Local" /* Local */) {
                const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
                let pj = { 'version': 'NA' };
                try {
                    pj = require(path.join(process.cwd(), 'node_modules', methodus.name, 'package.json'));
                }
                catch (error) {
                    try {
                        pj = require(path.join(methodus.name, 'package.json'));
                    }
                    catch (error) {
                    }
                }
                routes.push({ info: pj, active: true, methodus: methodus, name: cls });
            }
        });
        let remoteRoutes = [];
        Object.keys(data.classes).forEach((cls) => {
            if (data.classes[cls].methodType !== "Local" /* Local */) {
                const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
                let pj = { 'version': 'NA' };
                try {
                    pj = require(path.join(process.cwd(), 'node_modules', methodus.name, 'package.json'));
                }
                catch (error) {
                }
                remoteRoutes.push({ info: pj, active: true, methodus: methodus, configuration: data.classes[cls], name: cls });
            }
        });
        let events = {};
        Object.keys(data.classes).forEach((cls) => {
            const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
            if (methodus._workevents && Object.keys(methodus._workevents).length > 0) {
                Object.keys(methodus._workevents).forEach((eventKey) => {
                    methodus._workevents[eventKey].class = data.classes[cls];
                    methodus._workevents[eventKey].eventKey = eventKey;
                    methodus._workevents[eventKey].event_type = 'Event Worker';
                    events[cls] = events[cls] || { events: [] };
                    events[cls].events.push(methodus._workevents[eventKey]);
                });
            }
            if (methodus._events && Object.keys(methodus._events).length > 0) {
                Object.keys(methodus._events).forEach((eventKey) => {
                    methodus._events[eventKey].class = data.classes[cls];
                    methodus._events[eventKey].eventKey = eventKey;
                    methodus._events[eventKey].event_type = 'Event Handler';
                    events[cls] = events[cls] || { events: [] };
                    events[cls].events.push(methodus._events[eventKey]);
                });
            }
            if (methodus._workers && Object.keys(methodus._workers).length > 0) {
                Object.keys(methodus._workers).forEach((eventKey) => {
                    methodus._workers[eventKey].class = data.classes[cls];
                    methodus._workers[eventKey].eventKey = eventKey;
                    methodus._workers[eventKey].event_type = 'Worker';
                    events[cls] = events[cls] || { events: [] };
                    events[cls].events.push(methodus._workers[eventKey]);
                });
            }
        });
        let result = template(Object.assign({}, global.METHODUS_BRIDGE, { routes: routes, remoteRoutes: remoteRoutes, events: events }, { app: packageJson }, { base: fullUrl(req) }, {
            makeFrameName: (route) => {
                return (route + '_Frame').replace(/\//g, '_').replace(/:/g, '');
            },
            cleanID: (route) => {
                return (route.name + '__' + route.methodus.name).replace(/\//, '').replace('@', '');
            },
            adaptResolver: (urlx) => {
                if (urlx.indexOf('127.0.0.1') > 0) {
                    urlx = urlx.replace('127.0.0.1', req.host);
                }
                if (urlx.indexOf('localhost') > 0) {
                    urlx = urlx.replace('localhost', req.host);
                }
                return urlx;
            }
        }));
        return new server_1.MethodResult(result);
    }
    parentFrame(req, res) {
        let str = fs.readFileSync(path.join(clientDir, 'frame.ejs'), 'utf-8');
        var template = ejs.compile(str, { filename: path.join(clientDir, 'frame.ejs') });
        const packageJson = require(path.join(process.cwd(), 'package.json'));
        let result = template({}, { app: packageJson });
        return new server_1.MethodResult(result);
    }
    describe(req, res) {
        let str = fs.readFileSync(path.join(clientDir, 'index.ejs'), 'utf-8');
        var template = ejs.compile(str, { filename: path.join(clientDir, 'index.ejs') });
        const data = global.METHODUS_BRIDGE;
        const packageJson = require(path.join(process.cwd(), 'package.json'));
        let routes = [];
        let events = [];
        Object.keys(data.classes).forEach((cls) => {
            const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
            if (methodus._workevents) {
                Object.keys(methodus._workevents).forEach(event => {
                    events.push(event);
                });
            }
        });
        Object.keys(data.classes).forEach((cls) => {
            if (data.classes[cls].methodType === "Local" /* Local */) {
                const methodus1 = DescribeView_1.maybeMethodus(data.classes[cls].classType);
                routes.push({ active: true, methodus: methodus1, name: cls });
            }
        });
        let remoteRoutes = [];
        Object.keys(data.classes).forEach((cls) => {
            if (data.classes[cls].methodType !== "Local" /* Local */) {
                const methodus = DescribeView_1.maybeMethodus(data.classes[cls].classType);
                remoteRoutes.push({ active: true, methodus: methodus, configuration: data.classes[cls], name: cls });
            }
        });
        try {
            let result = template(Object.assign({}, global.METHODUS_BRIDGE, { routes: routes }, { events: events }, { remoteRoutes: remoteRoutes }, { app: packageJson }, { base: fullUrl(req) }, { logs: [] }, {
                makeFrameName: (route) => {
                    return (route + '_Frame').replace(/\//g, '_').replace(/:/g, '');
                },
                cleanID: (route) => {
                    return (route.name + '__' + route.methodus.name).replace(/\//, '').replace('@', '');
                },
                adaptResolver: (url1) => {
                    if (url1.indexOf('127.0.0.1') > 0) {
                        url1 = url1.replace('127.0.0.1', req.host);
                    }
                    if (url1.indexOf('localhost') > 0) {
                        url1 = url1.replace('localhost', req.host);
                    }
                    return url1;
                }
            }));
            return new server_1.MethodResult(result);
        }
        catch (error) {
            console.error(error);
        }
    }
    action(className, actionKey, req, res) {
        let str = fs.readFileSync(path.join(clientDir, 'test.ejs'), 'utf-8');
        var template = ejs.compile(str);
        const data = global.METHODUS_BRIDGE;
        const testedClass = data.classes[className];
        const methodus = DescribeView_1.maybeMethodus(testedClass.classType);
        const helper = {
            reflectSmallTypes: (param) => {
                if (param.name) {
                    return param.name.toLowerCase();
                }
            },
            reflectObject: (param) => {
                return param.name;
            },
            nameResolver: (param) => {
                let finalName = '';
                if ((param.from === 'body' && param.name) || param.from === 'files') {
                    return `name="${param.name || param.from}"`;
                }
                else {
                    return `id="${param.name || param.from}"`;
                }
            }
        };
        let result = template(Object.assign({}, { base: fullUrl(req) }, { helper: helper, methodus: methodus, cls: testedClass.classType, actionKey: actionKey }));
        return new server_1.MethodResult(result);
    }
    eventAction(className, actionKey, req, res) {
        let str = fs.readFileSync(path.join(clientDir, 'testEvent.ejs'), 'utf-8');
        var template = ejs.compile(str);
        const data = global.METHODUS_BRIDGE;
        const testedClass = data.classes[className];
        const methodus = DescribeView_1.maybeMethodus(testedClass.classType);
        const helper = {
            reflectSmallTypes: (param1) => {
                if (param1.name) {
                    return param1.name.toLowerCase();
                }
            },
            reflectObject: (param) => {
                return param.name;
            },
            nameResolver: (param) => {
                let finalName1 = '';
                if ((param.from === 'body' && param.name) || param.from === 'files') {
                    return `name="${param.name || param.from}"`;
                }
                else {
                    return `id="${param.name || param.from}"`;
                }
            }
        };
        let testedEvent = { event_type: '', class: null };
        if (methodus._workevents[actionKey]) {
            testedEvent = { event_type: 'Event Worker', class: methodus._workevents[actionKey] };
        }
        else if (methodus._events[actionKey]) {
            testedEvent = { event_type: 'Event Handler', class: methodus._workevents[actionKey] };
        }
        else if (methodus._workers[actionKey]) {
            testedEvent = { event_type: 'Worker', class: methodus._workevents[actionKey] };
        }
        let result = template(Object.assign({}, { base: fullUrl(req) }, { helper: helper, methodus: testedEvent, cls: testedClass.classType, actionKey: actionKey }));
        return new server_1.MethodResult(result);
    }
};
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/methodus'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "getMethodusData", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/methodus/:className'),
    __param(0, server_1.Param('className')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "getMethodusDataClass", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describeproxy/:path'),
    __param(0, server_1.Query('u')), __param(1, server_1.Param('path')), __param(2, server_1.Request()), __param(3, server_1.Response()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "describeproxy", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/info'),
    __param(0, server_1.Request()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "info", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/swaggerize/:env'),
    __param(0, server_1.Param('env')), __param(1, server_1.Request()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "swaggerize", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/dashboard'),
    __param(0, server_1.Request()), __param(1, server_1.Response()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "dashboard", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/'),
    __param(0, server_1.Request()), __param(1, server_1.Response()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "parentFrame", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/inner'),
    __param(0, server_1.Request()), __param(1, server_1.Response()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "describe", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/test/:className/:actionKey'),
    __param(0, server_1.Param('className')), __param(1, server_1.Param('actionKey')), __param(2, server_1.Request()), __param(3, server_1.Response()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "action", null);
__decorate([
    server_1.Method("GET" /* Get */, prefix + '/describe/testevent/:className/:actionKey'),
    __param(0, server_1.Param('className')), __param(1, server_1.Param('actionKey')), __param(2, server_1.Request()), __param(3, server_1.Response()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, Object, Object]),
    __metadata("design:returntype", void 0)
], DescribeView.prototype, "eventAction", null);
DescribeView = DescribeView_1 = __decorate([
    server_1.MethodConfig('DescribeView'),
    __metadata("design:paramtypes", [Object])
], DescribeView);
exports.DescribeView = DescribeView;
//# sourceMappingURL=describeView.js.map