"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HubProject = void 0;
const defaults_1 = require("./defaults");
const Catalog_1 = require("../search/Catalog");
const HubItemEntity_1 = require("../core/HubItemEntity");
const getEditorConfig_1 = require("../core/schemas/getEditorConfig");
// NOTE: this could be lazy-loaded just like the CUD functions
const fetch_1 = require("./fetch");
const getEntityMetrics_1 = require("../metrics/getEntityMetrics");
const resolveMetric_1 = require("../metrics/resolveMetric");
const view_1 = require("./view");
const util_1 = require("../util");
const edit_1 = require("./edit");
const enrichEntity_1 = require("../core/enrichEntity");
const set_prop_1 = require("../objects/set-prop");
const get_with_default_1 = require("../objects/get-with-default");
const metricToEditor_1 = require("../metrics/metricToEditor");
const getEditorSlug_1 = require("../core/_internal/getEditorSlug");
const hubItemEntityFromEditor_1 = require("../core/_internal/hubItemEntityFromEditor");
/**
 * Hub Project Class
 */
class HubProject extends HubItemEntity_1.HubItemEntity {
    /**
     * Private constructor so we don't have `new` all over the place. Allows for
     * more flexibility in how we create the HubProjectManager over time.
     * @param context
     */
    constructor(project, context) {
        super(project, context);
        this._catalog = Catalog_1.Catalog.fromJson(project.catalog, this.context);
    }
    /**
     * Catalog instance for this project. Note: Do not hold direct references to this object; always access it from the project.
     * @returns
     */
    get catalog() {
        return this._catalog;
    }
    /**
     * Create an instance from an IHubProject object
     * @param json - JSON object to create a HubProject from
     * @param context - ArcGIS context
     * @returns
     */
    static fromJson(json, context) {
        // merge what we have with the default values
        const pojo = this.applyDefaults(json, context);
        return new HubProject(pojo, context);
    }
    /**
     * Create a new HubProject, returning a HubProject instance.
     * Note: This does not persist the Project into the backing store
     * @param partialProject
     * @param context
     * @returns
     */
    static async create(partialProject, context, save = false) {
        const pojo = this.applyDefaults(partialProject, context);
        // return an instance of HubProject
        const instance = HubProject.fromJson(pojo, context);
        if (save) {
            await instance.save();
        }
        return instance;
    }
    /**
     * Fetch a Project from the backing store and return a HubProject instance.
     * @param identifier - Identifier of the project to load
     * @param context
     * @returns
     */
    static async fetch(identifier, context) {
        // fetch the project by id or slug
        try {
            const project = await (0, fetch_1.fetchProject)(identifier, context.requestOptions);
            // create an instance of HubProject from the project
            return HubProject.fromJson(project, context);
        }
        catch (ex) {
            if (ex.message ===
                "CONT_0001: Item does not exist or is inaccessible.") {
                throw new Error(`Project not found.`);
            }
            else {
                throw ex;
            }
        }
    }
    /**
     * Given a partial project, apply defaults to it to ensure that a baseline of properties are set
     * @param partialProject
     * @param context
     * @returns
     */
    static applyDefaults(partialProject, context) {
        // ensure we have the orgUrlKey
        if (!partialProject.orgUrlKey) {
            partialProject.orgUrlKey = context.portal.urlKey;
        }
        // ensure orgUrlKey is lowercase
        partialProject.orgUrlKey = partialProject.orgUrlKey.toLowerCase();
        // extend the partial over the defaults
        const pojo = Object.assign(Object.assign({}, defaults_1.DEFAULT_PROJECT), partialProject);
        return pojo;
    }
    /**
     * Convert the project entity into a card view model that can
     * be consumed by the suite of hub gallery components
     *
     * @param opts view model options
     */
    convertToCardModel(opts) {
        return (0, view_1.projectToCardModel)(this.entity, this.context, opts);
    }
    /*
     * Get a specific editor config for the HubProject entity.
     * @param i18nScope translation scope to be interpolated into the uiSchema
     * @param type editor type - corresponds to the returned uiSchema
     * @param options optional hash of dynamic uiSchema element options
     */
    async getEditorConfig(i18nScope, type) {
        // delegate to the schema subsystem
        return (0, getEditorConfig_1.getEditorConfig)(i18nScope, type, this.entity, this.context);
    }
    /**
     * Return the project as an editor object
     * @param editorContext
     * @returns
     */
    async toEditor(editorContext = {}, include = []) {
        // 1. optionally enrich entity and cast to editor
        const editor = include.length
            ? (await (0, enrichEntity_1.enrichEntity)((0, util_1.cloneObject)(this.entity), include, this.context.hubRequestOptions))
            : (0, util_1.cloneObject)(this.entity);
        // 2. editor._groups handling
        editor._groups = [];
        // 3. handle metrics
        const metrics = (0, getEntityMetrics_1.getEntityMetrics)(this.entity);
        const metric = metrics.find((m) => m.id === editorContext.metricId);
        const displays = (0, get_with_default_1.getWithDefault)(this.entity, "view.metricDisplays", []);
        const displayConfig = displays.find((display) => display.metricId === editorContext.metricId) || {};
        editor._metric = (0, metricToEditor_1.metricToEditor)(metric, displayConfig);
        // 4. slug life
        editor._slug = (0, getEditorSlug_1.getEditorSlug)(this.entity);
        return editor;
    }
    /**
     * Convert editor values back into a HubProject entity,
     * performing any necessary pre-save operations/transforms.
     * @param editor - the editor object to convert
     * @param _editorContext - optional editor context
     */
    async fromEditor(editor, _editorContext) {
        // delegate to an item-specific fromEditor util to
        // handle shared "fromEditor" logic
        const res = await (0, hubItemEntityFromEditor_1.hubItemEntityFromEditor)(editor, this.context);
        // iterate over the res object keys and set the values
        // on the HubProject instance
        Object.entries(res).forEach(([key, value]) => {
            (0, set_prop_1.setProp)(key, value, this);
        });
        // save or create the entity
        await this.save();
        return this.entity;
    }
    /**
     * Apply a new state to the instance
     * @param changes
     */
    update(changes) {
        if (this.isDestroyed) {
            throw new Error("HubProject is already destroyed.");
        }
        // merge partial onto existing entity
        this.entity = Object.assign(Object.assign({}, this.entity), changes);
        // update internal instances
        if (changes.catalog) {
            this._catalog = Catalog_1.Catalog.fromJson(this.entity.catalog, this.context);
        }
    }
    /**
     * Save the HubProject to the backing store. Currently Projects are stored as Items in Portal
     * @returns
     */
    async save() {
        if (this.isDestroyed) {
            throw new Error("HubProject is already destroyed.");
        }
        // get the catalog, and permission configs
        this.entity.catalog = this._catalog.toJson();
        if (this.entity.id) {
            // update it
            this.entity = await (0, edit_1.updateProject)(this.entity, this.context.userRequestOptions);
        }
        else {
            // create it
            this.entity = await (0, edit_1.createProject)(this.entity, this.context.userRequestOptions);
        }
        // call the after save hook on superclass
        await super.afterSave();
        return;
    }
    /**
     * Delete the HubProject from the store
     * set a flag to indicate that it is destroyed
     * @returns
     */
    async delete() {
        if (this.isDestroyed) {
            throw new Error("HubProject is already destroyed.");
        }
        this.isDestroyed = true;
        // Delegate to module fn
        await (0, edit_1.deleteProject)(this.entity.id, this.context.userRequestOptions);
    }
    /**
     * Resolve a single metric for this metric
     * @param metricId
     * @returns
     */
    resolveMetric(metricId) {
        const metrics = (0, getEntityMetrics_1.getEntityMetrics)(this.entity);
        const metric = metrics.find((m) => m.id === metricId);
        // TODO: add caching
        if (metric) {
            return (0, resolveMetric_1.resolveMetric)(metric, this.context);
        }
        else {
            throw new Error(`Metric ${metricId} not found.`);
        }
    }
}
exports.HubProject = HubProject;
//# sourceMappingURL=HubProject.js.map