export class GeometryCallback {
  constructor(viewer, vpXform) {
    this.viewer = viewer;
    this.vpXform = vpXform;
    this.lines = [];
  }

  onLineSegment(x1, y1, x2, y2) {
    let pt1 = new THREE.Vector3().set(x1, y1, 0).applyMatrix4(this.vpXform);
    let pt2 = new THREE.Vector3().set(x2, y2, 0).applyMatrix4(this.vpXform);

    this.lines.push({
      x1: pt1.x, 
      y1: pt1.y,
      x2: pt2.x, 
      y2: pt2.y
    });
  }
}

export function getBounds(dbId, frags) {
  let fragIds = frags.fragments.dbId2fragId[dbId]; 
  if (typeof fragIds === 'number') { 
    fragIds = [fragIds];
  };

  const bounds = fragIds.map(fId => {
    const bound = new THREE.Box3(); 
    const boundsCallback = new Autodesk.Viewing.Private.BoundsCallback(bound);
    const mesh = frags.getVizmesh(fId);
    const vbr = new Autodesk.Viewing.Private.VertexBufferReader(mesh.geometry, viewer.impl.use2dInstancing);
    vbr.enumGeomsForObject(dbId, boundsCallback);
    return bound;
  });

  return bounds; 
}

export function extractPoints(lines) {
  const tolerance = 0.001;
  const allPoints = [];

  for (let i = 0; i < lines.length; i++) {
    const { x1, y1, x2, y2 } = lines[i];
    allPoints.push({ x: x1, y: y1 });
    allPoints.push({ x: x2, y: y2 });
  }

  const pointsDeduped = [];

  for (let i = 0; i < allPoints.length; i++) {
    const element = allPoints[i];
    
    const notFound = !pointsDeduped.find(pt => Math.abs(pt.x - element.x) < tolerance && Math.abs(pt.y - element.y) < tolerance);
    if (notFound) pointsDeduped.push(element);
  }

  return pointsDeduped;
}

export function sortByAngle(points) {
  // Calculate centroid
  const centroid = new THREE.Vector3();
  points.forEach(v => centroid.add(v));
  centroid.divideScalar(points.length);
  
  // Sort by angle around centroid
  return points.slice().sort((a, b) => {
    const angleA = Math.atan2(a.y - centroid.y, a.x - centroid.x);
    const angleB = Math.atan2(b.y - centroid.y, b.x - centroid.x);
    return angleA - angleB;
  });
}

export function getColorByIndex(i) {
  const colors = [
    'magenta',
    'red',
    'orange',
    'yellow',
    'chartreuse',
    'green',
    'blue',
  ]
  if (i === 0) return 'black';
  return colors[i % 7];
}

/**
 * - THREE.Color: `{ r: number, g: number, b: number }`
 * - THREE.Vector4: `{ x: number, y: number, z: number, w: number }`
 * 
 * @param {string} colorStr e.g. `'#ff0000'`, `'white'`, `'hotpink'`
 * @returns A Vector4 object
 */
export function colorStrToVector4(colorStr) {
  const color = new THREE.Color().setStyle(colorStr);
  const vector4 = new THREE.Vector4(color.r, color.g, color.b, 1);
  return vector4;
}
