import type MapView from "../MapView.js";
import type SceneView from "../SceneView.js";
import type Widget from "../../widgets/Widget.js";
import type { EventedAccessor } from "../../core/Evented.js";
import type { Options, ComponentCompatible, MoveOptions, UIPosition } from "./types.js";

export interface UIProperties extends Partial<Pick<UI, "container" | "view">> {
  /**
   * Defines the padding for the UI from the top, left, right, and bottom sides
   * of the container or [View](https://developers.arcgis.com/javascript/latest/references/core/views/View/). If the value is a number,
   * it will be used to pad all sides of the container.
   *
   * @default { left: 15, top: 15, right: 15, bottom: 15 }
   * @example
   * // Setting a single number to this property
   * ui.padding = 0;
   * // is the same as setting it on all properties of the object
   * ui.padding = { top: 0, left: 0, right: 0, bottom: 0 };
   */
  padding?: any | null;
}

/**
 * This class provides a simple interface for [adding](https://developers.arcgis.com/javascript/latest/references/core/views/ui/UI/#add), [moving](https://developers.arcgis.com/javascript/latest/references/core/views/ui/UI/#move) and [removing](https://developers.arcgis.com/javascript/latest/references/core/views/ui/UI/#remove) components from a view's user interface (UI). In most cases, you will work with
 * the view's [DefaultUI](https://developers.arcgis.com/javascript/latest/references/core/views/ui/DefaultUI/) which places default
 * [widgets](https://developers.arcgis.com/javascript/latest/references/core/widgets/Widget/), such as [Zoom](https://developers.arcgis.com/javascript/latest/references/core/widgets/Zoom/) and
 * [Attribution](https://developers.arcgis.com/javascript/latest/references/core/widgets/Attribution/) in the [View](https://developers.arcgis.com/javascript/latest/references/core/views/View/).
 *
 * The UI class provides the API for easily placing HTML elements and widgets within the view. See
 * [DefaultUI](https://developers.arcgis.com/javascript/latest/references/core/views/ui/DefaultUI/) for details on working with this class.
 *
 * @since 4.0
 * @see [SceneView.ui](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/#ui)
 * @see [MapView.ui](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/#ui)
 * @see [Guide - Localization](https://developers.arcgis.com/javascript/latest/localization/)
 */
export default class UI extends EventedAccessor {
  constructor(properties?: UIProperties);
  /**
   * The HTML Element that contains the view.
   *
   * @see [SceneView.container](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/#container)
   * @see [View2D.container](https://developers.arcgis.com/javascript/latest/references/core/views/View2D/#container) for MapView and LinkChartView
   */
  accessor container: HTMLElement | null | undefined;
  /** The height of the UI container. */
  get height(): number;
  /**
   * Defines the padding for the UI from the top, left, right, and bottom sides
   * of the container or [View](https://developers.arcgis.com/javascript/latest/references/core/views/View/). If the value is a number,
   * it will be used to pad all sides of the container.
   *
   * @default { left: 15, top: 15, right: 15, bottom: 15 }
   * @example
   * // Setting a single number to this property
   * ui.padding = 0;
   * // is the same as setting it on all properties of the object
   * ui.padding = { top: 0, left: 0, right: 0, bottom: 0 };
   */
  get padding(): any;
  set padding(value: any | null | undefined);
  /** The view associated with the UI components. */
  accessor view: MapView | SceneView;
  /** The width of the UI container. */
  get width(): number;
  /**
   * Adds one or more HTML component(s) or [widgets](https://developers.arcgis.com/javascript/latest/references/core/widgets/Widget/) to the UI.
   *
   * @param component - The component(s) to add to the UI. This can be a widget instance, HTML element, a string value representing
   * a DOM node ID, or an array containing a combination of any of those types. See the example snippets below
   * for code examples. Alternatively, you can pass an array of objects with the following specification.
   * @param position - The position in the view at which to add the component.
   *                                     If not specified, `manual` is used by default. Using `manual` allows you to place the component in a
   *                                     container where you can position it anywhere using css. For the other possible values, "top", "bottom", "left",
   *                                     and "right" are consistent placements. The "leading" and "trailing" values depend on whether the browser is using
   *                                     right-to-left (RTL) or left-to-right (LTR). For LTR, "leading" is left and "trailing" is right.
   *                                     For RTL, "leading" is right and "trailing" is left.
   * @example
   * let toggle = new BasemapToggle({
   *   view: view,
   *   nextBasemap: "hybrid"
   * });
   * // Adds an instance of BasemapToggle widget to the
   * // top right of the view's container.
   * view.ui.add(toggle, "top-right");
   * @example
   * // Adds multiple widgets to the top right of the view
   * view.ui.add([ compass, toggle ], "top-leading");
   * @example
   * // Adds multiple components of different types to the bottom left of the view
   * view.ui.add([ searchWidget, "infoDiv" ], "bottom-left");
   * @example
   * // Adds multiple components of various types to different view positions
   * view.ui.add([
   *   {
   *     component: compassWidget,
   *     position: "top-left",
   *     index: 0
   *   }, {
   *     component: "infoDiv",
   *     position: "bottom-trailing"
   *   }, {
   *     component: searchWidget,
   *     position: "top-right",
   *     index: 0
   *   }, {
   *     component: legendWidgetDomNode,
   *     position: "top-right",
   *     index: 1
   *   }
   * ]);
   */
  add(component: Widget | HTMLElement | string | any[] | ComponentCompatible, position?: string | UIPosition | Options): void;
  /**
   * Removes all components from a given position.
   *
   * @param position - The position in the view at which to add the component.
   *                                     If not specified, `manual` is used by default. Using `manual` allows you to place the component in a
   *                                     container where you can position it anywhere using css. For the other possible values, "top", "bottom", "left",
   *                                     and "right" are consistent placements. The "leading" and "trailing" values depend on whether the browser is using
   *                                     right-to-left (RTL) or left-to-right (LTR). For LTR, "leading" is left and "trailing" is right.
   *                                     For RTL, "leading" is right and "trailing" is left.
   * @example
   * // Removes all of the elements in the top-left of the view's container
   * // including the default widgets zoom and compass (if working in SceneView)
   * view.ui.empty("top-left");
   */
  empty(position?: UIPosition): void;
  /**
   * Find a component by widget or DOM ID.
   *
   * @param id - The component's ID.
   * @returns Returns the Widget or HTMLElement if the id is found, otherwise returns `null`.
   * @example
   * let compassWidget = new Compass({
   *   view: view,
   *   id: "myCompassWidget" // set an id to get the widget with find
   * });
   *
   * // Add the Compass widget to the top left corner of the view
   * view.ui.add(compassWidget, "top-left");
   *
   * // Find the Widget with the specified ID
   * let compassWidgetFind = view.ui.find("myCompassWidget"))
   */
  find(id: string): Widget | HTMLElement | null | undefined;
  /**
   * Returns all widgets and/or HTML elements in the view, or only components at specified positions in the view.
   *
   * @param position - The position or array of positions from which to fetch the components. If not specified, all components will be returned from the View.
   * @returns Returns an array of Widgets and/or HTML elements in the View.
   * @since 4.27
   * @example
   * // Display the number of components added to MapView by default.
   * const view = new MapView({
   *   map,
   *   container: "viewDiv",
   *   zoom: 4,
   *   center: [-100, 35]
   * });
   * await view.when();
   * const components = view.ui.getComponents();
   * console.log(`There are ${components.length} components added to MapView.`); // There are 4 components added to MapView.
   * @example
   * // Display the label of the first manually placed widget in SceneView.
   * const view = new SceneView({
   *   map,
   *   container: "viewDiv",
   *   zoom: 4,
   *   center: [-100, 35]
   * });
   * await view.when();
   * console.log("Widget label is: ${view.ui.getComponents("manual")[0].label}.`); // Widget label is: Attribution.
   * @example
   * // Display how many components (i.e. widgets or HTMLElements) are placed in the top-left corner of the View.
   * const view = new MapView({
   *   map,
   *   container: "viewDiv",
   *   zoom: 4,
   *   center: [-100, 35]
   * });
   * await view.when();
   * const components = view.ui.getComponents("top-left");
   * console.log(`There is/are ${components.length} component(s) located in MapView's top-left corner.`);
   * // There is/are 1 component(s) located in MapView's top-left corner.
   */
  getComponents(position?: UIPosition | UIPosition[]): (Widget<any> | HTMLElement)[];
  /**
   * Moves one or more UI component(s) to the specified position.
   *
   * @param component - The component(s) to move.
   * This value can be a widget instance, HTML element, a string value representing
   * a DOM node ID, or an array containing a combination of any of those types. See the example snippets below
   * for code examples. Alternatively, you can pass an array of objects with the following specification.
   * @param position - The destination position. The component will be placed
   *                            in the UI [container](https://developers.arcgis.com/javascript/latest/references/core/views/ui/UI/#container) when not provided.
   * @example
   * // Moves the BasemapToggle widget from the view if added.
   * // See the example for add() for more context
   * view.ui.move(toggle, "bottom-leading");
   * @example
   * // Moves the default zoom widget to the bottom left corner of the view's container
   * view.ui.move("zoom", "bottom-left");
   * @example
   * // Moves multiple widgets to the bottom right of the view's UI
   * view.ui.move([ compass, toggle, "zoom" ], "bottom-right");
   * @example
   * // Moves the legend to the topmost position in the top-right corner of the view's UI.
   * view.ui.move({component: legend, position: "top-right", index: 0});
   */
  move(component: ComponentCompatible | ComponentCompatible[], position?: UIPosition | MoveOptions): void;
  /**
   * Removes one or more HTML component(s) or [widgets](https://developers.arcgis.com/javascript/latest/references/core/widgets/Widget/) from the UI.
   *
   * @param component - The component(s) to remove from the UI. This can be a widget instance, HTML element, a string value representing
   * a DOM node ID, or an array containing a combination of any of those types. See the example snippets below
   * for code examples.
   * @example
   * // Removes the BasemapToggle widget from the view if added.
   * // See the example for add() for more context
   * view.ui.remove(toggle);
   * @example
   * // Removes the default zoom widget from the view's container
   * view.ui.remove("zoom");
   * @example
   * // Removes multiple widgets from the view's UI
   * view.ui.remove([ compass, toggle, "zoom" ]);
   */
  remove(component: ComponentCompatible | ComponentCompatible[]): void;
}