import { RBTree } from '../../structs/RBTree/rbTree';
// import {Assert} from '../../utils/assert'
import { compareBooleans, compareNumbers } from '../../utils/compare';
import { LowObstacleSide } from './BasicObstacleSide';
import { StaticGraphUtility } from './StaticGraphUtility';
import { VisibilityGraphGenerator } from './VisibilityGraphGenerator';
export class RectilinearScanLine {
    constructor(scanDir, start) {
        this.scanDirection = scanDir;
        this.SideTree = new RBTree((a, b) => this.Compare(a, b));
        this.linePositionAtLastInsertOrRemove = start;
    }
    Insert(side, scanPos) {
        //         DevTraceInfo(1, "prev LinePos = {0}, new LinePos = {1}, inserting side = {2}", this.linePositionAtLastInsertOrRemove, scanPos, side.ToString());
        //  Assert(!scanDirection.IsFlat(side), "Flat sides are not allowed in the scanline");
        //  Assert(null == Find(side), "side already exists in the ScanLine");
        this.linePositionAtLastInsertOrRemove = scanPos;
        //  RBTree's internal operations on insert/remove etc. mean the node can't cache the
        //  RBNode returned by insert(); instead we must do find() on each call.  But we can
        //  use the returned node to get predecessor/successor.
        const node = this.SideTree.insert(side);
        // DevTraceDump(2);
        return node;
    }
    get Count() {
        return this.SideTree.count;
    }
    Remove(side, scanPos) {
        /*Assert.assert(
          null != this.Find(side),
          'side does not exist in the ScanLine',
        )*/
        this.linePositionAtLastInsertOrRemove = scanPos;
        this.SideTree.remove(side);
    }
    Find(side) {
        //  Sides that start after the current position cannot be in the scanline.
        if (-1 == this.scanDirection.ComparePerpCoord(this.linePositionAtLastInsertOrRemove, side.Start)) {
            return null;
        }
        return this.SideTree.find(side);
    }
    NextLowB(side) {
        return this.NextLowR(this.Find(side));
    }
    NextLowR(sideNode) {
        const pred = this.SideTree.previous(sideNode);
        return pred;
    }
    NextHighB(side) {
        return this.NextHighR(this.Find(side));
    }
    NextHighR(sideNode) {
        const succ = this.SideTree.next(sideNode);
        return succ;
    }
    Next(dir, sideNode) {
        const succ = StaticGraphUtility.IsAscending(dir) ? this.SideTree.next(sideNode) : this.SideTree.previous(sideNode);
        return succ;
    }
    Lowest() {
        return this.SideTree.treeMinimum();
    }
    ///  For ordering lines along the scanline at segment starts/ends.
    ///  <param name="first"></param>
    ///  <param name="second"></param>
    ///  <returns></returns>
    Compare(first, second) {
        //  If these are two sides of the same obstacle then the ordering is obvious.
        if (first.Obstacle == second.Obstacle) {
            if (first == second) {
                return 0;
            }
            return first instanceof LowObstacleSide ? -1 : 1;
        }
        // RectilinearScanLine.Debug_VerifySidesDoNotIntersect(first, second)
        //  Other than intersecting sides at vertices of the same obstacle, there should be no interior intersections...
        const firstIntersect = VisibilityGraphGenerator.ScanLineIntersectSidePBS(this.linePositionAtLastInsertOrRemove, first, this.scanDirection);
        const secondIntersect = VisibilityGraphGenerator.ScanLineIntersectSidePBS(this.linePositionAtLastInsertOrRemove, second, this.scanDirection);
        let cmp = firstIntersect.compareTo(secondIntersect);
        //  ... but we may still have rectangular sides that coincide, or angled sides that are close enough here but
        //  are not detected by the convex-hull overlap calculations.  In those cases, we refine the comparison by side
        //  type, with High coming before Low, and then by obstacle ordinal if needed. Because there are no interior
        //  intersections, this ordering will remain valid as long as the side(s) are in the scanline.
        if (0 == cmp) {
            const firstIsLow = first instanceof LowObstacleSide;
            const secondIsLow = second instanceof LowObstacleSide;
            cmp = compareBooleans(firstIsLow, secondIsLow);
            if (0 == cmp) {
                cmp = compareNumbers(first.Obstacle.Ordinal, second.Obstacle.Ordinal);
            }
        }
        return cmp;
    }
}
//# sourceMappingURL=RectilinearScanLine.js.map