import type AreaMeasurement2D from "./AreaMeasurement2D.js";
import type AreaMeasurement3D from "./AreaMeasurement3D.js";
import type DirectLineMeasurement3D from "./DirectLineMeasurement3D.js";
import type DistanceMeasurement2D from "./DistanceMeasurement2D.js";
import type Widget from "./Widget.js";
import type MeasurementViewModel from "./Measurement/MeasurementViewModel.js";
import type { Icon } from "@esri/calcite-components/components/calcite-icon";
import type { SystemOrAreaUnit, SystemOrLengthUnit } from "../core/units.js";
import type { MapViewOrSceneView } from "../views/MapViewOrSceneView.js";
import type { MeasurementComponentType } from "./Measurement/types.js";
import type { MeasurementViewModelProperties } from "./Measurement/MeasurementViewModel.js";
import type { WidgetProperties } from "./Widget.js";

export interface MeasurementProperties extends WidgetProperties, Partial<Pick<Measurement, "activeTool" | "areaUnit" | "linearUnit" | "view">> {
  /**
   * Icon which represents the widget. It is typically used when the widget is controlled by another
   * one (e.g. in the Expand widget).
   *
   * @default "measure"
   * @since 4.27
   * @see [Calcite Icon Search](https://developers.arcgis.com/calcite-design-system/icons/)
   * @see [Calcite Icon Search](https://developers.arcgis.com/calcite-design-system/icons/)
   */
  icon?: Icon["icon"] | null;
  /**
   * The widget's default label. This property is useful whenever the widget is controlled by another one
   * (e.g. [Expand](https://developers.arcgis.com/javascript/latest/references/core/widgets/Expand/)).
   *
   * @since 4.11
   */
  label?: string | null;
  /**
   * The view model for this widget. This is a class that contains all the logic
   * (properties and methods) that controls this widget's behavior. See the
   * [MeasurementViewModel](https://developers.arcgis.com/javascript/latest/references/core/widgets/Measurement/MeasurementViewModel/) class to access
   * all properties and methods on the widget.
   *
   * @example
   * // Initialize a measurement widget using the view model.
   * const measurement = new Measurement({
   *   viewModel: {
   *     view: view,
   *     activeTool: "distance",
   *     unit: "yards"
   *   }
   * });
   */
  viewModel?: MeasurementViewModelProperties;
}

export type AreaMeasurement = AreaMeasurement2D | AreaMeasurement3D;

export type DistanceMeasurement = DistanceMeasurement2D | DirectLineMeasurement3D;

export type MeasurementWidget = AreaMeasurement | DistanceMeasurement;

/**
 * The Measurement widget groups and manages multiple measurement tools and allows you to easily switch between them using
 * the [activeTool](https://developers.arcgis.com/javascript/latest/references/core/widgets/Measurement/#activeTool) property. The tools correspond to the measurement widgets for area and distance in 2D
 * ([AreaMeasurement2D](https://developers.arcgis.com/javascript/latest/references/core/widgets/AreaMeasurement2D/), [DistanceMeasurement2D](https://developers.arcgis.com/javascript/latest/references/core/widgets/DistanceMeasurement2D/)) and in 3D
 * ([AreaMeasurement3D](https://developers.arcgis.com/javascript/latest/references/core/widgets/AreaMeasurement3D/), [DirectLineMeasurement3D](https://developers.arcgis.com/javascript/latest/references/core/widgets/DirectLineMeasurement3D/)).
 *
 * This widget follows a composite pattern that allows developers to configure the UI to best match their specific requirements.
 * The measurement tools, placements, and icons can all be configured, which offers great flexibility to use with tabbed
 * interfaces or other customized UI. See the [Measurement widget sample](https://developers.arcgis.com/javascript/latest/sample-code/widgets-measurement/)
 * for an example of this flexibility.
 *
 * [![measurement-widget](https://developers.arcgis.com/javascript/latest/assets/references/core/widgets/measurement_widget_2D_distance_3D_area.png)](https://developers.arcgis.com/javascript/latest/sample-code/widgets-measurement/)
 *
 * How distances, areas, and perimeters are computed depends on the view type and its spatial reference.
 *
 * In 2D MapViews:
 * - In geographic coordinate systems (GCS) and in Web Mercator, they are computed geodetically.
 * - In projected coordinate systems (PCS), apart from Web Mercator, they are computed
 *   in a Euclidean manner (in their respective PCS).
 *
 * In 3D SceneViews:
 * - In geographic coordinate systems (GCS) and in Web Mercator:
 *   - horizontal distance is computed geodetically;
 *   - vertical distance is computed as a difference in z-values;
 *   - direct distance is computed in a Euclidean manner;
 *   - area and perimeter are computed:
 *     - in a Euclidean manner if the perimeter is below 100km;
 *     - geodetically if the perimeter is above 100km.
 * - In projected coordinate systems (PCS), apart from Web Mercator:
 *   - all three distances (direct, horizontal, and vertical), areas, and perimeters are computed in
 *     a Euclidean manner (in their respective PCS).
 *
 * @deprecated since version 5.0. Use the [Area Measurement 2D](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-area-measurement-2d/), [Area Measurement 3D](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-area-measurement-3d/), [Direct Line Measurement 3D](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-direct-line-measurement-3d/), or [Distance Measurement 2D](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-distance-measurement-2d/) components instead. For information on widget deprecation, read about [Esri's move to web components](https://developers.arcgis.com/javascript/latest/components-transition-plan/).
 * @since 4.13
 * @see [MeasurementViewModel](https://developers.arcgis.com/javascript/latest/references/core/widgets/Measurement/MeasurementViewModel/)
 * @see [Sample - Measurement widget](https://developers.arcgis.com/javascript/latest/sample-code/widgets-measurement/)
 * @see [DefaultUI](https://developers.arcgis.com/javascript/latest/references/core/views/ui/DefaultUI/)
 * @see [AreaMeasurement2D](https://developers.arcgis.com/javascript/latest/references/core/widgets/AreaMeasurement2D/)
 * @see [DistanceMeasurement2D](https://developers.arcgis.com/javascript/latest/references/core/widgets/DistanceMeasurement2D/)
 * @see [AreaMeasurement3D](https://developers.arcgis.com/javascript/latest/references/core/widgets/AreaMeasurement3D/)
 * @see [DirectLineMeasurement3D](https://developers.arcgis.com/javascript/latest/references/core/widgets/DirectLineMeasurement3D/)
 * @example
 * // Add the measurement widget to the upper right hand corner
 * // with the distance tool active
 * const map = new Map({
 *   basemap: "hybrid"
 * });
 *
 * const view = new MapView({
 *   container: "viewDiv",
 *   map: map,
 *   center: [-71.69, 43.76],
 *   zoom: 15
 * });
 *
 * const measurement = new Measurement({
 *   view: view,
 *   activeTool: "distance"
 * });
 * view.ui.add(measurement, "top-right");
 *
 * // Switch between area and distance measurement
 * function switchTool() {
 *  const tool = measurement.activeTool === "distance" ? "area" : "distance";
 *  measurement.activeTool = tool;
 * }
 */
export default class Measurement extends Widget {
  constructor(properties?: MeasurementProperties);
  /**
   * Specifies the current measurement tool to display. Setting its value to `area` activates
   * the area measurement tool and it works for both [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/) and
   * [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/). To measure distance in a [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/)
   * set the property to `distance` and in a [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/) set it to `direct-line`.
   * If this property is not set, the widget will not be displayed.
   *
   * @example
   * // To create the Measurement widget with SceneView's direct-line tool active.
   * const measurement = new Measurement({
   *   view: view,
   *   activeTool: "direct-line"
   * });
   *
   * // To switch between direct line and area measurement tools
   * function switchTool() {
   *  const tool = measurement.activeTool === "direct-line" ? "area" : "direct-line";
   *  measurement.activeTool = tool;
   * }
   */
  accessor activeTool: MeasurementComponentType | null | undefined;
  /**
   * The measurement widget that is currently being used. Use this property to
   * get access to the active widget.
   *
   * @example
   * // Print the active widget to the console.
   * const measurement = new Measurement({
   *   view: view,
   *   activeTool: "distance"
   * });
   * view.ui.add(measurement, "top-right");
   * console.log("Active Widget: ", measurement.activeWidget);
   */
  get activeWidget(): MeasurementWidget | null | undefined;
  /**
   * Unit system (imperial, metric) or specific unit used for displaying the area values.
   * Possible values are: `metric`, `imperial`, `square-inches`, `square-feet`, `square-us-feet`, `square-yards`, `square-miles`, `square-nautical-miles`, `square-meters`, `square-kilometers`, `acres`, `ares`, `hectares`.
   *
   * @example
   * // To create the Measurement widget that displays area in square US feet
   * const measurement = new Measurement({
   *   view: view,
   *   activeTool: "area",
   *   areaUnit: "square-us-feet"
   * });
   *
   * // To display the current area measurement unit
   * console.log("Current unit: ", measurement.areaUnit);
   */
  accessor areaUnit: SystemOrAreaUnit;
  /**
   * Icon which represents the widget. It is typically used when the widget is controlled by another
   * one (e.g. in the Expand widget).
   *
   * @default "measure"
   * @since 4.27
   * @see [Calcite Icon Search](https://developers.arcgis.com/calcite-design-system/icons/)
   * @see [Calcite Icon Search](https://developers.arcgis.com/calcite-design-system/icons/)
   */
  get icon(): Icon["icon"];
  set icon(value: Icon["icon"] | null | undefined);
  /**
   * The widget's default label. This property is useful whenever the widget is controlled by another one
   * (e.g. [Expand](https://developers.arcgis.com/javascript/latest/references/core/widgets/Expand/)).
   *
   * @since 4.11
   */
  get label(): string;
  set label(value: string | null | undefined);
  /**
   * Unit system (imperial, metric) or specific unit used for displaying the distance values.
   * Possible values are: `metric`, `imperial`, `inches`, `feet`, `us-feet`, `yards`, `miles`, `nautical-miles`, `meters`, `kilometers`.
   *
   * @example
   * // To create the Measurement widget that displays distance in yards
   * const measurement = new Measurement({
   *   view: view,
   *   activeTool: "distance",
   *   linearUnit: "yards"
   * });
   *
   * // To display the current linear measurement unit
   * console.log('Current linear unit: ', measurement.linearUnit);
   */
  accessor linearUnit: SystemOrLengthUnit;
  /**
   * A reference to the [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/) or [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
   * Set this to link the widget to a specific view.
   *
   * @example
   * // To create the Measurement widget for SceneView with the direct-line tool active.
   * const measurement = new Measurement({
   *   view: sceneView,
   *   activeTool: "direct-line"
   * });
   */
  accessor view: MapViewOrSceneView | null | undefined;
  /**
   * The view model for this widget. This is a class that contains all the logic
   * (properties and methods) that controls this widget's behavior. See the
   * [MeasurementViewModel](https://developers.arcgis.com/javascript/latest/references/core/widgets/Measurement/MeasurementViewModel/) class to access
   * all properties and methods on the widget.
   *
   * @example
   * // Initialize a measurement widget using the view model.
   * const measurement = new Measurement({
   *   viewModel: {
   *     view: view,
   *     activeTool: "distance",
   *     unit: "yards"
   *   }
   * });
   */
  get viewModel(): MeasurementViewModel;
  set viewModel(value: MeasurementViewModelProperties);
  /** Removes all measurement widgets and associated graphics. */
  clear(): void;
  /**
   * Starts a new measurement for the active measurement widget.
   *
   * @example
   * const measurement = new Measurement({
   *   view: view,
   *   activeTool: "distance"
   * });
   *
   * function measure () {
   *   measurement.startMeasurement();
   * }
   *
   * measure();
   */
  startMeasurement(): void;
}