import { Arr, Obj } from '@ephox/katamari';
import { Attribute, Classes, Css, Html, Value } from '@ephox/sugar';
import { patchDomChildren } from './Patching';
const diffKeyValueSet = (newObj, oldObj) => {
    const newKeys = Obj.keys(newObj);
    const oldKeys = Obj.keys(oldObj);
    const toRemove = Arr.difference(oldKeys, newKeys);
    const toSet = Obj.bifilter(newObj, (v, k) => {
        return !Obj.has(oldObj, k) || v !== oldObj[k];
    }).t;
    return { toRemove, toSet };
};
const reconcileToDom = (definition, obsoleted) => {
    const { class: clazz, style, ...existingAttributes } = Attribute.clone(obsoleted);
    const { toSet: attrsToSet, toRemove: attrsToRemove } = diffKeyValueSet(definition.attributes, existingAttributes);
    const updateAttrs = () => {
        Arr.each(attrsToRemove, (a) => Attribute.remove(obsoleted, a));
        Attribute.setAll(obsoleted, attrsToSet);
    };
    const existingStyles = Css.getAllRaw(obsoleted);
    const { toSet: stylesToSet, toRemove: stylesToRemove } = diffKeyValueSet(definition.styles, existingStyles);
    const updateStyles = () => {
        Arr.each(stylesToRemove, (s) => Css.remove(obsoleted, s));
        Css.setAll(obsoleted, stylesToSet);
    };
    const existingClasses = Classes.get(obsoleted);
    const classesToRemove = Arr.difference(existingClasses, definition.classes);
    const classesToAdd = Arr.difference(definition.classes, existingClasses);
    const updateClasses = () => {
        Classes.add(obsoleted, classesToAdd);
        Classes.remove(obsoleted, classesToRemove);
    };
    const updateHtml = (html) => {
        Html.set(obsoleted, html);
    };
    const updateChildren = () => {
        const children = definition.domChildren;
        patchDomChildren(obsoleted, children);
    };
    const updateValue = () => {
        const valueElement = obsoleted;
        definition.value
            .filter((value) => value !== Value.get(valueElement))
            .each((value) => Value.set(valueElement, value));
    };
    updateAttrs();
    updateClasses();
    updateStyles();
    // Patching can only support one form of children, so we only update the html or the children, but never both
    definition.innerHtml.fold(updateChildren, updateHtml);
    updateValue();
    return obsoleted;
};
export { reconcileToDom };
//# sourceMappingURL=Reconcile.js.map