import { isObject, isFunc } from '../core.mjs';
import { createLineSegments, create3DLineMaterial } from '../base/base3d.mjs';
import { drawDummy3DGeom } from '../geom/TGeoPainter.mjs';
import { drawPolyMarker3D as drawPolyMarker3Dplain } from './TPolyMarker3D.mjs';


/** @summary Prepare frame painter for 3D drawing
  * @private */
function before3DDraw(painter) {
   const fp = painter.getFramePainter();

   if (!fp?.mode3d || !painter.getObject())
      return null;

   if (fp?.toplevel)
      return fp;

   const main = painter.getMainPainter();

   if (main && !isFunc(main.drawExtras))
      return null;

   const pr = main ? Promise.resolve(main) : drawDummy3DGeom(painter);

   return pr.then(geop => {
      const pp = painter.getPadPainter();
      if (pp)
         pp.options._disable_dragging = true;

      if (geop.options.dummy && isFunc(painter.get3DBox))
         geop.extendCustomBoundingBox(painter.get3DBox());
      return geop.drawExtras(painter.getObject(), '', true, true);
   });
}

/** @summary Function to extract 3DBox for poly marker and line
  * @private */
function get3DBox() {
   const obj = this.getObject();
   if (!obj?.fP.length)
      return null;
   const box = { min: { x: 0, y: 0, z: 0 }, max: { x: 0, y: 0, z: 0 } };

   for (let k = 0; k < obj.fP.length; k += 3) {
      const x = obj.fP[k],
            y = obj.fP[k + 1],
            z = obj.fP[k + 2];
      if (k === 0) {
         box.min.x = box.max.x = x;
         box.min.y = box.max.y = y;
         box.min.z = box.max.z = z;
      } else {
         box.min.x = Math.min(x, box.min.x);
         box.max.x = Math.max(x, box.max.x);
         box.min.y = Math.min(y, box.min.y);
         box.max.y = Math.max(y, box.max.y);
         box.min.z = Math.min(z, box.min.z);
         box.max.z = Math.max(z, box.max.z);
      }
   }

   return box;
}


/** @summary direct draw function for TPolyMarker3D object (optionally with geo painter)
  * @private */
async function drawPolyMarker3D() {
   this.get3DBox = get3DBox;

   const fp = before3DDraw(this);

   if (!isObject(fp) || !fp.grx || !fp.gry || !fp.grz)
      return fp;

   this.$fp = fp;

   return drawPolyMarker3Dplain.bind(this)();
}

/** @summary Direct draw function for TPolyLine3D object
  * @desc Takes into account dashed properties
  * @private */
async function drawPolyLine3D() {
   this.get3DBox = get3DBox;

   const line = this.getObject(),
         fp = before3DDraw(this);

   if (!isObject(fp) || !fp.grx || !fp.gry || !fp.grz)
      return fp;

   const limit = 3 * line.fN, p = line.fP, pnts = [];

   for (let n = 3; n < limit; n += 3) {
      pnts.push(fp.grx(p[n - 3]), fp.gry(p[n - 2]), fp.grz(p[n - 1]),
                fp.grx(p[n]), fp.gry(p[n + 1]), fp.grz(p[n + 2]));
   }

   const lines = createLineSegments(pnts, create3DLineMaterial(this, line));

   fp.add3DMesh(lines, this, true);

   fp.render3D(100);

   return true;
}

export { drawPolyMarker3D, drawPolyLine3D };
