import { FieldPresence, FieldSchema, Objects, StructureSchema, ValueType } from '@ephox/boulder';
import { Arr, Fun, Obj, Optional } from '@ephox/katamari';
import * as Fields from '../data/Fields';
import * as UiSubstitutes from '../spec/UiSubstitutes';
import * as PartSubstitutes from './PartSubstitutes';
import * as PartType from './PartType';
// TODO: Make more functional if performance isn't an issue.
const generate = (owner, parts) => {
    const r = {};
    Arr.each(parts, (part) => {
        PartType.asNamedPart(part).each((np) => {
            const g = doGenerateOne(owner, np.pname);
            r[np.name] = (config) => {
                const validated = StructureSchema.asRawOrDie('Part: ' + np.name + ' in ' + owner, StructureSchema.objOf(np.schema), config);
                return {
                    ...g,
                    config,
                    validated
                };
            };
        });
    });
    return r;
};
// Does not have the config.
const doGenerateOne = (owner, pname) => ({
    uiType: UiSubstitutes.placeholder(),
    owner,
    name: pname
});
const generateOne = (owner, pname, config) => ({
    uiType: UiSubstitutes.placeholder(),
    owner,
    name: pname,
    config,
    validated: {}
});
const schemas = (parts) => 
// This actually has to change. It needs to return the schemas for things that will
// not appear in the components list, which is only externals
Arr.bind(parts, (part) => part.fold(Optional.none, Optional.some, Optional.none, Optional.none).map((data) => FieldSchema.requiredObjOf(data.name, data.schema.concat([
    Fields.snapshot(PartType.original())
]))).toArray());
const names = (parts) => Arr.map(parts, PartType.name);
const substitutes = (owner, detail, parts) => PartSubstitutes.subs(owner, detail, parts);
const components = (owner, detail, internals) => UiSubstitutes.substitutePlaces(Optional.some(owner), detail, detail.components, internals);
const getPart = (component, detail, partKey) => {
    const uid = detail.partUids[partKey];
    return component.getSystem().getByUid(uid).toOptional();
};
const getPartOrDie = (component, detail, partKey) => getPart(component, detail, partKey).getOrDie('Could not find part: ' + partKey);
const getParts = (component, detail, partKeys) => {
    const r = {};
    const uids = detail.partUids;
    const system = component.getSystem();
    Arr.each(partKeys, (pk) => {
        r[pk] = Fun.constant(system.getByUid(uids[pk]));
    });
    return r;
};
const getAllParts = (component, detail) => {
    const system = component.getSystem();
    return Obj.map(detail.partUids, (pUid, _k) => Fun.constant(system.getByUid(pUid)));
};
const getAllPartNames = (detail) => Obj.keys(detail.partUids);
const getPartsOrDie = (component, detail, partKeys) => {
    const r = {};
    const uids = detail.partUids;
    const system = component.getSystem();
    Arr.each(partKeys, (pk) => {
        r[pk] = Fun.constant(system.getByUid(uids[pk]).getOrDie());
    });
    return r;
};
const defaultUids = (baseUid, partTypes) => {
    const partNames = names(partTypes);
    return Objects.wrapAll(Arr.map(partNames, (pn) => ({ key: pn, value: baseUid + '-' + pn })));
};
const defaultUidsSchema = (partTypes) => FieldSchema.field('partUids', 'partUids', FieldPresence.mergeWithThunk((spec) => defaultUids(spec.uid, partTypes)), ValueType.anyValue());
export { generate, generateOne, schemas, names, substitutes, components, defaultUids, defaultUidsSchema, getAllParts, getAllPartNames, getPart, getPartOrDie, getParts, getPartsOrDie };
//# sourceMappingURL=AlloyParts.js.map