/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Topology
 */
import { Geometry } from "../Geometry";
import { Point3d } from "../geometry3d/Point3dVector3d";
/** Enumeration of categorization of "where" a HalfEdgePositionDetail is sitting in the graph. */
export var HalfEdgeTopo;
(function (HalfEdgeTopo) {
    /** No known position. */
    HalfEdgeTopo[HalfEdgeTopo["None"] = 0] = "None";
    /** Sitting at a vertex, reached by a ray in this sector. */
    HalfEdgeTopo[HalfEdgeTopo["Vertex"] = 1] = "Vertex";
    /** Sitting on an edge. */
    HalfEdgeTopo[HalfEdgeTopo["Edge"] = 2] = "Edge";
    /** Face point (before hitting barrier edge). */
    HalfEdgeTopo[HalfEdgeTopo["Face"] = 3] = "Face";
    /**
     * Exterior point (after hitting barrier edge at fraction).
     * Fraction is 0 if exterior point "in sweep around exterior corner".
    */
    HalfEdgeTopo[HalfEdgeTopo["ExteriorFace"] = 4] = "ExteriorFace";
})(HalfEdgeTopo || (HalfEdgeTopo = {}));
/**
 * Description of a generalized position within a graph, categorized as:
 * * "at a certain node around a vertex"
 * * "at a fractional position along an edge"
 * * "within a face"
 */
export class HalfEdgePositionDetail {
    /** The relevant node. */
    _node;
    /** The current coordinates. */
    x;
    y;
    z;
    /** Fractional position along edge. Only defined if the topo tag is `HalfEdgeTopo.Edge`. */
    _edgeFraction;
    /** Enumeration of status vertex, edge, or face status. */
    _topo;
    /** First data tag. */
    _iTag;
    /** Second data tag. */
    _dTag;
    /** Special case for point on edge or vertex but target beyond and exterior. */
    _isExteriorTarget;
    /**
     * Constructor.
     * * The point is CAPTURED (static `create` methods normally clone their inputs).
     */
    constructor(node, x, y, z, topo, edgeFraction, iTag, dTag, isExteriorTarget) {
        this._node = node;
        this.x = x;
        this.y = y;
        this.z = z;
        this._topo = topo;
        this._edgeFraction = edgeFraction;
        this._iTag = iTag;
        this._dTag = dTag;
        this._isExteriorTarget = isExteriorTarget;
    }
    /** Copy (clones of) all data from other. */
    setFrom(other) {
        this._node = other._node;
        this.x = other.x;
        this.y = other.y;
        this.z = other.z;
        this._topo = other._topo;
        this._edgeFraction = other._edgeFraction;
        this._iTag = other._iTag;
        this._dTag = other._dTag;
    }
    /** Reset to null topo state. */
    resetAsUnknown() {
        this._node = undefined;
        this._topo = HalfEdgeTopo.None;
    }
    /** Create with null data. */
    static create() {
        const detail = new HalfEdgePositionDetail(undefined, 0, 0, 0, HalfEdgeTopo.None);
        return detail;
    }
    getITag() {
        return this._iTag;
    }
    setITag(value) {
        this._iTag = value;
    }
    getDTag() {
        return this._dTag;
    }
    setDTag(value) {
        this._dTag = value;
    }
    getTopo() {
        return this._topo;
    }
    /** Create with node, fraction along edge, marked as "HalfEdgeTopo.Edge".  Compute interpolated xyz on the edge. */
    static createEdgeAtFraction(node, edgeFraction) {
        const node1 = node.faceSuccessor;
        const x = Geometry.interpolate(node.x, edgeFraction, node1.x);
        const y = Geometry.interpolate(node.y, edgeFraction, node1.y);
        const z = Geometry.interpolate(node.z, edgeFraction, node1.z);
        return new HalfEdgePositionDetail(node, x, y, z, HalfEdgeTopo.Edge, edgeFraction);
    }
    /**
     * Reassign contents so this instance becomes a face hit.
     * @param node new node value. If missing, current node is left unchanged.
     * @param xyz new coordinates. if missing, current coordinates are left unchanged.
     */
    resetAsFace(node, xyz) {
        this._topo = HalfEdgeTopo.Face;
        if (node)
            this._node = node;
        if (xyz) {
            this.x = xyz.x;
            this.y = xyz.y;
            this.z = xyz.z;
        }
        this._isExteriorTarget = undefined;
        return this;
    }
    /** Reassign contents so this instance has dTag but no node or HalfEdgeTopo. */
    resetAsUndefinedWithTag(dTag) {
        this._topo = HalfEdgeTopo.None;
        this._dTag = 0;
        this._iTag = 0;
        this._dTag = dTag;
        this._node = undefined;
        this._isExteriorTarget = undefined;
        return this;
    }
    /**
     * Reassign contents so this instance becomes an edge hit.
     * @param node new node value.
     * @param edgeFraction new edge fraction. xyz is recomputed from this edge and its face successor.
     */
    resetAtEdgeAndFraction(node, edgeFraction) {
        this._topo = HalfEdgeTopo.Edge;
        this._node = node;
        const nodeB = node.faceSuccessor;
        this._edgeFraction = edgeFraction;
        this.x = Geometry.interpolate(node.x, edgeFraction, nodeB.x);
        this.y = Geometry.interpolate(node.y, edgeFraction, nodeB.y);
        this.z = Geometry.interpolate(node.z, edgeFraction, nodeB.z);
        this._isExteriorTarget = undefined;
        return this;
    }
    /**
     * Create at a node.
     * * Take xyz from the node.
     */
    static createVertex(node) {
        return new HalfEdgePositionDetail(node, node.x, node.y, node.z, HalfEdgeTopo.Vertex);
    }
    /** Mark as "HalfEdgeTopo.Vertex". */
    resetAsVertex(node) {
        this._topo = HalfEdgeTopo.Vertex;
        this._node = node;
        this._edgeFraction = 0.0;
        this.setXYZFromNode(node);
        this._isExteriorTarget = undefined;
        return this;
    }
    /** Set the flag for an exterior relationship to target. */
    setIsExteriorTarget(isExterior) {
        this._isExteriorTarget = isExterior;
    }
    /** Copy x,y,z from the node to this instance local values. */
    setXYZFromNode(node) {
        this.x = node.x;
        this.y = node.y;
        this.z = node.z;
    }
    /** Return the (possibly undefined) edge fraction. */
    get edgeFraction() {
        return this._edgeFraction;
    }
    /**
     * Property access for the flag for an exterior relationship to target.
     * * undefined flag is returned as false.
     */
    get isExteriorTarget() {
        return this._isExteriorTarget !== undefined ? this._isExteriorTarget : false;
    }
    /** Return true if this detail is marked as being within a face. */
    get isFace() {
        return this._topo === HalfEdgeTopo.Face;
    }
    /** Return true if this detail is marked as being within an edge. */
    get isEdge() {
        return this._topo === HalfEdgeTopo.Edge;
    }
    /** Return true if this detail is marked as being at a vertex. */
    get isVertex() {
        return this._topo === HalfEdgeTopo.Vertex;
    }
    /** Return true if this detail has no vertex, edge, or face qualifier. */
    get isUnclassified() {
        return this._topo === HalfEdgeTopo.None;
    }
    /** Return the node reference from this detail */
    get node() {
        return this._node;
    }
    /** Return the (clone of, or optional filled in result) coordinates from this detail. */
    clonePoint(result) {
        return Point3d.create(this.x, this.y, this.z, result);
    }
    /*
      // If candidateKey is less than resultKey, replace resultPos and resultKey
      // by the candidate data.
      public updateMinimizer(
        HalfEdgePositionDetail & resultPos, number & resultKey,
    : HalfEdgePositionDetail & candidatePos, candidateKey: number
      ): boolean {
        if (candidateKey < resultKey) {
          resultKey = candidateKey;
          resultPos = candidatePos;
          return true;
        }
        return false;
      }
    */
    isAtXY(x, y) {
        return this._topo !== HalfEdgeTopo.None && Geometry.isSameCoordinate(this.x, x) && Geometry.isSameCoordinate(this.y, y);
    }
}
//# sourceMappingURL=HalfEdgePositionDetail.js.map