import { Inject, Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { FlexibleConnectedPositionStrategy, GlobalPositionStrategy, OverlayPositionBuilder, } from '@angular/cdk/overlay';
import { DOCUMENT } from '@angular/common';
import { Platform } from '@angular/cdk/platform';
import { RGlobalLogicalPosition } from './position-helper';
import { RViewportRulerAdapter } from '../adapter/viewport-ruler-adapter';
import { ROverlayContainerAdapter } from '../adapter/overlay-container-adapter';
export var RAdjustment;
(function (RAdjustment) {
    RAdjustment["NOOP"] = "noop";
    RAdjustment["CLOCKWISE"] = "clockwise";
    RAdjustment["COUNTERCLOCKWISE"] = "counterclockwise";
    RAdjustment["VERTICAL"] = "vertical";
    RAdjustment["HORIZONTAL"] = "horizontal";
})(RAdjustment || (RAdjustment = {}));
export var RPosition;
(function (RPosition) {
    RPosition["TOP"] = "top";
    RPosition["BOTTOM"] = "bottom";
    RPosition["LEFT"] = "left";
    RPosition["RIGHT"] = "right";
    RPosition["START"] = "start";
    RPosition["END"] = "end";
    RPosition["TOP_END"] = "top-end";
    RPosition["TOP_START"] = "top-start";
    RPosition["BOTTOM_END"] = "bottom-end";
    RPosition["BOTTOM_START"] = "bottom-start";
    RPosition["END_TOP"] = "end-top";
    RPosition["END_BOTTOM"] = "end-bottom";
    RPosition["START_TOP"] = "start-top";
    RPosition["START_BOTTOM"] = "start-bottom";
})(RPosition || (RPosition = {}));
const POSITIONS = {
    [RPosition.RIGHT](offset) {
        return {
            originX: 'end',
            originY: 'center',
            overlayX: 'start',
            overlayY: 'center',
            offsetX: offset,
        };
    },
    [RPosition.BOTTOM](offset) {
        return {
            originX: 'center',
            originY: 'bottom',
            overlayX: 'center',
            overlayY: 'top',
            offsetY: offset,
        };
    },
    [RPosition.LEFT](offset) {
        return {
            originX: 'start',
            originY: 'center',
            overlayX: 'end',
            overlayY: 'center',
            offsetX: -offset,
        };
    },
    [RPosition.TOP](offset) {
        return {
            originX: 'center',
            originY: 'top',
            overlayX: 'center',
            overlayY: 'bottom',
            offsetY: -offset,
        };
    },
    [RPosition.START](offset) {
        return this[RPosition.LEFT](offset);
    },
    [RPosition.END](offset) {
        return this[RPosition.RIGHT](offset);
    },
    [RPosition.END_TOP](offset) {
        return {
            originX: 'end',
            originY: 'bottom',
            overlayX: 'start',
            overlayY: 'bottom',
            offsetX: offset,
        };
    },
    [RPosition.END_BOTTOM](offset) {
        return {
            originX: 'end',
            originY: 'top',
            overlayX: 'start',
            overlayY: 'top',
            offsetX: offset,
        };
    },
    [RPosition.BOTTOM_START](offset) {
        return {
            originX: 'end',
            originY: 'bottom',
            overlayX: 'end',
            overlayY: 'top',
            offsetY: offset,
        };
    },
    [RPosition.BOTTOM_END](offset) {
        return {
            originX: 'start',
            originY: 'bottom',
            overlayX: 'start',
            overlayY: 'top',
            offsetY: offset,
        };
    },
    [RPosition.START_TOP](offset) {
        return {
            originX: 'start',
            originY: 'bottom',
            overlayX: 'end',
            overlayY: 'bottom',
            offsetX: -offset,
        };
    },
    [RPosition.START_BOTTOM](offset) {
        return {
            originX: 'start',
            originY: 'top',
            overlayX: 'end',
            overlayY: 'top',
            offsetX: -offset,
        };
    },
    [RPosition.TOP_START](offset) {
        return {
            originX: 'end',
            originY: 'top',
            overlayX: 'end',
            overlayY: 'bottom',
            offsetY: -offset,
        };
    },
    [RPosition.TOP_END](offset) {
        return {
            originX: 'start',
            originY: 'top',
            overlayX: 'start',
            overlayY: 'bottom',
            offsetY: -offset,
        };
    },
};
const COUNTER_CLOCKWISE_POSITIONS = [
    RPosition.TOP,
    RPosition.TOP_END,
    RPosition.TOP_START,
    RPosition.START,
    RPosition.START_TOP,
    RPosition.START_BOTTOM,
    RPosition.BOTTOM,
    RPosition.BOTTOM_START,
    RPosition.BOTTOM_END,
    RPosition.END,
    RPosition.END_BOTTOM,
    RPosition.END_TOP,
];
const CLOCKWISE_POSITIONS = [
    RPosition.TOP,
    RPosition.TOP_START,
    RPosition.TOP_END,
    RPosition.END,
    RPosition.END_TOP,
    RPosition.END_BOTTOM,
    RPosition.BOTTOM,
    RPosition.BOTTOM_END,
    RPosition.BOTTOM_START,
    RPosition.START,
    RPosition.START_BOTTOM,
    RPosition.START_TOP,
];
const VERTICAL_POSITIONS = [RPosition.BOTTOM, RPosition.TOP];
const HORIZONTAL_POSITIONS = [RPosition.START, RPosition.END];
function comparePositions(p1, p2) {
    return (p1.originX === p2.originX &&
        p1.originY === p2.originY &&
        p1.overlayX === p2.overlayX &&
        p1.overlayY === p2.overlayY);
}
/**
 * The main idea of the adjustable connected strategy is to provide predefined set of positions for your overlay.
 * You have to provide adjustment and appropriate strategy will be chosen in runtime.
 */
export class RAdjustableConnectedPositionStrategy extends FlexibleConnectedPositionStrategy {
    constructor() {
        super(...arguments);
        this._offset = 15;
        this.positionChange = this.positionChanges.pipe(map((positionChange) => positionChange.connectionPair), map((connectionPair) => {
            return this.appliedPositions.find(({ connectedPosition }) => {
                return comparePositions(connectedPosition, connectionPair);
            }).key;
        }));
    }
    attach(overlayRef) {
        /**
         * We have to apply positions before attach because super.attach() validates positions and crashes app
         * if no positions provided.
         * */
        this.applyPositions();
        super.attach(overlayRef);
    }
    apply() {
        this.applyPositions();
        super.apply();
    }
    position(position) {
        this._position = position;
        return this;
    }
    adjustment(adjustment) {
        this._adjustment = adjustment;
        return this;
    }
    offset(offset) {
        this._offset = offset;
        return this;
    }
    applyPositions() {
        const positions = this.createPositions();
        this.persistChosenPositions(positions);
        this.withPositions(this.appliedPositions.map(({ connectedPosition }) => connectedPosition));
    }
    createPositions() {
        switch (this._adjustment) {
            case RAdjustment.NOOP:
                return [this._position];
            case RAdjustment.CLOCKWISE:
                return this.reorderPreferredPositions(CLOCKWISE_POSITIONS);
            case RAdjustment.COUNTERCLOCKWISE:
                return this.reorderPreferredPositions(COUNTER_CLOCKWISE_POSITIONS);
            case RAdjustment.HORIZONTAL:
                return this.reorderPreferredPositions(HORIZONTAL_POSITIONS);
            case RAdjustment.VERTICAL:
                return this.reorderPreferredPositions(VERTICAL_POSITIONS);
        }
    }
    persistChosenPositions(positions) {
        this.appliedPositions = positions.map((position) => ({
            key: position,
            connectedPosition: POSITIONS[position](this._offset),
        }));
    }
    reorderPreferredPositions(positions) {
        // Physical positions should be mapped to logical as adjustments use logical positions.
        const startPositionIndex = positions.indexOf(this.mapToLogicalPosition(this._position));
        const firstPart = positions.slice(startPositionIndex);
        const secondPart = positions.slice(0, startPositionIndex);
        return firstPart.concat(secondPart);
    }
    mapToLogicalPosition(position) {
        if (position === RPosition.LEFT) {
            return RPosition.START;
        }
        if (position === RPosition.RIGHT) {
            return RPosition.END;
        }
        return position;
    }
}
export class RGlobalPositionStrategy extends GlobalPositionStrategy {
    position(position) {
        switch (position) {
            case RGlobalLogicalPosition.TOP_START:
                return this.top().left();
            case RGlobalLogicalPosition.TOP_END:
                return this.top().right();
            case RGlobalLogicalPosition.BOTTOM_START:
                return this.bottom().left();
            case RGlobalLogicalPosition.BOTTOM_END:
                return this.bottom().right();
        }
    }
}
export class RPositionBuilderService {
    constructor(document, viewportRuler, platform, positionBuilder, overlayContainer) {
        this.document = document;
        this.viewportRuler = viewportRuler;
        this.platform = platform;
        this.positionBuilder = positionBuilder;
        this.overlayContainer = overlayContainer;
    }
    global() {
        return new RGlobalPositionStrategy();
    }
    connectedTo(elementRef) {
        return new RAdjustableConnectedPositionStrategy(elementRef, this.viewportRuler, this.document, this.platform, this.overlayContainer).withFlexibleDimensions(false).withPush(false);
    }
}
RPositionBuilderService.decorators = [
    { type: Injectable }
];
RPositionBuilderService.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
    { type: RViewportRulerAdapter },
    { type: Platform },
    { type: OverlayPositionBuilder },
    { type: ROverlayContainerAdapter }
];
//# sourceMappingURL=overlay-position.js.map