///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
//   This application incorporates Open Design Alliance software pursuant to a
//   license agreement with Open Design Alliance.
//   Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
//   All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
import { Matrix3d, OdTvPlane, Point3d, Vector3d } from "./Geometry";

export type ViewParams = {
  position: number[];
  target: number[];
  upVector: number[];
  viewFieldWidth: number;
  viewFieldHeight: number;
  perspective: boolean;
};

export class OdaGeAction {
  protected m_module;

  constructor(module: any) {
    this.m_module = module;
  }

  protected getViewer(): any {
    return this.m_module.getViewer();
  }

  protected getModel(): any {
    return this.getViewer().getMarkupModel();
  }

  protected copyPoint(point: Point3d): Point3d {
    const p: Point3d = new this.m_module.Point3d();
    p.set(point.x, point.y, point.z);
    return p;
  }

  protected createVector3d(): Vector3d {
    return new this.m_module.Vector3d();
  }

  protected createPoint3d(): Point3d {
    return new this.m_module.Point3d();
  }

  protected createMatrix3d(): Matrix3d {
    return new this.m_module.Matrix3d();
  }

  protected createPlane(): OdTvPlane {
    return new this.m_module.OdTvPlane();
  }

  protected toVector(geVector): Vector3d {
    return this.m_module.Vector3d.createFromArray(geVector);
  }

  protected toGeVector(v: Vector3d): number[] {
    return [v.x, v.y, v.z];
  }

  protected toGePoint(point: Point3d): number[] {
    return [point.x, point.y, point.z];
  }

  protected toPoint(gePoint: number[]): Point3d {
    return this.m_module.Point3d.createFromArray(gePoint);
  }

  protected screenToWorld(x: number, y: number): Point3d {
    return this.toPoint(this.m_module.getViewer().screenToWorld(x, y));
  }

  protected toDoubleArray(points: Point3d[]): number[] {
    const p: number[] = [];
    for (let i = 0; i < points.length; i++) {
      p.push(points[i].x);
      p.push(points[i].y);
      p.push(points[i].z);
    }
    return p;
  }

  protected correctCameraTarget(): void {
    const params = this.getViewParams();
    const ext = this.m_module.getViewer().getActiveExtents();
    const { min, max } = ext;
    const target = this.toPoint(params.target);

    const contains =
      target.x >= min.x &&
      target.y >= min.y &&
      target.z >= min.z &&
      target.x <= max.x &&
      target.y <= max.y &&
      target.z <= max.z;
    if (!contains) {
      params.target = ext.center();
      this.setViewParams(params);
    }
  }

  protected setViewParams = (params: ViewParams) => {
    const extView = this.m_module.getViewer().getActiveTvExtendedView();
    extView.setView(
      params.position,
      params.target,
      params.upVector,
      params.viewFieldWidth,
      params.viewFieldHeight,
      params.perspective
    );
    extView.delete?.();
  };

  protected getViewParams = () => {
    const view = this.m_module.getViewer().activeView;
    const obj = {
      position: view.viewPosition,
      target: view.viewTarget,
      upVector: view.upVector,
      viewFieldWidth: view.viewFieldWidth,
      viewFieldHeight: view.viewFieldHeight,
      perspective: view.perspective,
    } as ViewParams;
    view.delete?.();
    return obj;
  };
}
