import 'babel-polyfill';
import * as POTRACE from 'potrace-js';
import { POTRACE_OPTIONS } from 'doodle3d-core/constants/d2Constants.js';

self.addEventListener('message', (event) => {
  switch (event.data.msg) {
    case 'FLOOD_FILL':
      const { imageData, start, tolerance } = event.data;

      self.postMessage({
        msg: 'FLOOD_FILL',
        status: 'OK',
        traceData: floodFill(imageData, start, tolerance)
      });
      break;

    case 'TRACE':
      const { fill, width, height } = event.data;

      const bitmap = new POTRACE.Bitmap(width, height);
      for (let i = 0; i < fill.length; i ++) {
        const index = fill[i];
        bitmap.data[index] = 1;
      }

      self.postMessage({
        msg: 'TRACE',
        status: 'OK',
        paths: POTRACE.getPaths(POTRACE.traceBitmap(bitmap, POTRACE_OPTIONS))
      });
      break;

    default:
      break;
  }
});

function floodFill(imageData, start, tolerance) {
  const { width, height } = imageData;

  const compairIndex = start.y * width + start.x;
  const stack = [compairIndex];
  const done = { [compairIndex]: true };

  const edge = [];
  const fill = [];

  while (stack.length > 0) {
    const index = stack.pop();

    const value = imageData.data[index];
    const pass = value < tolerance;

    if (!pass) {
      edge.push(index);
      continue;
    }

    fill.push(index);

    const left = index % width !== 0;
    const right = index % width !== width - 1;
    const top = Math.floor(index / width) !== 0;
    const bottom = Math.floor(index / width) !== height - 1;

    const neighbours = [];
    if (left) neighbours.push(index - 1);
    if (right) neighbours.push(index + 1);
    if (top) neighbours.push(index - width);
    if (bottom) neighbours.push(index + width);

    if (neighbours.length !== 4) edge.push(index);

    for (let i = 0; i < neighbours.length; i ++) {
      const neighbourIndex = neighbours[i];

      if (!done[neighbourIndex]) {
        stack.push(neighbourIndex);
      }
      done[neighbourIndex] = true;
    }
  }

  return { edge, fill };
}
