import {
  Object3D,
  Ray,
  Vector3
} from '../../../src/Three';

declare class Face {
  constructor();
  normal: Vector3;
  midpoint: Vector3;
  area: number;
  constant: number;
  outside: VertexNode;
  mark: number;
  edge: HalfEdge;

  static create(a: VertexNode, b: VertexNode, c: VertexNode): Face;

  compute(): this;
  getEdge(i: number): HalfEdge;
}

declare class HalfEdge {
  constructor(vertex: VertexNode, face: Face);
  vertex: VertexNode;
  prev: HalfEdge;
  next: HalfEdge;
  twin: HalfEdge;
  face: Face;

  head(): VertexNode;
  length(): number;
  lengthSquared(): number;
  setTwin(edge: HalfEdge): this;
  tail(): VertexNode;
}

declare class VertexNode {
  constructor(point: Vector3);
  point: Vector3;
  prev: VertexNode;
  next: VertexNode;
  face: Face;
}

declare class VertexList {
  constructor();
  head: VertexNode;
  tail: VertexNode;

  append(vertex: VertexNode): this;
  appendChain(vertex: VertexNode): this;
  clear(): this;
  first(): VertexNode;
  insertAfter(target: VertexNode, vertex: VertexNode): this;
  insertBefore(target: VertexNode, vertex: VertexNode): this;
  isEmpty(): boolean;
  last(): VertexNode;
  remove(vertex: VertexNode): this;
  removeSubList(a: VertexNode, b: VertexNode): this;
}

export class ConvexHull {
  constructor();
  tolerance: number;
  faces: Face[];
  newFaces: Face[];
  assigned: VertexList;
  unassigned: VertexList;
  vertices: VertexNode[];

  addAdjoiningFace(eyeVertex: VertexNode, horizonEdge: HalfEdge): HalfEdge;
  addNewFaces(eyeVertex: VertexNode, horizon: HalfEdge[]): this;
  addVertexToFace(vertex: VertexNode, face: Face): this;
  addVertexToHull(eyeVertex: VertexNode): this;
  cleanup(): this;
  compute(): this;
  computeExtremes(): object;
  computeHorizon(eyePoint: Vector3, crossEdge: HalfEdge, face: Face, horizon: HalfEdge[]): this;
  computeInitialHull(): this;
  containsPoint(point: Vector3): boolean;
  deleteFaceVertices(face: Face, absorbingFace: Face): this;
  intersectRay(ray: Ray, target: Vector3): Vector3 | null;
  intersectsRay(ray: Ray): boolean;
  makeEmpty(): this;
  nextVertexToAdd(): VertexNode | undefined;
  reindexFaces(): this;
  removeAllVerticesFromFace(face: Face): VertexNode | undefined;
  removeVertexFromFace(vertex: VertexNode, face: Face): this;
  resolveUnassignedPoints(newFaces: Face[]): this;
  setFromPoints(points: Vector3[]): this;
  setFromObject(object: Object3D): this;
}
