import {Point, ICurve} from '../../..'
import {Polyline} from '../../../math/geometry'
import {Assert} from '../../../utils/assert'
import {CdtTriangle} from '../../ConstrainedDelaunayTriangulation/CdtTriangle'
import {BundleBase} from './BundleBase'
import {MetroNodeInfo} from './MetroNodeInfo'

//  (this needs to be public because it's used elsewhere in an interface implementation)
export class Station {
  constructor(serialNumber: number, isRealNode: boolean, position: Point) {
    this.SerialNumber = serialNumber
    this.IsRealNode = isRealNode
    this.Position = position
  }

  //  id of the station (used for comparison)
  SerialNumber: number

  //  if true the station is a center of an obstacle
  IsRealNode: boolean

  //  radius of the corresponding hub
  Radius = 0

  //  position of the corresponding hub
  Position: Point

  //  neighbors sorted in counter-clockwise order around the station
  Neighbors: Station[]

  //  it maps each neighbor to its hub
  BundleBases: Map<Station, BundleBase> = new Map<Station, BundleBase>()

  //  it maps a node to a set of tight polylines that can contain the node
  EnterableTightPolylines: Set<Polyline>

  //  it maps a node to a set of loose polylines that can contain the node
  EnterableLoosePolylines: Set<Polyline>

  //  MetroNodeInfos corresponding to the node
  MetroNodeInfos: Array<MetroNodeInfo> = new Array<MetroNodeInfo>()

  //  curve of the hub
  BoundaryCurve: ICurve

  public static less(a: Station, b: Station): boolean {
    Assert.assert(a == b || a.SerialNumber != b.SerialNumber)
    return a.SerialNumber < b.SerialNumber
  }

  public static greater(a: Station, b: Station): boolean {
    return a.SerialNumber > b.SerialNumber
  }

  CdtTriangle: CdtTriangle

  cachedRadiusCost: number

  cachedBundleCost: number

  private _cachedIdealRadius = 0
  public get cachedIdealRadius() {
    return this._cachedIdealRadius
  }
  public set cachedIdealRadius(value) {
    Assert.assert(!isNaN(value))
    this._cachedIdealRadius = value
  }

  AddEnterableLoosePolyline(poly: Polyline) {
    if (this.EnterableLoosePolylines == null) {
      this.EnterableLoosePolylines = new Set<Polyline>()
    }

    this.EnterableLoosePolylines.add(poly)
  }

  AddEnterableTightPolyline(poly: Polyline) {
    if (this.EnterableTightPolylines == null) {
      this.EnterableTightPolylines = new Set<Polyline>()
    }

    this.EnterableTightPolylines.add(poly)
  }
}
