import {Subject} from "rxjs/Subject";
import {PanI} from "./PeekInterfaces.web";
import {PeekCanvasBounds} from "./PeekCanvasBounds";
import {ModelCoordSet} from "@peek/peek_plugin_diagram/_private/tuples/ModelCoordSet";
import {EditorToolType} from "./PeekCanvasEditorToolType.web";
import {DrawModeE} from "../canvas-render/PeekDispRenderDrawModeE.web";


/**
 * Peek Canvas Data
 *
 * This class is responsible for storing all the data required for the canvas.
 * This includes storing referecnes to Model objects, and settings for this canvas
 */
export class PeekCanvasConfig {
    private static canvasIdCounter = 0;

    canvasId: number;

    controller = {
        updateInterval: 400,
        coordSetChange: new Subject<ModelCoordSet>(),
        coordSet: null,
        modelSetKey: ''
    };

    renderer = {
        invalidate: new Subject<void>(), // Set this to true to cause the renderer to redraw
        drawInterval: 60,
        backgroundColor: 'black',
        useEdgeColors: false,
        selection: {
            color: 'white',
            width: 8,
            lineGap: 6,
            dashLen: 3
        },
        suggestion: {
            color: '#3399FF',
            width: 2,
            lineGap: 2,
            dashLen: 3,
            margin: 10, // The distance distance that the click can happen from the shape
        },
        editSelection: {
            color: '#3399FF',
            width: 2,
            lineGap: 4,
            dashLen: 3,
            margin: 10, // The distance distance that the click can happen from the shape
        },
        invisible: { // Draw invisble items in edit mode
            color: 'grey',
            width: 2,
            dashLen: 2
        },
        grid: {
            show: false,
            size: 16,
            color: '#CCC',
            font: '12px Arial',
            lineWidth: 1,
            snapDashedLen: 2
        }
    };

    viewPort = {
        windowChange: new Subject<PeekCanvasBounds>(),
        window: new PeekCanvasBounds(),
        zoomChange: new Subject<number>(),
        panChange: new Subject<PanI>(),
        pan: {
            x: 238255,
            y: 124655
        },
        zoom: 0.5,

        minZoom: 0.01,
        maxZoom: 10
    };

    canvas = {
        windowChange: new Subject<PeekCanvasBounds>(),
        window: new PeekCanvasBounds()
    };

    mouse = {
        currentDelegateName: EditorToolType.SELECT_TOOL,
        phUpDownZoomFactor: 20.0,
        currentViewPortPosition: {x: 0, y: 0},
        currentCanvasPosition: {x: 0, y: 0},
        selecting: {
            color: '#3399FF',
            width: 2,
            lineGap: 2,
            dashLen: 3,
            margin: 10, // The distance distance that the click can happen from the shape
        },
    };

    model = {
        // Set this to true to cause the model to rebuild
        needsCompiling: new Subject<void>(),
        gridsWaitingForData: 0,
        dispOnScreen: 0,
        overlayEnabled: true
    };

    editor = {
        branchKeyChange: new Subject<string | null>(),
        branchKey: null,
        showAllLayers: false,
        showAllLevels: false,
        active: false,
        resizeHandleMargin: 3.0,
        resizeHandleWidth: 6.0,
        selectionHighlightColor: 'orange',
        activeBranchTuple: null,
        snapToGrid: false,
        snapSize: 4
    };

    // Debug data
    debug = {};

    getSelectionDrawDetailsForDrawMode(drawMode: DrawModeE) {
        switch (drawMode) {
            case DrawModeE.ForView:
                return this.renderer.selection;
            case DrawModeE.ForEdit:
                return this.renderer.editSelection;
            case DrawModeE.ForSuggestion:
                return this.renderer.suggestion;
            default:
                throw new Error(`Invalid drawMode ${drawMode}`)
        }
    }

    constructor() {
        this.canvasId = PeekCanvasConfig.canvasIdCounter++;
    }

    invalidate() {
        this.renderer.invalidate.next();
    };

    setModelNeedsCompiling() {
        this.model.needsCompiling.next();
    };

    updateViewPortPan(newPan: PanI) {
        this.viewPort.pan = newPan;
        this.viewPort.panChange.next(newPan);
    }

    updateViewPortZoom(newZoom: number) {
        this.viewPort.zoom = newZoom;
        this.viewPort.zoomChange.next(newZoom);
    }

    updateViewPortWindow(newBounds: PeekCanvasBounds) {
        this.viewPort.window = newBounds;
        this.viewPort.windowChange.next(newBounds);
    }

    updateCanvasWindow(newBounds: PeekCanvasBounds) {
        this.canvas.window = newBounds;
        this.canvas.windowChange.next(newBounds);
    }

    updateCoordSet(newCoordSet: ModelCoordSet) {
        this.controller.coordSet = newCoordSet;
        this.controller.coordSetChange.next(newCoordSet);

        this.viewPort.minZoom = newCoordSet.minZoom;
        this.viewPort.maxZoom = newCoordSet.maxZoom;

        if (newCoordSet == null) {
            this.updateViewPortPan({x: 0, y: 0});
            this.updateViewPortZoom(1.0);

        } else {
            this.updateViewPortPan(
                {x: newCoordSet.initialPanX, y: newCoordSet.initialPanY}
            );
            this.updateViewPortZoom(newCoordSet.initialZoom);
        }
    }

    updateEditedBranch(branchKey: string | null): void {
        this.editor.branchKey = branchKey;
        this.editor.branchKeyChange.next(branchKey);
    }

    get coordSet(): ModelCoordSet | null {
        return this.controller.coordSet;
    }
}