"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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ArrayFieldPatched = exports.copyItemFunction = void 0;
exports.onArrayFieldChange = onArrayFieldChange;
const React = __importStar(require("react"));
const deepmerge_1 = __importDefault(require("deepmerge"));
const utils_1 = require("../../utils");
const ArrayFieldTemplate_1 = require("../templates/ArrayFieldTemplate");
const ReactContext_1 = __importDefault(require("../../ReactContext"));
const core_1 = require("@rjsf/core");
// Doesn't work with arrays properly since uses JSON Pointers but not JSON path.
// e.g. "copy all array item values expect these" is impossible.
const copyItemFunction = (that, copyItem) => (props, { type, filter }) => {
    const { schema, registry, formContext } = that.props;
    const defaultItem = (0, utils_1.getDefaultFormState)(schema.items, undefined);
    copyItem = formContext.utils.filterItemIdsDeeply(copyItem, that.props.idSchema.$id);
    const source = type === "blacklist" ? defaultItem : copyItem;
    const filtered = filter.sort().reverse().reduce((target, f) => {
        let sourceValue;
        try {
            sourceValue = (0, utils_1.parseJSONPointer)(source, f);
        }
        catch (e) {
            const schema = (0, utils_1.schemaJSONPointer)(schema.items, f);
            sourceValue = (0, utils_1.getDefaultFormState)(schema, undefined);
        }
        return (0, utils_1.updateFormDataWithJSONPointer)({ schema: schema.items, formData: target, registry }, sourceValue, f);
    }, type === "blacklist" ? copyItem : defaultItem);
    const tmpIdTree = that.props.formContext.services.ids.getRelativeTmpIdTree(props.idSchema.$id);
    return (0, utils_1.addLajiFormIds)(filtered, tmpIdTree, false)[0];
};
exports.copyItemFunction = copyItemFunction;
function onArrayFieldChange(formData, props) {
    const tmpIdTree = props.formContext.services.ids.getRelativeTmpIdTree(props.idSchema.$id);
    return (0, utils_1.addLajiFormIds)(formData, tmpIdTree, false)[0];
}
const { ArrayField } = (0, core_1.getDefaultRegistry)().fields;
class ArrayFieldPatched extends ArrayField {
    constructor(...params) {
        super(...params);
        const { _getNewFormDataRow } = this;
        this._getNewFormDataRow = () => {
            const tmpIdTree = this.props.formContext.services.ids.getRelativeTmpIdTree(this.props.idSchema.$id);
            const [item] = (0, utils_1.addLajiFormIds)(_getNewFormDataRow.call(this), tmpIdTree, false);
            return item;
        };
        const { onDropIndexClick } = this;
        this.onDropIndexClick = (index) => (event) => {
            const item = this.props.formData[index];
            const tmpIdTree = this.props.formContext.services.ids.getRelativeTmpIdTree(`${this.props.idSchema.$id}_${index}`);
            const oldIds = (0, utils_1.getAllLajiFormIdsDeeply)(item, tmpIdTree);
            Object.keys(oldIds).forEach((id) => {
                return this.props.formContext.services.submitHooks.remove(id);
            }, []);
            onDropIndexClick.call(this, index)(event);
        };
    }
    renderArrayFieldItem(props) {
        // rjsf@5 started rendering array items with titles as "name-idx" - we don't want that.
        if (typeof props.name === "string") {
            props.name = undefined;
        }
        if (this.props.idSchema) {
            const idSchema = this.getIdSchema(this.props, props.index);
            return super.renderArrayFieldItem(Object.assign(Object.assign({}, props), { itemIdSchema: idSchema }));
        }
        return super.renderArrayFieldItem(props);
    }
    getIdSchema(props, _index) {
        const { idSchema } = props;
        const index = (0, utils_1.getFormDataIndex)(_index, props.uiSchema);
        const root = idSchema.$id;
        const reduced = (idSchema, root) => Object.keys(idSchema).reduce((idSchema, prop) => {
            if (prop === "$id") {
                return Object.assign(Object.assign({}, idSchema), { "$id": idSchema.$id.replace(root, `${root}_${index}`) });
            }
            return Object.assign(Object.assign({}, idSchema), { [prop]: reduced(idSchema[prop], root) });
        }, idSchema);
        return reduced(idSchema, root);
    }
}
exports.ArrayFieldPatched = ArrayFieldPatched;
class _ArrayField extends React.Component {
    constructor() {
        super(...arguments);
        this.onChange = (formData) => {
            this.props.onChange(onArrayFieldChange(formData, this.props));
        };
        this.buttonDefinitions = {
            copy: {
                glyph: "duplicate",
                fn: () => (...params) => {
                    (0, ArrayFieldTemplate_1.beforeAdd)(this.props);
                    this.onChange([
                        ...this.props.formData,
                        (0, exports.copyItemFunction)(this, this.props.formData[this.props.formData.length - 1])(...params)
                    ]);
                },
                rules: {
                    minLength: 1,
                    canAdd: true
                },
                changesFormData: true
            },
            addPredefined: {
                fn: () => (onClickProps, { default: _default }) => {
                    (0, ArrayFieldTemplate_1.beforeAdd)(this.props);
                    this.onChange([
                        ...(this.props.formData || []),
                        (0, utils_1.getDefaultFormState)(this.props.schema.items, _default)
                    ]);
                },
                rules: {
                    canAdd: true
                },
                changesFormData: true
            }
        };
    }
    render() {
        const { props } = this;
        let { schema } = props;
        if (props.uiSchema.items && props.uiSchema.items["ui:field"]) {
            schema = Object.assign(Object.assign({}, schema), { uniqueItems: false });
        }
        // MultiArrayField needs to intercept default ArrayField internals, the instance is passed in formContext.
        const { ArrayField: _ArrayField } = props.formContext;
        const Component = _ArrayField || ArrayFieldPatched;
        // Reset formContext.ArrayField
        const formContext = _ArrayField ? Object.assign(Object.assign({}, props.formContext), { ArrayField: undefined }) : props.formContext;
        const registry = _ArrayField ? Object.assign(Object.assign({}, props.registry), { formContext }) : props.registry;
        return React.createElement(Component, Object.assign({}, props, { formContext: formContext, registry: registry, schema: schema, uiSchema: Object.assign(Object.assign({}, props.uiSchema), { "ui:options": Object.assign(Object.assign({ orderable: false }, props.uiSchema["ui:options"]), { buttonDefinitions: (0, utils_1.getUiOptions)(props.uiSchema).buttonDefinitions
                        ? (0, deepmerge_1.default)(this.buttonDefinitions, (0, utils_1.getUiOptions)(props.uiSchema).buttonDefinitions)
                        : this.buttonDefinitions }) }), onChange: this.onChange }));
    }
}
_ArrayField.contextType = ReactContext_1.default;
exports.default = _ArrayField;
