import { m as macro } from '../../macros2.js';
import vtkCellArray from '../../Common/Core/CellArray.js';
import vtkPolyData from '../../Common/DataModel/PolyData.js';

const {
  vtkErrorMacro
} = macro;
class SegmentAgregator {
  constructor() {
    this.segmentMapping = {};
    this.segments = [null]; // to force first id to be 1
    this.faces = [];
  }
  addSegment(segment) {
    const first = segment[0];
    const last = segment[segment.length - 1];
    if (first === last || segment.length < 2) {
      return;
    }
    const mappingFirst = this.segmentMapping[first];
    const mappingLast = this.segmentMapping[last];
    if (mappingFirst !== undefined && mappingLast !== undefined) {
      if (Math.abs(mappingFirst) === Math.abs(mappingLast)) {
        // This make a closing loop
        const idx = mappingFirst < mappingLast ? mappingLast : mappingFirst;
        const seg = this.segments[idx];
        if (mappingFirst > 0) {
          for (let i = 1; i < segment.length - 1; i++) {
            seg.push(segment[i]);
          }
        } else {
          for (let i = 1; i < segment.length - 1; i++) {
            seg.unshift(segment[segment.length - 1 - i]);
          }
        }
        this.faces.push(seg);
        this.segments[idx] = null;
        this.segmentMapping[first] = undefined;
        this.segmentMapping[last] = undefined;
      } else {
        // we need to merge segments
        // strategie:
        // => remove and add them again in special order to induce merge
        const idxHead = Math.abs(mappingFirst);
        const idxTail = Math.abs(mappingLast);
        const segHead = this.segments[idxHead];
        const segTail = this.segments[idxTail];
        this.segments[idxHead] = null;
        this.segments[idxTail] = null;
        this.segmentMapping[segHead[0]] = undefined;
        this.segmentMapping[segTail[0]] = undefined;
        this.segmentMapping[segHead[segHead.length - 1]] = undefined;
        this.segmentMapping[segTail[segTail.length - 1]] = undefined;

        // This will lead to a single segment
        this.addSegment(segment);
        this.addSegment(segHead);
        this.addSegment(segTail);
      }
    } else if (mappingFirst !== undefined) {
      if (mappingFirst > 0) {
        // The head of our segment match the tail of the existing one
        const seg = this.segments[mappingFirst];
        for (let i = 1; i < segment.length; i++) {
          seg.push(segment[i]);
        }
        // record new tail
        this.segmentMapping[last] = mappingFirst;
      } else {
        // our segment should be reverted and put on the front of the existing one
        const seg = this.segments[-mappingFirst];
        // record new head
        this.segmentMapping[last] = mappingFirst;
        for (let i = 1; i < segment.length; i++) {
          seg.unshift(segment[i]);
        }
      }
      // Erase used connection
      this.segmentMapping[first] = undefined;
    } else if (mappingLast !== undefined) {
      if (mappingLast > 0) {
        // The tail of our segment match the tail of the existing one
        const seg = this.segments[mappingLast];
        for (let i = 1; i < segment.length; i++) {
          seg.push(segment[segment.length - 1 - i]);
        }
        // record new tail
        this.segmentMapping[first] = mappingLast;
      } else {
        // our segment should be reverted and put on the front of the existing one
        const seg = this.segments[-mappingLast];

        // record new head
        this.segmentMapping[first] = mappingLast;
        for (let i = 1; i < segment.length; i++) {
          seg.unshift(segment[segment.length - i - 1]);
        }
      }
      // Erase used connection
      this.segmentMapping[last] = undefined;
    } else {
      // store segment for now
      const id = this.segments.length;
      this.segments.push(segment);
      this.segmentMapping[first] = -id;
      this.segmentMapping[last] = id;
    }
  }
}

// ----------------------------------------------------------------------------
// vtkClosedPolyLineToSurfaceFilter methods
// ----------------------------------------------------------------------------

function vtkClosedPolyLineToSurfaceFilter(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkClosedPolyLineToSurfaceFilter');

  // --------------------------------------------------------------------------

  publicAPI.requestData = (inData, outData) => {
    // implement requestData
    const input = inData[0];
    if (!input) {
      vtkErrorMacro('Invalid or missing input');
      return;
    }
    const output = vtkPolyData.newInstance();
    output.shallowCopy(input);

    // Extract faces
    const agregator = new SegmentAgregator();
    const lines = input.getLines().getData();
    let offset = 0;
    while (offset < lines.length) {
      const lineSize = lines[offset++];
      const lineSegment = [];
      for (let i = 0; i < lineSize; i++) {
        lineSegment.push(lines[offset + i]);
      }
      agregator.addSegment(lineSegment);
      offset += lineSize;
    }

    // Create CellArray for polys
    const {
      faces
    } = agregator;
    let cellArraySize = faces.length;
    for (let i = 0; i < faces.length; i++) {
      cellArraySize += faces[i].length;
    }
    const cellArray = new Uint16Array(cellArraySize);
    offset = 0;
    for (let i = 0; i < faces.length; i++) {
      const face = faces[i];
      cellArray[offset++] = face.length;
      for (let j = 0; j < face.length; j++) {
        cellArray[offset++] = face[j];
      }
    }
    output.setPolys(vtkCellArray.newInstance({
      values: cellArray,
      name: 'faces'
    }));
    outData[0] = output;
  };
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {};

// ----------------------------------------------------------------------------

function extend(publicAPI, model) {
  let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Make this a VTK object
  macro.obj(publicAPI, model);

  // Also make it an algorithm with one input and one output
  macro.algo(publicAPI, model, 1, 1);

  // Object specific methods
  vtkClosedPolyLineToSurfaceFilter(publicAPI, model);
}

// ----------------------------------------------------------------------------

const newInstance = macro.newInstance(extend, 'vtkClosedPolyLineToSurfaceFilter');

// ----------------------------------------------------------------------------

var vtkClosedPolyLineToSurfaceFilter$1 = {
  newInstance,
  extend
};

export { vtkClosedPolyLineToSurfaceFilter$1 as default, extend, newInstance };
