import { range } from 'd3-array';
import { scaleBand, scaleQuantile } from 'd3-scale';
import { WaferMapOriginLocation } from '../types';
/**
 * Computations calculates and stores different measures which are used in the Wafermap
 */
export class Computations {
    get containerDimensions() {
        return this._containerDimensions;
    }
    get dieDimensions() {
        return this._dieDimensions;
    }
    get radius() {
        return this._radius;
    }
    get margin() {
        return this._margin;
    }
    get horizontalScale() {
        return this._horizontalScale;
    }
    get verticalScale() {
        return this._verticalScale;
    }
    get invertedHorizontalScale() {
        return this._invertedHorizontalScale;
    }
    get invertedVerticalScale() {
        return this._invertedVerticalScale;
    }
    constructor(wafermap) {
        this.wafermap = wafermap;
        this.defaultPadding = 0;
        this.baseMarginPercentage = 0.04;
    }
    updateContainerDimensions() {
        const canvasDimensions = {
            width: this.wafermap.canvasWidth,
            height: this.wafermap.canvasHeight
        };
        const canvasDiameter = Math.min(canvasDimensions.width, canvasDimensions.height);
        const canvasMargin = {
            top: (canvasDimensions.height - canvasDiameter) / 2,
            right: (canvasDimensions.width - canvasDiameter) / 2,
            bottom: (canvasDimensions.height - canvasDiameter) / 2,
            left: (canvasDimensions.width - canvasDiameter) / 2
        };
        const baseMargin = {
            top: canvasDiameter * this.baseMarginPercentage,
            right: canvasDiameter * this.baseMarginPercentage,
            bottom: canvasDiameter * this.baseMarginPercentage,
            left: canvasDiameter * this.baseMarginPercentage
        };
        this._margin = this.calculateMarginAddition(baseMargin, canvasMargin);
        this._containerDimensions = this.calculateContainerDimensions(canvasDimensions, this._margin);
        const containerDiameter = Math.min(this._containerDimensions.width, this._containerDimensions.height);
        this._radius = containerDiameter / 2;
        this.updateScales();
    }
    updateScales() {
        const containerDiameter = Math.min(this._containerDimensions.width, this._containerDimensions.height);
        const gridDimensions = this.gridDimensionsValidAndDefined()
            ? this.calculateGridDimensionsFromBoundingBox()
            : this.calculateGridDimensionsFromDies(this.wafermap.dies);
        // this scale is used for positioning the dies on the canvas
        const originLocation = this.wafermap.originLocation;
        this._horizontalScale = this.createHorizontalScale(originLocation, gridDimensions, containerDiameter);
        this._invertedHorizontalScale = this.createInvertedHorizontalScale(originLocation, gridDimensions, containerDiameter);
        // this scale is used for positioning the dies on the canvas
        this._verticalScale = this.createVerticalScale(originLocation, gridDimensions, containerDiameter);
        this._invertedVerticalScale = this.createInvertedVerticalScale(originLocation, gridDimensions, containerDiameter);
        const dieWidth = this.horizontalScale.bandwidth();
        const dieHeight = this.verticalScale.bandwidth();
        this._dieDimensions = {
            width: isNaN(dieWidth) ? 0 : dieWidth,
            height: isNaN(dieHeight) ? 0 : dieHeight
        };
    }
    gridDimensionsValidAndDefined() {
        return (!this.wafermap.validity.invalidGridDimensions
            && typeof this.wafermap.gridMinX === 'number'
            && typeof this.wafermap.gridMinY === 'number'
            && typeof this.wafermap.gridMaxX === 'number'
            && typeof this.wafermap.gridMinX === 'number');
    }
    calculateGridDimensionsFromBoundingBox() {
        const gridDimensions = { origin: { x: 0, y: 0 }, rows: 0, cols: 0 };
        if (typeof this.wafermap.gridMaxY === 'number'
            && typeof this.wafermap.gridMinY === 'number'
            && typeof this.wafermap.gridMaxX === 'number'
            && typeof this.wafermap.gridMinX === 'number') {
            gridDimensions.origin.x = this.wafermap.gridMinX;
            gridDimensions.origin.y = this.wafermap.gridMinY;
            gridDimensions.rows = this.wafermap.gridMaxY - this.wafermap.gridMinY + 1;
            gridDimensions.cols = this.wafermap.gridMaxX - this.wafermap.gridMinX + 1;
        }
        return gridDimensions;
    }
    calculateGridDimensionsFromDies(dies) {
        if (dies.length === 0 || dies[0] === undefined) {
            return { origin: { x: 0, y: 0 }, rows: 0, cols: 0 };
        }
        const minPoint = { x: dies[0].x, y: dies[0].y };
        const maxPoint = { x: dies[0].x, y: dies[0].y };
        for (const die of dies) {
            if (die.x < minPoint.x) {
                minPoint.x = die.x;
            }
            if (die.y < minPoint.y) {
                minPoint.y = die.y;
            }
            if (die.x > maxPoint.x) {
                maxPoint.x = die.x;
            }
            if (die.y > maxPoint.y) {
                maxPoint.y = die.y;
            }
        }
        return {
            origin: minPoint,
            rows: maxPoint.y - minPoint.y + 1,
            cols: maxPoint.x - minPoint.x + 1
        };
    }
    calculateContainerDimensions(canvasDimensions, margin) {
        return {
            width: canvasDimensions.width - margin.left - margin.right,
            height: canvasDimensions.height - margin.top - margin.bottom
        };
    }
    createHorizontalScale(originLocation, grid, containerWidth) {
        const scale = scaleBand()
            .domain(range(grid.origin.x, grid.origin.x + grid.cols))
            .paddingInner(0)
            .paddingOuter(0)
            .align(0)
            .round(false);
        if (originLocation === WaferMapOriginLocation.bottomLeft
            || originLocation === WaferMapOriginLocation.topLeft) {
            return scale.range([0, containerWidth]);
        }
        return scale.range([containerWidth, 0]);
    }
    createInvertedHorizontalScale(originLocation, grid, containerWidth) {
        const scale = scaleQuantile().domain([0, containerWidth]);
        if (originLocation === WaferMapOriginLocation.bottomLeft
            || originLocation === WaferMapOriginLocation.topLeft) {
            return scale.range(range(grid.origin.x, grid.origin.x + grid.cols));
        }
        return scale.range(range(grid.origin.x, grid.origin.x + grid.cols).reverse());
    }
    createVerticalScale(originLocation, grid, containerHeight) {
        const scale = scaleBand()
            .domain(range(grid.origin.y, grid.origin.y + grid.rows))
            .paddingInner(this.defaultPadding)
            .paddingOuter(0)
            .align(0)
            .round(false);
        // html canvas has top-left origin https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes#the_grid
        // we need to flip the vertical scale
        if (originLocation === WaferMapOriginLocation.bottomLeft
            || originLocation === WaferMapOriginLocation.bottomRight) {
            return scale.range([containerHeight, 0]);
        }
        return scale.range([0, containerHeight]);
    }
    createInvertedVerticalScale(originLocation, grid, containerHeight) {
        const scale = scaleQuantile().domain([0, containerHeight]);
        // html canvas has top-left origin https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes#the_grid
        // we need to flip the inverted vertical scale
        if (originLocation === WaferMapOriginLocation.bottomLeft
            || originLocation === WaferMapOriginLocation.bottomRight) {
            return scale.range(range(grid.origin.y, grid.origin.y + grid.rows).reverse());
        }
        return scale.range(range(grid.origin.y, grid.origin.y + grid.rows));
    }
    calculateMarginAddition(baseMargin, addedMargin) {
        return {
            top: baseMargin.top + addedMargin.top,
            right: baseMargin.right + addedMargin.right,
            bottom: baseMargin.bottom + addedMargin.bottom,
            left: baseMargin.left + addedMargin.left
        };
    }
}
//# sourceMappingURL=computations.js.map