import { m as macro } from '../../macros2.js';
import vtkBoundingBox from './BoundingBox.js';
import vtkImplicitFunction from './ImplicitFunction.js';

// ----------------------------------------------------------------------------
// Global methods
// ----------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Bounding box intersection code from David Gobbi.  Go through the
// bounding planes one at a time and compute the parametric coordinate
// of each intersection and return the parametric values and the calculated points
function intersectWithLine(bounds, p1, p2) {
  let plane1 = -1;
  let plane2 = -1;
  let t1 = 0.0;
  let t2 = 1.0;
  for (let j = 0; j < 3; j++) {
    for (let k = 0; k < 2; k++) {
      // Compute distances of p1 and p2 from the plane along the plane normal
      const i = 2 * j + k;
      const d1 = (bounds[i] - p1[j]) * (1 - 2 * k);
      const d2 = (bounds[i] - p2[j]) * (1 - 2 * k);

      // If both distances are positive, both points are outside
      if (d1 > 0 && d2 > 0) {
        return;
      }
      // If one of the distances is positive, the line crosses the plane
      if (d1 > 0 || d2 > 0) {
        // Compute fractional distance "t" of the crossing between p1 & p2
        let t = 0.0;
        if (d1 !== 0) {
          t = d1 / (d1 - d2);
        }

        // If point p1 was clipped, adjust t1
        if (d1 > 0) {
          if (t >= t1) {
            t1 = t;
            plane1 = i;
          }
        }
        // else point p2 was clipped, so adjust t2
        else if (t <= t2) {
          t2 = t;
          plane2 = i;
        }
        // If this happens, there's no line left
        if (t1 > t2) {
          // Allow for planes that are coincident or slightly inverted
          if (plane1 < 0 || plane2 < 0) {
            return;
          }
        }
      }
    }
  }
  function getValues(plane, t) {
    const x = [0, 0, 0];
    for (let count = 0; count < 2; count++) {
      for (let i = 0; i < 3; i++) {
        if (plane === 2 * i || plane === 2 * i + 1) {
          x[i] = bounds[plane];
        } else {
          x[i] = p1[i] * (1.0 - t) + p2[i] * t;
          if (x[i] < bounds[2 * i]) {
            x[i] = bounds[2 * i];
          }
          if (x[i] > bounds[2 * i + 1]) {
            x[i] = bounds[2 * i + 1];
          }
        }
      }
    }
    return x;
  }
  const x1 = getValues(plane1, t1);
  const x2 = getValues(plane2, t2);
  const outObject = {
    t1,
    t2,
    x1,
    x2
  };

  // eslint-disable-next-line consistent-return
  return outObject;
}

// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------

const STATIC = {};

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

  // TODO: replace with macro.setArray ?
  publicAPI.setBounds = function () {
    let boundsArray = [];
    for (var _len = arguments.length, bounds = new Array(_len), _key = 0; _key < _len; _key++) {
      bounds[_key] = arguments[_key];
    }
    if (Array.isArray(bounds[0])) {
      boundsArray = bounds[0];
    } else {
      for (let i = 0; i < bounds.length; i++) {
        boundsArray.push(bounds[i]);
      }
    }
    if (boundsArray.length !== 6) {
      console.log('vtkBox.setBounds', boundsArray, bounds);
      return;
    }
    vtkBoundingBox.setBounds(model.bbox, boundsArray);
  };
  publicAPI.getBounds = () => model.bbox;
  publicAPI.evaluateFunction = (x, y, z) => {
    const point = Array.isArray(x) ? x : [x, y, z];
    let diff;
    let dist;
    let t;
    let minDistance = -Number.MAX_VALUE;
    let distance = 0;
    const minPoint = vtkBoundingBox.getMinPoint(model.bbox);
    const maxPoint = vtkBoundingBox.getMaxPoint(model.bbox);
    let inside = 1;
    for (let i = 0; i < 3; i++) {
      diff = vtkBoundingBox.getLength(model.bbox, i);
      if (diff !== 0.0) {
        t = (point[i] - minPoint[i]) / diff;
        if (t < 0.0) {
          inside = 0;
          dist = minPoint[i] - point[i];
        } else if (t > 1.0) {
          inside = 0;
          dist = point[i] - maxPoint[i];
        } else {
          // want negative distance, we are inside
          if (t <= 0.5) {
            dist = minPoint[i] - point[i];
          } else {
            dist = point[i] - maxPoint[i];
          }
          if (dist > minDistance) {
            // remember, it's negative
            minDistance = dist;
          }
        } // end if inside
      } else {
        dist = Math.abs(point[i] - minPoint[i]);
        if (dist > 0.0) {
          inside = 0;
        }
      }
      if (dist > 0.0) {
        distance += dist * dist;
      }
    } // end for i
    distance = Math.sqrt(distance);
    if (inside) {
      return minDistance;
    }
    return distance;
  };
  publicAPI.addBounds = function () {
    let boundsArray = [];
    if (Array.isArray(arguments.length <= 0 ? undefined : arguments[0])) {
      boundsArray = arguments.length <= 0 ? undefined : arguments[0];
    } else {
      for (let i = 0; i < arguments.length; i++) {
        boundsArray.push(i < 0 || arguments.length <= i ? undefined : arguments[i]);
      }
    }
    if (boundsArray.length !== 6) {
      return;
    }
    vtkBoundingBox.addBounds(model.bbox, ...boundsArray);
    publicAPI.modified();
  };
  publicAPI.addBox = other => publicAPI.addBounds(other.getBounds());
  publicAPI.intersectWithLine = (p1, p2) => intersectWithLine(model.bbox, p1, p2);
}

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

const DEFAULT_VALUES = {
  bbox: [...vtkBoundingBox.INIT_BOUNDS]
};

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

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

  // Object methods
  vtkImplicitFunction.extend(publicAPI, model, initialValues);
  vtkBox(publicAPI, model);
}

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

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

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

var vtkBox$1 = {
  newInstance,
  extend,
  intersectWithLine,
  ...STATIC
};

export { STATIC, vtkBox$1 as default, extend, intersectWithLine, newInstance };
