import { LayerEdge } from './LayerEdge';
// import {Assert} from '../../utils/assert'
import { LineSegment } from '../../math/geometry/lineSegment';
import { Curve } from '../../math/geometry/curve';
import { Point } from '../../math/geometry/point';
class Routing {
    static FindClosestPoints(segmentInFrontOfLabel, labelSide) {
        const minDistOutput = Curve.minDistWithinIntervals(segmentInFrontOfLabel, labelSide, segmentInFrontOfLabel.parStart, segmentInFrontOfLabel.parEnd, labelSide.parStart, labelSide.parEnd, (segmentInFrontOfLabel.parStart + segmentInFrontOfLabel.parEnd) / 2, (labelSide.parStart + labelSide.parEnd) / 2);
        if (minDistOutput) {
            return {
                curveClosestPoint: minDistOutput.aX,
                labelSideClosest: minDistOutput.bX,
            };
        }
        return;
    }
    static GetSegmentInFrontOfLabel(edgeCurve, labelY) {
        if (edgeCurve instanceof Curve) {
            for (const seg of edgeCurve.segs)
                if ((seg.start.y - labelY) * (seg.end.y - labelY) <= 0)
                    return seg;
        }
        else {
            /*Assert.assert(false)*/
        }
        return null;
    }
    static ShiftLabel(e, curveClosestPoint, labelSideClosest) {
        const w = e.lineWidth / 2;
        const shift = curveClosestPoint.sub(labelSideClosest);
        const shiftLength = shift.length;
        //   SugiyamaLayoutSettings.Show(e.Curve, shiftLength > 0 ? new LineSegment(curveClosestPoint, labelSideClosest) : null, PolyFromBox(e.LabelBBox));
        if (shiftLength > w)
            e.label.center = e.label.center.add(shift.div(shiftLength * (shiftLength - w)));
    }
    static updateLabel(e, anchor) {
        let labelSide = null;
        if (anchor.labelIsToTheRightOfTheSpline) {
            e.label.center = new Point(anchor.x + anchor.rightAnchor / 2, anchor.y);
            labelSide = LineSegment.mkPP(e.labelBBox.leftTop, e.labelBBox.leftBottom);
        }
        else if (anchor.labelIsToTheLeftOfTheSpline) {
            e.label.center = new Point(anchor.x - anchor.leftAnchor / 2, anchor.y);
            labelSide = LineSegment.mkPP(e.labelBBox.rightTop, e.labelBBox.rightBottom);
        }
        const segmentInFrontOfLabel = Routing.GetSegmentInFrontOfLabel(e.curve, e.label.center.y);
        if (segmentInFrontOfLabel == null)
            return;
        if (Curve.getAllIntersections(e.curve, Curve.polyFromBox(e.labelBBox), false).length == 0) {
            const t = Routing.FindClosestPoints(segmentInFrontOfLabel, labelSide);
            if (t) {
                //shift the label if needed
                Routing.ShiftLabel(e, t.curveClosestPoint, t.labelSideClosest);
            }
            else {
                let curveClosestPoint;
                let labelSideClosest;
                //assume that the distance is reached at the ends of labelSideClosest
                const u = segmentInFrontOfLabel.closestParameter(labelSide.start);
                const v = segmentInFrontOfLabel.closestParameter(labelSide.end);
                if (segmentInFrontOfLabel.value(u).sub(labelSide.start).length < segmentInFrontOfLabel.value(v).sub(labelSide.end).length) {
                    curveClosestPoint = segmentInFrontOfLabel.value(u);
                    labelSideClosest = labelSide.start;
                }
                else {
                    curveClosestPoint = segmentInFrontOfLabel.value(v);
                    labelSideClosest = labelSide.end;
                }
                Routing.ShiftLabel(e, curveClosestPoint, labelSideClosest);
            }
        }
    }
}
// An edge with source and target represented as integers,
// they point to the array of Nodes of the graph
export class PolyIntEdge {
    constructor(source, target, geomEdge, weight = 1, separation = 1) {
        this.reversed = false;
        this.source = source;
        this.target = target;
        this.edge = geomEdge;
        this.weight = weight;
        this.separation = separation;
    }
    get CrossingWeight() {
        return 1;
    }
    get hasLabel() {
        return this.edge.label != null;
    }
    get labelWidth() {
        return this.edge.label.width;
    }
    get labelHeight() {
        return this.edge.label.height;
    }
    // This function changes the edge by swapping source and target.
    reverse() {
        const t = this.source;
        this.source = this.target;
        this.target = t;
        this.reversed = !this.reversed;
    }
    toString() {
        return 'edge(' + this.source + '->' + this.target + ')';
    }
    get curve() {
        return this.edge.curve;
    }
    set curve(value) {
        this.edge.curve = value;
    }
    get underlyingPolyline() {
        return this.edge.underlyingPolyline;
    }
    set underlyingPolyline(value) {
        this.edge.underlyingPolyline = value;
    }
    get LayerSpan() {
        return this.LayerEdges != null ? this.LayerEdges.length : 0;
    }
    isSelfEdge() {
        return this.source == this.target;
    }
    reversedClone() {
        const ret = new PolyIntEdge(this.target, this.source, this.edge);
        if (this.LayerEdges != null) {
            const len = this.LayerEdges.length;
            ret.LayerEdges = new Array(len);
            for (let i = 0; i < len; i++) {
                const le = this.LayerEdges[len - 1 - i];
                ret.LayerEdges[i] = new LayerEdge(le.Target, le.Source, le.CrossingWeight);
            }
            ret.LayerEdges[0].Source = this.target;
            ret.LayerEdges[this.LayerEdges.length - 1].Target = this.source;
        }
        return ret;
    }
    get count() {
        return this.LayerEdges.length;
    }
    getNode(i) {
        if (i >= 0) {
            if (i < this.LayerEdges.length)
                return this.LayerEdges[i].Source;
            if (i == this.LayerEdges.length)
                return this.LayerEdges[i - 1].Target;
        }
        throw new Error('wrong index ' + i);
    }
    updateEdgeLabelPosition(anchors) {
        if (this.edge.label != null) {
            const m = this.LayerEdges.length / 2;
            const layerEdge = this.LayerEdges[m];
            Routing.updateLabel(this.edge, anchors[layerEdge.Source]);
        }
    }
    [Symbol.iterator]() {
        return this.nodes();
    }
    // enumerates over virtual virtices corresponding to the original edge
    *nodes() {
        yield this.LayerEdges[0].Source;
        for (const le of this.LayerEdges)
            yield le.Target;
    }
}
//# sourceMappingURL=polyIntEdge.js.map