import { Adt, Fun, Optional } from '@ephox/katamari';
import { Height, Scroll, SugarPosition, Width } from '@ephox/sugar';
import * as Boxes from '../../alien/Boxes';
import * as OuterPosition from '../../frame/OuterPosition';
import { NuPositionCss } from '../view/PositionCss';
import * as Direction from './Direction';
const adt = Adt.generate([
    { none: [] },
    { relative: ['x', 'y', 'width', 'height'] },
    { fixed: ['x', 'y', 'width', 'height'] }
]);
const positionWithDirection = (posName, decision, x, y, width, height) => {
    const decisionRect = decision.rect;
    const decisionX = decisionRect.x - x;
    const decisionY = decisionRect.y - y;
    const decisionWidth = decisionRect.width;
    const decisionHeight = decisionRect.height;
    const decisionRight = width - (decisionX + decisionWidth);
    const decisionBottom = height - (decisionY + decisionHeight);
    const left = Optional.some(decisionX);
    const top = Optional.some(decisionY);
    const right = Optional.some(decisionRight);
    const bottom = Optional.some(decisionBottom);
    const none = Optional.none();
    return Direction.cata(decision.direction, () => NuPositionCss(posName, left, top, none, none), // southeast
    () => NuPositionCss(posName, none, top, right, none), // southwest
    () => NuPositionCss(posName, left, none, none, bottom), // northeast
    () => NuPositionCss(posName, none, none, right, bottom), // northwest
    () => NuPositionCss(posName, left, top, none, none), // south
    () => NuPositionCss(posName, left, none, none, bottom), // north
    () => NuPositionCss(posName, left, top, none, none), // east
    () => NuPositionCss(posName, none, top, right, none) // west
    );
};
const reposition = (origin, decision) => origin.fold(() => {
    const decisionRect = decision.rect;
    return NuPositionCss('absolute', Optional.some(decisionRect.x), Optional.some(decisionRect.y), Optional.none(), Optional.none());
}, (x, y, width, height) => {
    return positionWithDirection('absolute', decision, x, y, width, height);
}, (x, y, width, height) => {
    return positionWithDirection('fixed', decision, x, y, width, height);
});
const toBox = (origin, element) => {
    const rel = Fun.curry(OuterPosition.find, element);
    const position = origin.fold(rel, rel, () => {
        const scroll = Scroll.get();
        // TODO: Make adding the scroll in OuterPosition.find optional.
        return OuterPosition.find(element).translate(-scroll.left, -scroll.top);
    });
    const width = Width.getOuter(element);
    const height = Height.getOuter(element);
    return Boxes.bounds(position.left, position.top, width, height);
};
const viewport = (origin, optBounds) => optBounds.fold(
/* There are no bounds supplied */
() => origin.fold(Boxes.win, Boxes.win, Boxes.bounds), (bounds) => 
/* Use any bounds supplied or remove the scroll position of the bounds for fixed. */
origin.fold(Fun.constant(bounds), Fun.constant(bounds), () => {
    const pos = translate(origin, bounds.x, bounds.y);
    return Boxes.bounds(pos.left, pos.top, bounds.width, bounds.height);
}));
const translate = (origin, x, y) => {
    const pos = SugarPosition(x, y);
    const removeScroll = () => {
        const outerScroll = Scroll.get();
        return pos.translate(-outerScroll.left, -outerScroll.top);
    };
    // This could use cata if it wasn't a circular reference
    return origin.fold(Fun.constant(pos), Fun.constant(pos), removeScroll);
};
const cata = (subject, onNone, onRelative, onFixed) => subject.fold(onNone, onRelative, onFixed);
const none = adt.none;
const relative = adt.relative;
const fixed = adt.fixed;
export { none, relative, fixed, reposition, viewport, toBox, translate, cata };
//# sourceMappingURL=Origins.js.map