"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 __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
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 react_dom_1 = require("react-dom");
const PropTypes = __importStar(require("prop-types"));
const utils_1 = require("../../utils");
const components_1 = require("../components");
const Context_1 = __importDefault(require("../../Context"));
const ReactContext_1 = __importDefault(require("../../ReactContext"));
const react_spinner_1 = __importDefault(require("react-spinner"));
const MapArrayField_1 = require("./MapArrayField");
const memoizee_1 = __importDefault(require("memoizee"));
const SAVE = "SAVE", FETCH = "FETCH";
/**
 * Compatible only with gathering field.
 */
class NamedPlaceSaverField extends React.Component {
    constructor() {
        super(...arguments);
        this.state = { show: false };
        this.onButtonClick = () => () => {
            this.setState({ show: !this.state.show });
        };
        this.onSave = (place) => {
            this.setState({ show: false }, () => {
                this.props.onChange(Object.assign(Object.assign({}, (this.props.formData || {})), { namedPlaceID: place.id }));
            });
        };
        this.onHide = () => this.setState({ show: false });
    }
    getUiSchema(props) {
        const innerUiSchema = (0, utils_1.getInnerUiSchema)(props.uiSchema);
        const uiSchema = Object.assign(Object.assign({}, innerUiSchema), { "ui:options": Object.assign(Object.assign({}, (0, utils_1.getUiOptions)(innerUiSchema)), { buttons: [
                    ...((0, utils_1.getUiOptions)(innerUiSchema).buttons || []),
                    this.getButton(props)
                ] }) });
        return uiSchema;
    }
    getButton(props) {
        return {
            label: props.formContext.translations.SaveNamedPlace,
            fn: this.onButtonClick,
            glyph: "floppy-disk",
            position: "top",
            disabled: !(0, MapArrayField_1.parseGeometries)((props.formData || {}).geometry).length
        };
    }
    render() {
        const { registry: { fields: { SchemaField } }, formContext } = this.props;
        const { Modal } = this.context.theme;
        const uiSchema = this.getUiSchema(this.props);
        return (React.createElement("div", null,
            React.createElement(SchemaField, Object.assign({}, this.props, { uiSchema: uiSchema })),
            this.state && this.state.show
                ? (React.createElement(Modal, { dialogClassName: "laji-form", show: true, onHide: this.onHide },
                    React.createElement(Modal.Header, null,
                        React.createElement(Modal.Title, null, formContext.translations.NamedPlaces)),
                    React.createElement(Modal.Body, null,
                        React.createElement(PlaceSaverDialog, { formContext: formContext, onSave: this.onSave, gathering: this.props.formData || {} })))) : null));
    }
}
NamedPlaceSaverField.contextType = ReactContext_1.default;
NamedPlaceSaverField.propTypes = {
    schema: PropTypes.shape({
        type: PropTypes.oneOf(["object"])
    }).isRequired,
    formData: PropTypes.object
};
exports.default = NamedPlaceSaverField;
class PlaceSaverDialog extends React.Component {
    constructor(props) {
        super(props);
        this.onInputChange = ({ target: { value } }) => {
            this.setState({ value });
        };
        this.getGathering = () => {
            return ["geometry", "country", "administrativeProvince", "biologicalProvince", "municipality", "locality", "localityDescription", "habitat", "habitatDescription", "coordinateRadius"].reduce((gathering, key) => {
                gathering[key] = this.props.gathering[key];
                return gathering;
            }, {});
        };
        this.onSaveNew = (e) => {
            e.preventDefault();
            const _a = this.getGathering(), { namedPlaceID } = _a, gathering = __rest(_a, ["namedPlaceID"]);
            this.onSave({
                name: this.state.value,
                prepopulatedDocument: { gatherings: [gathering] }
            });
        };
        this.onOverwriteCurrentFor = (0, memoizee_1.default)((namedPlaceID) => () => {
            const gathering = this.getGathering();
            this.onSave(Object.assign(Object.assign({}, this.state.placeIdsToPlaces[namedPlaceID]), { name: this.state.value, prepopulatedDocument: { gatherings: [gathering] } }));
        });
        this.onOverwriteSelected = (0, memoizee_1.default)((place) => () => {
            const gathering = this.getGathering();
            this.onSave(Object.assign(Object.assign({}, place), { name: this.state.value, prepopulatedDocument: { gatherings: [gathering] } }));
        });
        this.onOverwriteExistingFor = (0, memoizee_1.default)((place) => () => {
            this.onOverwriteSelected(place)();
        });
        // Hack that fixed autofocus cursor position
        this.onFocus = (e) => {
            var val = e.target.value;
            e.target.value = "";
            e.target.value = val;
        };
        this.onSubmit = (e) => {
            e.preventDefault();
        };
        this.setInputRef = (elem) => {
            this.inputRef = elem;
        };
        const { namedPlaceID, locality = "" } = props.gathering;
        this.state = { value: locality };
        if (namedPlaceID) {
            this.state = { value: "", loading: true };
        }
        this.apiClient = props.formContext.apiClient;
    }
    componentWillUnmount() {
        this.mounted = false;
    }
    componentDidMount() {
        this.mounted = true;
        this.apiClient.get("/named-places", { query: { includePublic: false, pageSize: 100000 } }).then(response => {
            if (!this.mounted)
                return;
            const state = {
                places: response.results,
                placeIdsToPlaces: response.results.reduce((idsToPlaces, place) => {
                    idsToPlaces[place.id] = place;
                    return idsToPlaces;
                }, {}),
                placeNamesToPlaces: response.results.reduce((namesToPlaces, place) => {
                    if (!namesToPlaces[place.name])
                        namesToPlaces[place.name] = [];
                    namesToPlaces[place.name].push(place);
                    return namesToPlaces;
                }, {})
            };
            const { namedPlaceID } = this.props.gathering;
            if (namedPlaceID) {
                state.value = state.placeIdsToPlaces[namedPlaceID].name;
                state.loading = false;
            }
            this.setState(state, () => {
                if (namedPlaceID) {
                    (0, react_dom_1.findDOMNode)(this.inputRef).focus();
                }
            });
        }).catch(() => {
            this.setState({ failed: FETCH });
        });
    }
    onSave(place) {
        return __awaiter(this, void 0, void 0, function* () {
            place = Object.assign(Object.assign({}, place), { geometry: place.prepopulatedDocument.gatherings[0].geometry });
            this.props.formContext.services.blocker.push();
            try {
                const savedPlace = yield this.apiClient[place.id ? "put" : "post"](`/named-places${place.id ? "/{id}" : ""}`, place.id ? { path: { id: place.id } } : undefined, place);
                this.props.formContext.services.blocker.pop();
                yield this.props.onSave(savedPlace);
            }
            catch (e) {
                this.props.formContext.services.blocker.pop();
                this.setState({ failed: SAVE });
            }
        });
    }
    render() {
        const { value, placeNamesToPlaces = {}, loading } = this.state;
        const { translations } = this.props.formContext;
        const existingPlaces = (placeNamesToPlaces[value] || []).filter(place => {
            return (place.owners || []).includes(this.props.formContext.uiSchemaContext.creator);
        });
        const getButton = (onClick, text) => {
            return React.createElement(components_1.Button, { small: true, onClick: onClick, disabled: loading || (0, utils_1.isEmptyString)(value) }, text);
        };
        const { Panel, FormGroup, FormControl, ListGroup, ListGroupItem, Alert, Form, ControlLabel } = this.context.theme;
        return this.state.failed ? (React.createElement(Alert, { variant: "danger" }, `${translations[`NamedPlaces${this.state.failed === FETCH ? "Fetch" : "Save"}Fail`]} ${translations.TryAgainLater}`)) : (React.createElement("div", { className: "place-saver-dialog" },
            React.createElement(Form, { inline: true, onSubmit: this.onSubmit },
                React.createElement(FormGroup, null,
                    React.createElement(ControlLabel, null,
                        translations.Name,
                        ": "),
                    " ",
                    React.createElement(FormControl, { type: "text", value: value, onChange: this.onInputChange, autoFocus: true, onFocus: this.onFocus, disabled: loading, ref: this.setInputRef }),
                    " ",
                    !existingPlaces.length ?
                        getButton(this.onSaveNew, `${translations.Save} ${translations.new}`) : null,
                    " ",
                    this.props.gathering.namedPlaceID ?
                        getButton(this.onOverwriteCurrentFor(this.props.gathering.namedPlaceID), translations.SaveCurrentOverwrite) : null,
                    existingPlaces.length === 1 && !this.props.gathering.namedPlaceID ?
                        getButton(this.onOverwriteExistingFor(existingPlaces[0]), translations.SaveExistingOverwrite) : null),
                loading ? React.createElement("div", { className: "pull-right" },
                    React.createElement(react_spinner_1.default, null)) : null),
            !this.props.gathering.namedPlaceID && existingPlaces.length ?
                React.createElement(Alert, { variant: "warning" }, `${translations.Warning}: ${translations.UsedNamedPlaceName}.${existingPlaces.length > 1 ? ` ${translations.UsedNamedPlaceNameMultiple}.` : ""}`)
                : null,
            existingPlaces.length > 1 ? (React.createElement(FormGroup, null,
                React.createElement(Panel, null,
                    React.createElement(Panel.Heading, null, translations.ClickPlaceToOverwrite),
                    React.createElement(ListGroup, { fill: "fill" }, existingPlaces.map(place => React.createElement(ListGroupItem, { header: place.name, key: place.id, onClick: loading ? undefined : this.onOverwriteSelected(place), disabled: loading }, place.notes)))))) : null));
    }
}
PlaceSaverDialog.contextType = ReactContext_1.default;
(0, Context_1.default)("SCHEMA_FIELD_WRAPPERS").NamedPlaceSaverField = true;
