"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseUIController = void 0;
var controller_1 = require("./controller");
var _1 = require(".");
var datagrid_1 = require("lynx-datagrid/datagrid");
var sprintf_js_1 = require("sprintf-js");
/**
 * Basic controller that generates all the UI that contains the logic to perform the
 * different operations.
 */
var BaseUIController = /** @class */ (function (_super) {
    __extends(BaseUIController, _super);
    function BaseUIController() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    /**
     * Generate the list of entities
     * @param req The current Lynx request
     */
    BaseUIController.prototype.generateEntitiesIndex = function (req) {
        return __awaiter(this, void 0, void 0, function () {
            var ctx;
            return __generator(this, function (_a) {
                ctx = {
                    parentTemplate: _1.default.indexParentTemplatePath,
                    entities: this.entitiesList(),
                };
                return [2 /*return*/, this.render(_1.default.indexTemplatePath, req, ctx)];
            });
        });
    };
    /**
     * Perform ajax request for selection values
     * @param entityName the name of the entity
     * @param id the id of the editing entity
     * @param field the name of the field that is edited
     * @param req the current Lynx request
     */
    BaseUIController.prototype.performAjaxRequest = function (entityName, id, field, req) {
        return __awaiter(this, void 0, void 0, function () {
            var entityData, metadata, _field, tmp, e_1, response;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 1:
                        entityData = _a.sent();
                        if (!entityData) {
                            throw this.error(404, 'not found');
                        }
                        metadata = this.retrieveMetadata(entityName);
                        return [4 /*yield*/, this.generateContextMetadata(metadata, req)];
                    case 2:
                        metadata = _a.sent();
                        _field = metadata.fields[field];
                        if (!_field) {
                            throw this.error(500, 'field not found');
                        }
                        if (!_field.searchRequest) {
                            throw this.error(500, "You need to implement the 'searchRequest' parameter for the field '" +
                                field +
                                "'");
                        }
                        if (!req.query.selection) return [3 /*break*/, 7];
                        tmp = entityData[field];
                        if (!req.query.defaultId) return [3 /*break*/, 6];
                        _a.label = 3;
                    case 3:
                        _a.trys.push([3, 5, , 6]);
                        return [4 /*yield*/, this.retrieveEntity(_field.selfType, req.query.defaultId)];
                    case 4:
                        tmp = (_a.sent());
                        return [3 /*break*/, 6];
                    case 5:
                        e_1 = _a.sent();
                        return [3 /*break*/, 6];
                    case 6: return [2 /*return*/, {
                            data: [{ id: tmp.getId(), text: tmp.getLabel() }],
                            pagination: false,
                        }];
                    case 7: return [4 /*yield*/, _field.searchRequest(req, entityData, req.query.term, Number(req.query.page))];
                    case 8:
                        response = _a.sent();
                        return [2 /*return*/, {
                                data: response[0].map(function (b) {
                                    return { id: b.key, text: b.value };
                                }),
                                pagination: response[1],
                            }];
                }
            });
        });
    };
    /**
     * Retrieve entity data to dynamically display results
     * @param entityName the name of the entity
     * @param id the id of the editing entity
     * @param field the name of the field that is edited
     * @param selection the current selection for the field
     * @param req the current Lynx request
     */
    BaseUIController.prototype.performAjaxDetails = function (entityName, id, field, selection, req) {
        return __awaiter(this, void 0, void 0, function () {
            var entityData, metadata, _field, _meta, data, cleaned, key;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 1:
                        entityData = _a.sent();
                        if (!entityData) {
                            throw this.error(404, 'not found');
                        }
                        metadata = this.retrieveMetadata(entityName);
                        return [4 /*yield*/, this.generateContextMetadata(metadata, req)];
                    case 2:
                        metadata = _a.sent();
                        _field = metadata.fields[field];
                        if (!_field) {
                            throw this.error(500, 'field not found');
                        }
                        _meta = this.retrieveMetadata(_field.selfType);
                        return [4 /*yield*/, this.generateContextMetadata(_meta, req)];
                    case 3:
                        _meta = _a.sent();
                        return [4 /*yield*/, this.retrieveEntity(_field.selfType, selection)];
                    case 4:
                        data = _a.sent();
                        if (!data) {
                            throw this.error(404, 'not found');
                        }
                        return [4 /*yield*/, this.cleanData(req, data, _meta, false)];
                    case 5:
                        cleaned = _a.sent();
                        for (key in cleaned) {
                            if (cleaned[key] instanceof datagrid_1.default) {
                                this.logger.log('WARNING: currently not supporting Datagrid data with ExpandedAndSelection type...');
                                delete cleaned[key];
                            }
                        }
                        return [2 /*return*/, cleaned];
                }
            });
        });
    };
    /**
     * Delete the specified entity.
     * @param entityName The name of the entity class
     * @param id  The id of the entity
     * @param req The current Lynx request
     */
    BaseUIController.prototype.performEntityDelete = function (entityName, id, req) {
        return __awaiter(this, void 0, void 0, function () {
            var entityData, e_2, msg;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 1:
                        entityData = _a.sent();
                        if (!entityData) {
                            throw this.error(404, 'not found');
                        }
                        _a.label = 2;
                    case 2:
                        _a.trys.push([2, 4, , 5]);
                        return [4 /*yield*/, entityData.remove()];
                    case 3:
                        _a.sent();
                        return [3 /*break*/, 5];
                    case 4:
                        e_2 = _a.sent();
                        this.logger.error(e_2);
                        msg = this.tr('admin-ui.unable-delete', req);
                        this.addErrorMessage(sprintf_js_1.sprintf(msg, entityData.getLabel()), req);
                        return [3 /*break*/, 5];
                    case 5:
                        if (req.query.redirect) {
                            return [2 /*return*/, this.redirect(req.query.redirect)];
                        }
                        return [2 /*return*/, this.redirect('adminUI.list', { entityName: entityName })];
                }
            });
        });
    };
    /**
     * Delete the specified entities.
     * @param entityName The name of the entity class
     * @param req The current Lynx request, containing the query parameter ids, with an array of id
     */
    BaseUIController.prototype.performEntityDeleteMultiple = function (entityName, req) {
        return __awaiter(this, void 0, void 0, function () {
            var ids, _i, ids_1, id, entityData, e_3, msg;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        ids = JSON.parse(req.query.ids);
                        _i = 0, ids_1 = ids;
                        _a.label = 1;
                    case 1:
                        if (!(_i < ids_1.length)) return [3 /*break*/, 7];
                        id = ids_1[_i];
                        return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 2:
                        entityData = _a.sent();
                        if (!entityData) {
                            throw this.error(404, 'not found');
                        }
                        _a.label = 3;
                    case 3:
                        _a.trys.push([3, 5, , 6]);
                        return [4 /*yield*/, entityData.remove()];
                    case 4:
                        _a.sent();
                        return [3 /*break*/, 6];
                    case 5:
                        e_3 = _a.sent();
                        this.logger.error(e_3);
                        msg = this.tr('admin-ui.unable-delete', req);
                        this.addErrorMessage(sprintf_js_1.sprintf(msg, entityData.getLabel()), req);
                        return [3 /*break*/, 6];
                    case 6:
                        _i++;
                        return [3 /*break*/, 1];
                    case 7:
                        if (req.query.redirect) {
                            return [2 /*return*/, this.redirect(req.query.redirect)];
                        }
                        return [2 /*return*/, this.redirect('adminUI.list', { entityName: entityName })];
                }
            });
        });
    };
    /**
     * Retrieve and display the list of a specified entity
     * @param entityName The name of the entity class
     * @param req The current Lynx request
     */
    BaseUIController.prototype.retrieveEntityList = function (entityName, req) {
        return __awaiter(this, void 0, void 0, function () {
            var metadata, datagrid, fields, hasSmartSearchable, key, field, data, k, tmp, u, _i, tmp_1, t, ctx;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        metadata = this.retrieveMetadata(entityName);
                        if (!metadata) {
                            throw this.error(404, 'Not found');
                        }
                        datagrid = new datagrid_1.default('', req);
                        return [4 /*yield*/, this.retrieveList(req, entityName, datagrid)];
                    case 1:
                        _a.sent();
                        return [4 /*yield*/, this.generateContextMetadata(metadata, req)];
                    case 2:
                        metadata = _a.sent();
                        return [4 /*yield*/, this.generateContextFields(metadata, req, {})];
                    case 3:
                        fields = _a.sent();
                        hasSmartSearchable = false;
                        for (key in fields) {
                            field = fields[key];
                            if (field.smartSearchable || field.searchable) {
                                field.readOnly = false;
                                field.required = false;
                            }
                            if (field.smartSearchable) {
                                hasSmartSearchable = true;
                            }
                        }
                        data = {};
                        for (k in req.query) {
                            tmp = req.query[k];
                            if (tmp instanceof Array) {
                                u = [];
                                for (_i = 0, tmp_1 = tmp; _i < tmp_1.length; _i++) {
                                    t = tmp_1[_i];
                                    try {
                                        u.push(parseInt(t));
                                    }
                                    catch (e) {
                                        u.push(t);
                                    }
                                }
                                tmp = u;
                            }
                            data[k] = tmp;
                        }
                        ctx = {
                            metadata: metadata,
                            configuration: _1.default.configuration,
                            parentTemplate: metadata.classParameters.listParentTemplate,
                            gridData: datagrid,
                            data: data,
                            fields: fields,
                            hasSmartSearchable: hasSmartSearchable,
                        };
                        return [2 /*return*/, this.render(metadata.classParameters.listTemplate, req, ctx)];
                }
            });
        });
    };
    BaseUIController.prototype.generateCxtForEditingRender = function (data, isPopup, metadata, fields) {
        var _a, _b, _c, _d, _e, _f;
        var usedTypes = [];
        for (var key in fields) {
            if (usedTypes.indexOf(fields[key].type) == -1) {
                usedTypes.push(fields[key].type);
            }
        }
        var ctx = {
            data: data,
            configuration: _1.default.configuration,
            parentTemplate: isPopup
                ? metadata.classParameters.popupEditorParentTemplate
                : metadata.classParameters.editorParentTemplate,
            tabs: (_a = metadata.classParameters.uiSettings) === null || _a === void 0 ? void 0 : _a.tabs,
            defaultTab: (_b = metadata.classParameters.uiSettings) === null || _b === void 0 ? void 0 : _b.defaultTab,
            tabsAsSections: (_c = metadata.classParameters.uiSettings) === null || _c === void 0 ? void 0 : _c.tabsAsSections,
            hideTabsInExpanded: (_d = metadata.classParameters.uiSettings) === null || _d === void 0 ? void 0 : _d.hideTabsInExpanded,
            hideTabsInModal: (_e = metadata.classParameters.uiSettings) === null || _e === void 0 ? void 0 : _e.hideTabsInModal,
            hasRightColumn: (_f = metadata.classParameters.uiSettings) === null || _f === void 0 ? void 0 : _f.hasRightColumn,
            nested: false,
            metadata: metadata,
            fields: fields,
            usedTypes: usedTypes,
        };
        return ctx;
    };
    /**
     * Retrieve the details of a specific entity by its id
     * @param entityName The name of the entity class
     * @param id The id of the entity to retrieve
     * @param req The current Lynx request
     */
    BaseUIController.prototype.retrieveEntityDetails = function (entityName, id, req) {
        return __awaiter(this, void 0, void 0, function () {
            var entityData, metadata, _a, fields, data, usedTypes, key, isPopup, ctx;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 1:
                        entityData = _b.sent();
                        if (!entityData) {
                            throw this.error(404, 'not found');
                        }
                        metadata = this.retrieveMetadata(entityName);
                        _a = [{}];
                        return [4 /*yield*/, this.generateContextMetadata(metadata, req)];
                    case 2:
                        metadata = __assign.apply(void 0, _a.concat([(_b.sent())]));
                        return [4 /*yield*/, this.generateContextFields(metadata, req, entityData)];
                    case 3:
                        fields = _b.sent();
                        metadata.fields = fields;
                        return [4 /*yield*/, this.cleanData(req, entityData, metadata)];
                    case 4:
                        data = _b.sent();
                        usedTypes = [];
                        for (key in fields) {
                            if (usedTypes.indexOf(fields[key].type) == -1) {
                                usedTypes.push(fields[key].type);
                            }
                        }
                        isPopup = req.query.popup;
                        ctx = this.generateCxtForEditingRender(data, isPopup, metadata, fields);
                        return [2 /*return*/, this.render(isPopup
                                ? metadata.classParameters.popupEditorTemplate
                                : metadata.classParameters.editorTemplate, req, ctx)];
                }
            });
        });
    };
    /**
     * Retrieve the nested view of an entity
     * @param entityName The name of the entity class
     * @param id The id of the entity to retrieve
     * @param nestedKey The name of the property of the entity to display
     * @param req The current Lynx request
     * @param enableDelete Determines if the delete action is enabled
     */
    BaseUIController.prototype.retrieveNestedView = function (entityName, id, nestedKey, req, enableDelete) {
        if (enableDelete === void 0) { enableDelete = false; }
        return __awaiter(this, void 0, void 0, function () {
            var entityData, metadata, nestedField, entityData_1, e_4, data, ctx, _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 1:
                        entityData = _b.sent();
                        if (!entityData) {
                            throw this.error(404, 'not found');
                        }
                        metadata = __assign({}, this.retrieveMetadata(entityName));
                        return [4 /*yield*/, this.generateContextMetadata(metadata, req)];
                    case 2:
                        metadata = _b.sent();
                        nestedField = metadata.fields[nestedKey];
                        metadata.fields = {};
                        metadata.fields[nestedKey] = nestedField;
                        if (!(enableDelete && req.query.remove)) return [3 /*break*/, 7];
                        return [4 /*yield*/, this.retrieveEntity(nestedField.selfType, req.query.remove)];
                    case 3:
                        entityData_1 = _b.sent();
                        if (!entityData_1) {
                            throw this.error(404, 'not found');
                        }
                        _b.label = 4;
                    case 4:
                        _b.trys.push([4, 6, , 7]);
                        return [4 /*yield*/, entityData_1.remove()];
                    case 5:
                        _b.sent();
                        return [3 /*break*/, 7];
                    case 6:
                        e_4 = _b.sent();
                        this.logger.error(e_4);
                        this.addErrorMessage('Unable to delete ' +
                            entityData_1.getLabel() +
                            '. Please check its dependencies.', req);
                        return [3 /*break*/, 7];
                    case 7: return [4 /*yield*/, this.cleanData(req, entityData, metadata)];
                    case 8:
                        data = _b.sent();
                        _a = {
                            data: data,
                            configuration: _1.default.configuration,
                            parentTemplate: _1.default.nestedParentTemplatePath,
                            nested: true,
                            metadata: metadata
                        };
                        return [4 /*yield*/, this.generateContextFields(metadata, req, entityData)];
                    case 9:
                        ctx = (_a.fields = _b.sent(),
                            _a);
                        return [2 /*return*/, this.render(_1.default.nestedTemplatePath, req, ctx)];
                }
            });
        });
    };
    /**
     * Perform the edit of a specific entity
     * @param entityName The name of the entity class
     * @param id The id of the entity to edit
     * @param req The current Lynx request
     */
    BaseUIController.prototype.performEntityEdit = function (entityName, id, req) {
        return __awaiter(this, void 0, void 0, function () {
            var metadata, entity, _a, _b, updated, e_5, errorField, field, _c, isPopup, fields, ctx;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        metadata = this.retrieveMetadata(entityName);
                        if (!metadata) {
                            throw this.error(404, 'not found');
                        }
                        if (!(!id || id == '0')) return [3 /*break*/, 1];
                        entity = new (this.retrieveEntityClass(entityName))();
                        return [3 /*break*/, 3];
                    case 1: return [4 /*yield*/, this.retrieveEntity(entityName, id)];
                    case 2:
                        entity = (_d.sent());
                        if (!entity) {
                            throw this.error(404, 'not found');
                        }
                        _d.label = 3;
                    case 3:
                        _a = [__assign({}, metadata)];
                        _b = {};
                        return [4 /*yield*/, this.generateContextFields(metadata, req, entity)];
                    case 4:
                        metadata = __assign.apply(void 0, _a.concat([(_b.fields = _d.sent(), _b)]));
                        return [4 /*yield*/, this.setData(req, entity, req.body, metadata)];
                    case 5:
                        _d.sent();
                        _d.label = 6;
                    case 6:
                        _d.trys.push([6, 8, , 11]);
                        return [4 /*yield*/, controller_1.Controller.saveEntity(entity, req)];
                    case 7:
                        updated = _d.sent();
                        return [3 /*break*/, 11];
                    case 8:
                        e_5 = _d.sent();
                        this.logger.log('error saving the entity', e_5);
                        try {
                            errorField = /'([a-zA-Z0-0_)]+)'/.exec(e_5.message)[1];
                            field = metadata.fields[errorField];
                            if (field) {
                                this.addErrorMessage(this.app.translate('admin-ui.error-on-field', req) +
                                    this.app.translate(field.name, req), req);
                            }
                            else {
                                this.addErrorMessage(e_5.message, req);
                            }
                        }
                        catch (ee) {
                            this.logger.error(e_5);
                            this.logger.error(ee);
                            this.addErrorMessage(e_5.message, req);
                        }
                        _c = [{}];
                        return [4 /*yield*/, this.generateContextMetadata(metadata, req)];
                    case 9:
                        metadata = __assign.apply(void 0, _c.concat([(_d.sent())]));
                        isPopup = req.query.popup;
                        return [4 /*yield*/, this.generateContextFields(metadata, req, entity)];
                    case 10:
                        fields = _d.sent();
                        metadata.fields = fields;
                        ctx = this.generateCxtForEditingRender(req.body, isPopup, metadata, fields);
                        /*let ctx = {
                            data: req.body,
                            configuration: AdminUIModule.configuration,
                            parentTemplate: isPopup
                                ? metadata.classParameters.popupEditorParentTemplate
                                : metadata.classParameters.editorParentTemplate,
                            nested: false,
                            metadata: metadata,
                            fields: await this.generateContextFields(metadata, req, entity),
                        } as any;*/
                        return [2 /*return*/, this.render(isPopup
                                ? metadata.classParameters.popupEditorTemplate
                                : metadata.classParameters.editorTemplate, req, ctx)];
                    case 11:
                        if (id == 0) {
                            this.addSuccessMessage('admin-ui.success-create', req);
                        }
                        else {
                            this.addSuccessMessage('admin-ui.success-update', req);
                        }
                        return [2 /*return*/, this.redirect('adminUI.details', {
                                entityName: entityName,
                                id: updated.id,
                            })];
                }
            });
        });
    };
    return BaseUIController;
}(controller_1.Controller));
exports.BaseUIController = BaseUIController;
