"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 ReactContext_1 = __importDefault(require("../../../ReactContext"));
const utils_1 = require("../../../utils");
const Context_1 = __importDefault(require("../../../Context"));
const NamedPlaceChooser_1 = require("./NamedPlaceChooser");
const PLACE_WHITELIST = [
    "geometry",
    "country",
    "administrativeProvince",
    "biologicalProvince",
    "municipality",
    "locality",
    "localityDescription",
    "habitat",
    "habitatDescription"
];
const PLACES_FETCH_FAIL = "PLACES_FETCH_FAIL";
const PLACE_USE_FAIL = "PLACE_USE_FAIL";
const PLACE_DELETE_FAIL = "PLACE_DELETE_FAIL";
/** Compatible only with gatherings array and gathering object */
class NamedPlaceChooserField extends React.Component {
    constructor() {
        super(...arguments);
        this.mounted = false;
        this.state = {};
        this.getUiSchema = (props, buttonDefinition) => {
            if (buttonDefinition) {
                buttonDefinition = Object.assign(Object.assign({}, buttonDefinition), { label: props.formContext.translations.ChooseFromNamedPlace });
                const innerUiSchema = (0, utils_1.getInnerUiSchema)(props.uiSchema);
                const options = (0, utils_1.getUiOptions)(innerUiSchema);
                return Object.assign(Object.assign({}, innerUiSchema), { "ui:options": Object.assign(Object.assign({}, options), { buttons: [
                            buttonDefinition,
                            ...(options.buttons || [])
                        ] }) });
            }
            else {
                return (0, utils_1.getInnerUiSchema)(props.uiSchema);
            }
        };
        this.isGatheringsArray = (schema) => schema.type === "array";
        this.onPlaceSelected = (place) => {
            const getGathering = (schema) => {
                let gathering = (0, utils_1.getDefaultFormState)(schema);
                const placeGathering = place.prepopulatedDocument.gatherings[0];
                PLACE_WHITELIST.forEach(prop => {
                    if (prop in placeGathering && prop in schema.properties) {
                        gathering[prop] = placeGathering[prop];
                    }
                });
                gathering.namedPlaceID = place.id;
                const tmpIdTree = this.props.formContext.services.ids.getRelativeTmpIdTree(this.props.idSchema.$id);
                const [withLajiFormIds] = (0, utils_1.addLajiFormIds)(gathering, tmpIdTree, false);
                return withLajiFormIds;
            };
            try {
                let targetId, gathering, newFormData, zoomToData;
                const { schema } = this.props;
                if (this.isGatheringsArray(schema)) {
                    gathering = getGathering(schema.items);
                    newFormData = [
                        ...(this.props.formData || []),
                        gathering
                    ];
                    this.setState({ show: false });
                    targetId = this.props.idSchema.$id;
                    this.props.formContext.services.customEvents.send(targetId, "activeIdx", (this.props.formData || []).length);
                }
                else { // gathering object
                    gathering = getGathering(schema);
                    gathering.namedPlaceID = place.id;
                    newFormData = Object.assign(Object.assign({}, this.props.formData), gathering);
                    this.setState({ show: false });
                    const splits = this.props.idSchema.$id.split("_");
                    splits.pop();
                    targetId = splits.join("_");
                    zoomToData = true;
                }
                this.props.onChange(newFormData);
                if (zoomToData)
                    this.props.formContext.services.customEvents.send(targetId, "zoomToData", undefined);
            }
            catch (e) {
                this.setState({ failed: PLACE_USE_FAIL });
            }
        };
        this.onPlaceDeleted = (place, end) => __awaiter(this, void 0, void 0, function* () {
            try {
                yield this.props.formContext.apiClient.delete("/named-places/{id}", { path: { id: place.id } });
                end();
            }
            catch (e) {
                this.setState({ failed: PLACE_DELETE_FAIL });
                this.props.formContext.notifier.error(this.props.formContext.translations.PlaceRemovalFailed);
                end();
            }
        });
        this.onButtonClick = () => () => {
            this.setState({ show: true });
        };
        this.updatePlaces = (response) => {
            var _a;
            if (!this.mounted)
                return;
            const state = { places: response.results.sort((a, b) => {
                    if (a.name < b.name)
                        return -1;
                    if (a.name > b.name)
                        return 1;
                    return 0;
                }) };
            if (!((_a = response.results) === null || _a === void 0 ? void 0 : _a.length)) {
                return;
            }
            const buttonDefinition = {
                fn: this.onButtonClick,
                fnName: "addNamedPlace",
                glyph: "map-marker",
                label: this.props.formContext.translations.ChooseFromNamedPlace,
                id: this.props.idSchema.$id,
                changesFormData: true,
                variant: "primary"
            };
            if (this.isGatheringsArray(this.props.schema)) {
                buttonDefinition.rules = { canAdd: true };
            }
            else {
                buttonDefinition.position = "top";
            }
            state.buttonDefinition = buttonDefinition;
            this.setState(state);
        };
        this.onHide = () => this.setState({ show: false });
    }
    componentDidMount() {
        this.mounted = true;
        this.getNamedPlacesUnsubscribe = this.props.formContext.apiClient.subscribe("/named-places", { query: { includePublic: false, pageSize: 100000 } }, this.updatePlaces, () => this.setState({ failed: PLACES_FETCH_FAIL }), 1000);
    }
    componentWillUnmount() {
        this.mounted = false;
        this.getNamedPlacesUnsubscribe();
    }
    render() {
        const { registry: { fields: { SchemaField } }, formContext } = this.props;
        const { translations } = formContext;
        const { failed } = this.state;
        const { Modal, Alert } = this.context.theme;
        return React.createElement(React.Fragment, null,
            React.createElement(SchemaField, Object.assign({}, this.props, { uiSchema: this.getUiSchema(this.props, this.state.buttonDefinition) })),
            this.state.places && this.state.show ? (React.createElement(Modal, { dialogClassName: "laji-form map-dialog named-place-chooser-modal", show: true, onHide: this.onHide },
                React.createElement(Modal.Header, { closeButton: true }, translations.ChooseNamedPlace),
                React.createElement(Modal.Body, null,
                    failed === PLACE_USE_FAIL && React.createElement(Alert, { variant: "danger" }, translations.NamedPlacesUseFail),
                    failed === PLACES_FETCH_FAIL && React.createElement(Alert, { variant: "danger" }, translations.NamedPlacesFetchFail),
                    React.createElement(NamedPlaceChooser_1.NamedPlaceChooser, { places: this.state.places, failed: failed === PLACES_FETCH_FAIL ? true : false, formContext: formContext, onSelected: this.onPlaceSelected, onDeleted: this.onPlaceDeleted })))) : null);
    }
}
NamedPlaceChooserField.contextType = ReactContext_1.default;
exports.default = NamedPlaceChooserField;
(0, Context_1.default)("SCHEMA_FIELD_WRAPPERS").NamedPlaceChooserField = true;
