export function getViewportDimensionsAndCoords() {
    const width = window.innerWidth;
    const height = window.innerHeight;
    const left = window.pageXOffset;
    const top = window.pageYOffset;
    const right = left + width;
    const bottom = top + height;
    return { width, height, left, top, right, bottom };
}
export function getElementDimensionsAndCoords(element) {
    const rect = element.getBoundingClientRect();
    const window = getViewportDimensionsAndCoords();
    const width = rect.width;
    const height = rect.height;
    const left = rect.left + window.left;
    const top = rect.top + window.top;
    const right = left + width;
    const bottom = top + height;
    return { width, height, left, top, right, bottom };
}
export function getElementDimensions(element) {
    const rect = element.getBoundingClientRect();
    const width = rect.width;
    const height = rect.height;
    return { width, height };
}
const reverseDirectionMap = {
    left: "right",
    right: "left",
    top: "bottom",
    bottom: "top",
};
const dimensionMap = {
    left: "width",
    right: "width",
    top: "height",
    bottom: "height",
};
export function calculateMenuPosition({ toggler, viewport, menu, alignment = ["right", "bottom"], spacing = 0, offset = 0, topLevelMenu = true, }) {
    const sharedArguments = { toggler, viewport, menu, spacing, offset };
    const [directionPreferredPrimary, directionPrefferedSecondary] = alignment;
    const [primaryCoordinateDirection, primaryCoordinate] = calculatePositionForDirection({
        ...sharedArguments,
        direction: directionPreferredPrimary,
        isPrimaryDimension: true,
    });
    const [secondaryCoordinateDirection, secondaryCoordinate] = calculatePositionForDirection({
        ...sharedArguments,
        direction: directionPrefferedSecondary,
        isPrimaryDimension: false,
    });
    const coordinates = {
        [primaryCoordinateDirection]: primaryCoordinate,
        [secondaryCoordinateDirection]: secondaryCoordinate,
    };
    // Convert from left/right+top/bottom coordinates to left+top coordinates
    const res = {
        left: typeof coordinates.left === "number"
            ? coordinates.left
            : toggler.width - menu.width - coordinates.right,
        top: typeof coordinates.top === "number"
            ? coordinates.top
            : toggler.height - menu.height - coordinates.bottom,
    };
    // Returned coordinates are relative to toggler.
    //   - Submenus are positioned relative to the toggler, so we do not do anything.
    //   - Top menu is inside portal positioned relative to the page, so we convert
    //     from coords relative to toggler to coords relative to page.
    if (topLevelMenu) {
        res.left += toggler.left;
        res.top += toggler.top;
    }
    return res;
}
function calculatePositionForDirection({ toggler, viewport, menu, direction, spacing, offset, isPrimaryDimension, }) {
    // Toggler and viewport coordinates are absolute to the page.
    // Returned coordinates are relative to the toggler.
    const directionReverse = reverseDirectionMap[direction];
    const dimension = dimensionMap[direction];
    const directionBottomRight = direction === "bottom" || direction === "right";
    const directionBottomRightMultiplier = directionBottomRight ? 1 : -1;
    const secondaryDimensionAdjust = isPrimaryDimension ? 0 : toggler[dimension];
    const spacingAdjust = isPrimaryDimension ? spacing : 0;
    const offsetAdjust = isPrimaryDimension ? 0 : offset;
    // Primary space is size of the ideal position on the screen.
    // eg.: for direction = "right" primary space would be space between
    // toggler right and viewport right.
    let primarySpace = viewport[direction] - toggler[direction];
    primarySpace = primarySpace + secondaryDimensionAdjust * directionBottomRightMultiplier;
    primarySpace = primarySpace * directionBottomRightMultiplier;
    primarySpace = primarySpace - spacingAdjust;
    primarySpace = primarySpace - offsetAdjust;
    primarySpace = Math.max(0, primarySpace);
    const fitsInPrimarySpace = menu[dimension] <= primarySpace;
    if (fitsInPrimarySpace) {
        // eg.: direction = "right"
        //  menu left side is placed to right side of toggler
        //  menu.left = toggler.width
        const distance = toggler[dimension] - secondaryDimensionAdjust + spacingAdjust + offsetAdjust;
        return [directionReverse, distance];
    }
    let secondarySpace = toggler[directionReverse] - viewport[directionReverse];
    secondarySpace = secondarySpace + secondaryDimensionAdjust * directionBottomRightMultiplier;
    secondarySpace = secondarySpace * directionBottomRightMultiplier;
    secondarySpace = secondarySpace - spacingAdjust;
    secondarySpace = secondarySpace - offsetAdjust;
    secondarySpace = Math.max(0, secondarySpace);
    const fitsInSecondarySpace = menu[dimension] <= secondarySpace;
    if (fitsInSecondarySpace) {
        // eg.: direction = "right"
        //  menu right side is placed to left side of toggler
        //  menu.left = -menu.width
        const distance = -menu[dimension] + secondaryDimensionAdjust - spacingAdjust - offsetAdjust;
        return [directionReverse, distance];
    }
    const doesNotFitInViewport = menu[dimension] > viewport[dimension];
    if (doesNotFitInViewport) {
        // eg.: direction = "right"
        //  menu left side is always placed to left side of viewport
        //  menu.left = viewport.left - menu.left
        const distance = (viewport[directionReverse] - toggler[directionReverse]) * directionBottomRightMultiplier;
        return [directionReverse, distance];
    }
    // eg.: direction = "right"
    //  menu right is placed to the same viewport side
    //  menu.right = toggler.right - menu.right
    const distance = (toggler[direction] - viewport[direction]) * directionBottomRightMultiplier;
    return [direction, distance];
}
