"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const React = __importStar(require("react"));
const PropTypes = __importStar(require("prop-types"));
const utils_1 = require("../../utils");
const LajiForm_1 = __importDefault(require("../LajiForm"));
const Context_1 = __importDefault(require("../../Context"));
const ReactContext_1 = __importDefault(require("../../ReactContext"));
const components_1 = require("../components");
const react_spinner_1 = __importDefault(require("react-spinner"));
const utils_2 = require("@luomus/laji-map/lib/utils");
const memoizee_1 = __importDefault(require("memoizee"));
class AnnotationField extends React.Component {
    constructor() {
        super(...arguments);
        this.state = { show: false };
        this.getButton = () => {
            const annotations = this.getAnnotations();
            return {
                glyph: "comment",
                tooltip: this.props.formContext.translations.ShowAnnotations,
                tooltipPlacement: "left",
                fn: this.onClick,
                variant: annotations && annotations.length ? "primary" : "default"
            };
        };
        this.onClick = (0, memoizee_1.default)(() => () => {
            this.setState({ show: !this.state.show });
        });
        this.onHide = () => {
            this.setState({ show: false });
        };
        this.getAnnotations = () => {
            const { annotations = {} } = this.props.formContext.uiSchemaContext;
            const { id } = this.props.formData;
            return (0, Context_1.default)(`${this.props.formContext.contextId}_ANNOTATIONS`)[id] || annotations[id];
        };
    }
    render() {
        const { adminOnly, container, add, filter, uiSchema: annotationUiSchema, buttonsPath = "/", formId } = (0, utils_1.getUiOptions)(this.props.uiSchema);
        const innerUiSchema = (0, utils_1.getInnerUiSchema)(this.props.uiSchema);
        let uiSchema = adminOnly && !this.props.formContext.uiSchemaContext.isAdmin
            || !this.props.formContext.uiSchemaContext.isEdit
            || !this.props.formData.id
            ? innerUiSchema
            : (0, utils_1.injectButtons)(innerUiSchema, [this.getButton()], buttonsPath);
        let Container = undefined;
        const { Modal } = this.context.theme;
        switch (container) {
            case "modal":
                Container = ({ children }) => {
                    return (React.createElement(Modal, { show: true, dialogClassName: "laji-form", onHide: this.onHide },
                        React.createElement(Modal.Header, { closeButton: true }),
                        React.createElement(Modal.Body, null, children)));
                };
                break;
            default:
                Container = ({ children }) => React.createElement("div", null, children);
        }
        const { SchemaField } = this.props.registry.fields;
        return (React.createElement("div", null,
            React.createElement(SchemaField, Object.assign({}, this.props, { uiSchema: uiSchema })),
            (this.props.formData.id && (container !== "modal" || this.state.show)) &&
                React.createElement(Container, null,
                    React.createElement(AnnotationBox, { id: this.props.formData.id, annotations: this.getAnnotations(), lang: this.props.formContext.lang, formContext: this.props.formContext, add: add, uiSchema: annotationUiSchema, filter: filter, formId: formId }))));
    }
}
AnnotationField.contextType = ReactContext_1.default;
AnnotationField.propTypes = {
    uiSchema: PropTypes.shape({
        "ui:options": PropTypes.shape({
            adminOnly: PropTypes.bool,
            container: PropTypes.oneOf(["modal"]),
            add: PropTypes.object,
            filter: PropTypes.object,
            uiSchema: PropTypes.object,
            buttonsPath: PropTypes.string,
            formId: PropTypes.string
        }),
        uiSchema: PropTypes.object
    }).isRequired,
    schema: PropTypes.shape({
        type: PropTypes.oneOf(["object"])
    }).isRequired,
    formData: PropTypes.object.isRequired
};
exports.default = AnnotationField;
(0, Context_1.default)("SCHEMA_FIELD_WRAPPERS").AnnotationField = true;
class AnnotationBox extends React.Component {
    constructor(props) {
        super(props);
        this.onAnnotationSubmit = (_a) => __awaiter(this, [_a], void 0, function* ({ formData }) {
            const { type } = this.getAddOptions();
            const rootID = this.props.formContext.services.rootInstance.getFormData().id;
            this.props.formContext.services.blocker.push();
            const body = Object.assign(Object.assign({}, formData), { targetID: this.props.id, rootID, type, byRole: "MMAN.formAdmin" });
            try {
                const annotation = yield this.props.formContext.apiClient.post("/annotations", undefined, body);
                this.props.formContext.services.blocker.pop();
                const annotationContext = (0, Context_1.default)(`${this.props.formContext.contextId}_ANNOTATIONS`);
                const annotations = [annotation];
                annotationContext[this.props.id] = annotations;
                this.setState({ annotations: annotations, fail: false });
            }
            catch (e) {
                this.props.formContext.services.blocker.pop();
                this.setState({ fail: true });
            }
        });
        this.onAnnotationChange = (formData) => {
            let state = {};
            if (this.state.fail !== undefined) {
                state.fail = undefined;
            }
            const { submitOnChange } = this.getAddOptions();
            if (submitOnChange) {
                this.onAnnotationSubmit({ formData });
            }
            state.addFormData = formData;
            this.setState(state);
        };
        this.onAnnotationSubmitClick = () => {
            this.onAnnotationSubmit({ formData: this.state.addFormData });
        };
        this.getAddOptions = () => {
            const { add, formContext: { uiSchemaContext: { isAdmin } } } = this.props;
            let addOptions = (0, utils_2.isObject)(add) ? add : {};
            const submitOnChange = "submitOnChange" in addOptions ? addOptions.submitOnChange : false;
            const type = isAdmin ? "MAN.typeAdmin" : addOptions.type;
            return Object.assign(Object.assign({}, addOptions), { submitOnChange, type });
        };
        this.renderAdd = () => {
            const { formContext, add } = this.props;
            const { lang, translations } = formContext;
            const { metadataForm } = this.state;
            const { Alert } = this.context.theme;
            if (!metadataForm) {
                return null;
            }
            const _uiSchema = this.getUiSchema();
            let addSchema = undefined;
            let addUiSchema = undefined;
            let submitOnChange = undefined;
            let addFormData = undefined;
            if (add && metadataForm && metadataForm.schema) {
                const { adminOnly, filter: _filter, uiSchema: _addUiSchema, submitOnChange: _submitOnChange, formData } = this.getAddOptions();
                if (adminOnly && !formContext.uiSchemaContext.isAdmin) {
                    return null;
                }
                let propArray = Object.keys(metadataForm.schema.properties);
                propArray = (0, utils_1.filter)(propArray, ["created", "annotationByPerson"], "blacklist");
                if (_filter)
                    propArray = (0, utils_1.filter)(propArray, _filter.filter, _filter.filterType);
                const addSchemaProperties = propArray.reduce((properties, prop) => {
                    properties[prop] = metadataForm.schema.properties[prop];
                    return properties;
                }, {});
                addSchema = Object.assign(Object.assign({}, metadataForm.schema), { properties: addSchemaProperties });
                addUiSchema = _addUiSchema || Object.assign(Object.assign({}, _uiSchema), { "ui:readonly": false });
                submitOnChange = _submitOnChange;
                addFormData = this.state.addFormData || (formData
                    ? (0, utils_1.getDefaultFormState)(addSchema, formData)
                    : undefined);
            }
            const renderSubmit = !submitOnChange;
            return add && addSchema ? (React.createElement(LajiForm_1.default, Object.assign({}, metadataForm, { schema: addSchema, uiSchema: addUiSchema || _uiSchema, onSubmit: this.onAnnotationSubmit, onChange: this.onAnnotationChange, renderSubmit: renderSubmit, formData: addFormData, lang: lang, apiClient: this.props.formContext.apiClient.apiClient, uiSchemaContext: this.props.formContext.uiSchemaContext }), React.createElement("div", null,
                this.state.fail !== undefined &&
                    React.createElement(Alert, { variant: this.state.fail ? "danger" : "success" }, translations[this.state.fail ? "SaveFail" : "SaveSuccess"]),
                renderSubmit && React.createElement(components_1.Button, { id: "submit", type: "submit", onClick: this.onAnnotationSubmitClick }, translations.Submit)))) : null;
        };
        this.getUiSchema = () => {
            const { uiSchema } = this.props;
            const metadataForm = this.state.metadataForm || {};
            return uiSchema || Object.assign(Object.assign({}, (metadataForm.uiSchema || {})), { "ui:shortcuts": Object.assign(Object.assign({}, ((metadataForm.uiSchema || {})["ui:shorcuts"] || {})), (this.props.formContext.services.keyHandler.shortcuts)), "ui:showShortcutsButton": false });
        };
        this.onDelete = (id) => () => __awaiter(this, void 0, void 0, function* () {
            try {
                yield this.props.formContext.apiClient.delete("/annotations/{id}", { path: { id } });
                const annotationContext = (0, Context_1.default)(`${this.props.formContext.contextId}_ANNOTATIONS`);
                const annotations = this.state.annotations.filter(({ id: _id }) => _id !== id);
                annotationContext[this.props.id] = annotations;
                this.setState({ deleteFail: false, annotations });
            }
            catch (e) {
                this.setState({ deleteFail: true });
            }
        });
        this.state = { annotations: props.annotations || [] };
    }
    componentDidMount() {
        this.mounted = true;
        this.props.formContext.apiClient.get("/forms/{id}", { path: { id: this.props.formId }, query: { format: "schema" } })
            .then(metadataForm => {
            if (!this.mounted)
                return;
            const { filter: _filter } = this.props;
            let propArray = Object.keys(metadataForm.schema.properties);
            if (_filter)
                propArray = (0, utils_1.filter)(propArray, _filter.filter, _filter.filterType);
            const schemaProperties = propArray.reduce((properties, prop) => {
                properties[prop] = metadataForm.schema.properties[prop];
                return properties;
            }, {});
            const schema = Object.assign(Object.assign({}, metadataForm.schema), { properties: schemaProperties });
            this.setState({ metadataForm: Object.assign(Object.assign({}, metadataForm), { schema }) });
        });
    }
    componentWillUnmount() {
        this.mounted = false;
    }
    render() {
        const { formContext: { translations, lang, apiClient } } = this.props;
        const { metadataForm = {}, annotations = [] } = this.state;
        const _uiSchema = Object.assign(Object.assign({}, this.getUiSchema()), { "ui:readonly": true });
        const { Panel, ListGroup, ListGroupItem, Alert } = this.context.theme;
        return (React.createElement(Panel, null,
            React.createElement(Panel.Heading, null,
                React.createElement("strong", null, translations.Comments)),
            React.createElement(Panel.Body, null,
                this.renderAdd(),
                React.createElement(ListGroup, null, this.state.metadataForm ? annotations.slice(0).reverse().map((annotation, idx) => React.createElement(ListGroupItem, { key: idx, className: `annotation-list${idx % 2 === 0 ? "" : "-odd"}` },
                    React.createElement("div", null,
                        React.createElement(LajiForm_1.default, Object.assign({}, metadataForm, { uiSchema: _uiSchema, lang: lang, formData: annotation, renderSubmit: false, apiClient: apiClient.apiClient, uiSchemaContext: this.props.formContext.uiSchemaContext }))))) : React.createElement(react_spinner_1.default, null)),
                this.state.deleteFail &&
                    React.createElement(Alert, { variant: "danger" }, translations["DeleteFail"]))));
    }
}
AnnotationBox.contextType = ReactContext_1.default;
AnnotationBox.defaultProps = {
    formId: "MHL.15"
};
