import { IDisplayInteractionListener } from "../Common/Interfaces/IDisplayInteractionListener";

export abstract class AbstractDisplayInteractionManager {
    protected listeners: IDisplayInteractionListener[] = [];
    private zoomGestureActive: boolean = false;
    protected touchCount: number = 0;
    protected touchActive: boolean = false;
    protected touchMoving: boolean = false;
    private lastRelPosX: number;
    private lastRelPosY: number;
    protected lastPixelX: number;
    protected lastPixelY: number;
    protected displayWidth: number = 1;
    protected displayHeight: number = 1;
    protected displayDpi: number = 96;
    protected maxNumerOfFingers: number = 2;
    protected movementThreshInch: number = 0.075;
    protected interactionWasZoomGesture: boolean = false;
    constructor() {
        // TODO MB: Linter doesn't like empty constructors. Can we just remove this?
    }
    public addListener(listener: IDisplayInteractionListener): void {
        this.listeners.push(listener);
    }
    public get ZoomGestureActive(): boolean {
        return this.zoomGestureActive;
    }
    public get WasZoomGestureActive(): boolean {
        return this.interactionWasZoomGesture;
    }
    public displaySizeChanged(displayWidthInPixel: number, displayHeightInPixel: number): void {
        this.displayWidth = displayWidthInPixel;
        this.displayHeight = displayHeightInPixel;
        for (const listener of this.listeners) {
            listener.displaySizeChanged(this.displayWidth, this.displayHeight);
        }
    }
    public Dispose(): void {
        this.dispose();
    }
    public Initialize(): void {
        this.initialize();
    }
    public get DisplayDpi(): number {
        return this.displayDpi;
    }
    public get TouchActive(): boolean {
        return this.touchActive;
    }
    public get TouchMoving(): boolean {
        return this.touchMoving;
    }
    protected abstract dispose(): void;
    protected abstract initialize(): void;
    protected touchDown(positionInPixelX: number, positionInPixelY: number, leftMouseButton: boolean): void {
        this.interactionWasZoomGesture = false;
        const relativePositionX: number = positionInPixelX / this.displayWidth;
        const relativePositionY: number = positionInPixelY / this.displayHeight;
        this.lastRelPosX = relativePositionX;
        this.lastRelPosY = relativePositionY;
        this.lastPixelX = positionInPixelX;
        this.lastPixelY = positionInPixelY;
        this.touchActive = true;
        this.touchMoving = false;
        this.touchCount = Math.min(this.touchCount + 1, this.maxNumerOfFingers);
        for (const listener of this.listeners) {
            //JL: Why is this negating the leftmousebutton? i guess it expects it to be undefined since it is a touch?
            listener.mouseDown(relativePositionX, relativePositionY, !leftMouseButton);
        }
    }
    protected move(positionInPixelX: number, positionInPixelY: number): void {
        if (this.touchActive && !this.zoomGestureActive) {
            const relativePositionX: number = positionInPixelX / this.displayWidth;
            const relativePositionY: number = positionInPixelY / this.displayHeight;
            const deltaX: number = (relativePositionX - this.lastRelPosX);
            const deltaY: number = (relativePositionY - this.lastRelPosY);
            this.touchMoving = true;
            for (const listener of this.listeners) {
                listener.mouseMove(relativePositionX, relativePositionY, deltaX, deltaY);
            }
        }
    }
    protected zoomGestureStarted(): void {
        this.zoomGestureActive = true;
    }
    protected zoomGestureCompleted(): void {
        this.zoomGestureActive = false;
        this.interactionWasZoomGesture = true;
    }
    protected zoomGestureMove(scale: number): void {
        if (this.zoomGestureActive) {
            this.listeners.forEach(function (dil: IDisplayInteractionListener): void {
                dil.zoom(scale);
            });
        }
    }
    protected touchUp(positionInPixelX: number, positionInPixelY: number): void {
        this.touchActive = false;
        this.touchMoving = false;
        this.touchCount = Math.max(0, this.touchCount - 1);
        const relativePositionX: number = positionInPixelX / this.displayWidth;
        const relativePositionY: number = positionInPixelY / this.displayHeight;
        for (const listener of this.listeners) {
            listener.mouseUp(relativePositionX, relativePositionY);
        }
    }
    protected click(positionInPixelX: number, positionInPixelY: number): void {
        // don't click, if it was a move:
        // changed to still fire click even for small movements (needed for ios, as no touches began fires at view border.)
        if (!this.mouseDidMove(this.lastPixelX, positionInPixelX, this.lastPixelY, positionInPixelY) && !this.ZoomGestureActive) {
            const relativePositionX: number = positionInPixelX / this.displayWidth;
            const relativePositionY: number = positionInPixelY / this.displayHeight;
            for (const listener of this.listeners) {
                listener.positionTouched(relativePositionX, relativePositionY);
            }
        }
    }
    protected doubleClick(positionInPixelX: number, positionInPixelY: number): void {
        // don't click, if it was a move:
        // changed to still fire click even for small movements (needed for ios, as no touches began fired at view border.)
        if (!this.mouseDidMove(this.lastPixelX, positionInPixelX, this.lastPixelY, positionInPixelY) && !this.ZoomGestureActive) {
            const relativePositionX: number = positionInPixelX / this.displayWidth;
            const relativePositionY: number = positionInPixelY / this.displayHeight;
            for (const listener of this.listeners) {
                listener.positionDoubleTouched(relativePositionX, relativePositionY);
            }
        }
    }
    protected mouseDidMove(oldPosX: number, newPosX: number, oldPosY: number, newPosY: number): boolean {
        const movementDpiX: number = Math.abs(oldPosX - newPosX) / this.displayDpi;
        const movementDpiY: number = Math.abs(oldPosY - newPosY) / this.displayDpi;
        return movementDpiX > this.movementThreshInch || movementDpiY > this.movementThreshInch;
    }
}
