import type Extent from "../geometry/Extent.js";
import type Layer from "./Layer.js";
import type { EsriPromiseMixin } from "../core/Promise.js";
import type { AbortOptions } from "../core/promiseUtils.js";
import type { BlendLayer, BlendLayerProperties } from "./mixins/BlendLayer.js";
import type { RefreshableLayer, RefreshableLayerProperties } from "./mixins/RefreshableLayer.js";
import type { ScaleRangeLayer, ScaleRangeLayerProperties } from "./mixins/ScaleRangeLayer.js";
import type { LayerProperties } from "./Layer.js";

export interface BaseDynamicLayerProperties extends LayerProperties, RefreshableLayerProperties, ScaleRangeLayerProperties, BlendLayerProperties {}

/**
 * This class may be extended to create dynamic map layers. Dynamic layers display
 * an image dynamically generated on the server based on a request, including the
 * extent and size of the image. The exported image covers the entire view extent.
 * Each interaction on the view (e.g. panning, zooming) will result in an export of
 * a new image on the server.
 * Each export is unique so it cannot be cached in the browser.
 *
 * You can create a custom [DynamicLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/) by calling its
 * [Accessor.createSubclass()](https://developers.arcgis.com/javascript/latest/references/core/core/Accessor/#createSubclass)
 * method. You may create a custom dynamic layer for one of the following reasons:
 *
 * * The source of the images isn't explicitly supported by the ArcGIS Maps SDK for JavaScript
 * * Images need to be preprocessed prior to display in the view
 *
 * ### Request images as they are defined
 *
 * To request images as they are predefined from a data source, overwrite the [getImageUrl()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#getImageUrl)
 * method so it returns the URL for the requested tile for a given level, row and column.
 *
 * ```js
 * let MyCustomDynamicLayer = BaseDynamicLayer.createSubclass({
 *  // properties of the custom dynamic layer
 *  properties: {
 *    getMapUrl: null,
 *    getMapParameters: null
 *  },
 *
 *  // override getImageUrl() to generate URL to the image
 *  getImageUrl: function (extent, width, height) {
 *    // generate the URL for the map image
 *    let urlVariables = this._prepareQuery(this.getMapParameters, extent, width, height);
 *    let queryString = this._joinUrlVariables(urlVariables);
 *
 *    // return the URL to the generated image
 *    return this.getMapUrl + "?" + queryString;
 *  },
 *  ...
 * });
 * ```
 * See the [Custom DynamicLayer sample](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-dynamiclayer/)
 * for an example of this workflow.
 *
 * ### Preprocess images prior to display
 *
 * If data needs to be preprocessed prior to display, then override the [fetchImage()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#fetchImage)
 * method to generate
 * an [html image element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement) or
 * [canvas element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement) by
 * processing the data returned by the server. For example, if you need to apply a
 * [compositing operation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)
 * to the image returned from the server before the image is displayed then you would
 * override this method.
 *
 * ```js
 * // Fetches images for given extent and size
 * fetchImage: function (extent, width, height){
 *   let url = this.getImageUrl(extent, width, height);
 *
 *   // request for the image  based on the generated url
 *   return esriRequest(url, {
 *     responseType: "image"
 *   })
 *   .then(function(response) {
 *     let image = response.data;
 *
 *     // create a canvas with teal fill
 *     let canvas = document.createElement("canvas");
 *     let context = canvas.getContext("2d");
 *     canvas.width = width;
 *     canvas.height = height;
 *
 *     // Apply destination-atop operation to the image returned from the server
 *     context.fillStyle = "rgb(0,200,200)";
 *     context.fillRect(0, 0, width, height);
 *     context.globalCompositeOperation = "destination-atop";
 *     context.drawImage(image, 0, 0, width, height);
 *
 *     return canvas;
 *   }.bind(this));
 * }
 * ```
 * The layer is responsible for generating the image URL and fetching the image from the server for
 * the extent and size provided by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/). The
 * LayerView displays the fetched tiles.
 *
 * If the custom dynamic layer requires loadable resources, then you must load all loadable
 * dependencies on the layer, within the [load()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#load) method. Add the promise returned
 * from the loadable resource with the [addResolvingPromise()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#addResolvingPromise) method.
 * The layer will then wait for all of dependencies to
 * finish loading before it is considered [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#loaded).
 *
 * @since 4.4
 * @see [Creating Custom Layers and LayerViews (slides) - 2017 Esri Dev Summit](https://proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_97.pdf)
 * @see [Creating Custom Layers and LayerViews (video)](https://youtu.be/QOoZ1lgWESA)
 * @see [Sample - Custom DynamicLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-dynamiclayer/)
 */
export default abstract class BaseDynamicLayer extends BaseDynamicLayerSuperclass {
  constructor(properties?: BaseDynamicLayerProperties);
  /** The layer type provides a convenient way to check the type of the layer without the need to import specific layer modules. */
  get type(): "base-dynamic";
  /**
   * Adds a promise to the layer's loadable chain.
   * This is typically used in the [load()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#load) method to ensure that all
   * loadable resources required for the layer
   * to function are loaded prior to this layer resolving and becoming [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#loaded).
   *
   * @param promiseToLoad - A promise that must resolve for the layer
   *   to resolve and move from the `loading` [status](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#loadStatus) to being
   *   [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseDynamicLayer/#loaded).
   * @example
   * // the externalLayer must load() prior to the MyDynamicLayer
   * // resolving and moving to the "loaded" status
   * let MyDynamicLayer = BaseElevationLayer.createSubclass({
   *   load: function() {
   *     let promise = this.requiredLayer.load();
   *     this.addResolvingPromise(promise);
   *   }
   * });
   */
  addResolvingPromise<U, V extends EsriPromiseMixin>(promiseToLoad: PromiseLike<U> | V | PromiseLike<V> | null | undefined): void;
  /**
   * This method fetches the image for the specified extent and size. Override this method if the data returned
   * from the server needs to be processed before it can be displayed. For example, if the server returns binary
   * data, override this method to convert the binary data to an image.
   *
   * @param extent - The extent of the view. This value is provided by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
   * @param width - The width of the view in pixels. This value is provided by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
   * @param height - The height of the view in pixels. This value is provided by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
   * @param options - The parameter options is an object with the following properties.
   * @returns Returns a promise that resolves to an
   * [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement) or
   * [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement).
   * @example
   * // Fetches images for given extent and size
   * fetchImage: function (extent, width, height){
   *   let url = this.getImageUrl(extent, width, height);
   *
   *   // request for the image  based on the generated url
   *   return esriRequest(url, {
   *     responseType: "image"
   *   })
   *   .then(function(response) {
   *     let image = response.data;
   *
   *     let canvas = document.createElement("canvas");
   *     let context = canvas.getContext("2d");
   *     canvas.width = width;
   *     canvas.height = height;
   *
   *     // Apply destination-atop operation to the image returned from the server
   *     context.fillStyle = "rgb(0,200,200)";
   *     context.fillRect(0, 0, width, height);
   *     context.globalCompositeOperation = "destination-atop";
   *     context.drawImage(image, 0, 0, width, height);
   *
   *     return canvas;
   *   }.bind(this));
   * }
   */
  fetchImage(extent: Extent, width: number, height: number, options?: AbortOptions): Promise<HTMLImageElement | HTMLCanvasElement>;
  /**
   * This method returns a URL to an image for a given extent, width, and height.
   * Override this method to construct the URL for the image based on user interaction.
   *
   * @param extent - Extent of the view. This value is populated by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
   * @param width - Width of the view in pixels. This value is populated by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
   * @param height - Height of the view in pixels. This value is populated by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
   * @returns Returns a string or a promise that resolves to a string. The string is the URL to the image.
   * @see [Sample - Custom DynamicLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-dynamiclayer/)
   */
  getImageUrl(extent: Extent, width: number, height: number): string | Promise<string>;
}
declare const BaseDynamicLayerSuperclass: typeof Layer & typeof RefreshableLayer & typeof ScaleRangeLayer & typeof BlendLayer