import { Rect } from './Rect';
// -------------------------- Packer -------------------------- //
/**
 * @param {Number} width
 * @param {Number} height
 * @param {String} sortDirection
 *   topLeft for vertical, leftTop for horizontal
 */
export class Packer {
    width;
    height;
    sortDirection;
    spaces = [];
    sorter;
    constructor(width, height, sortDirection) {
        this.width = width || 0;
        this.height = height || 0;
        this.sortDirection = sortDirection || 'downwardLeftToRight';
        this.sorter = sorters[this.sortDirection];
        this.reset();
    }
    reset() {
        this.spaces = [];
        var initialSpace = new Rect({
            x: 0,
            y: 0,
            width: this.width,
            height: this.height,
        });
        this.spaces.push(initialSpace);
        // set sorter
        this.sorter = sorters[this.sortDirection] || sorters.downwardLeftToRight;
    }
    // change x and y of rect to fit with in Packer's available spaces
    pack(rect) {
        let doFit = false;
        let space = null;
        for (var i = 0; i < this.spaces.length; i++) {
            space = this.spaces[i];
            if (space.canFit(rect)) {
                doFit = true;
                break;
            }
        }
        if (doFit && space) {
            this.placeInSpace(rect, space);
        }
        return doFit;
    }
    placeInSpace(rect, space) {
        // place rect in space
        rect.x = space.x;
        rect.y = space.y;
        this.placed(rect);
    }
    // update spaces with placed rect
    placed(rect) {
        // update spaces
        var revisedSpaces = [];
        for (var i = 0; i < this.spaces.length; i++) {
            var space = this.spaces[i];
            var newSpaces = space.getMaximalFreeRects(rect);
            // add either the original space or the new spaces to the revised spaces
            if (newSpaces) {
                revisedSpaces.push.apply(revisedSpaces, newSpaces);
            }
            else {
                revisedSpaces.push(space);
            }
        }
        this.spaces = revisedSpaces;
        this.mergeSortSpaces();
    }
    mergeSortSpaces() {
        // remove redundant spaces
        Packer.mergeRects(this.spaces);
        this.spaces.sort(this.sorter);
    }
    // add a space back
    addSpace(rect) {
        this.spaces.push(rect);
        this.mergeSortSpaces();
    }
    // -------------------------- utility functions -------------------------- //
    /**
     * Remove redundant rectangle from array of rectangles
     * @param {Array} rects: an array of Rects
     * @returns {Array} rects: an array of Rects
     **/
    static mergeRects(rects) {
        var i = 0;
        var rect = rects[i];
        rectLoop: while (rect) {
            var j = 0;
            var compareRect = rects[i + j];
            while (compareRect) {
                if (compareRect == rect) {
                    j++; // next
                }
                else if (compareRect.contains(rect)) {
                    // remove rect
                    rects.splice(i, 1);
                    rect = rects[i]; // set next rect
                    continue rectLoop; // bail on compareLoop
                }
                else if (rect.contains(compareRect)) {
                    // remove compareRect
                    rects.splice(i + j, 1);
                }
                else {
                    j++;
                }
                compareRect = rects[i + j]; // set next compareRect
            }
            i++;
            rect = rects[i];
        }
        return rects;
    }
}
// -------------------------- sorters -------------------------- //
// functions for sorting rects in order
var sorters = {
    // top down, then left to right
    downwardLeftToRight: function (a, b) {
        return a.y - b.y || a.x - b.x;
    },
    // left to right, then top down
    rightwardTopToBottom: function (a, b) {
        return a.x - b.x || a.y - b.y;
    },
};
//# sourceMappingURL=Packer.js.map