text: // @flow
  
  const wrap = require('../util/util').wrap;
  
  /**
   * A `LngLat` object represents a given longitude and latitude coordinate, measured in degrees.
   *
   * Mapbox GL uses longitude, latitude coordinate order (as opposed to latitude, longitude) to match GeoJSON.
   *
   * Note that any Mapbox GL method that accepts a `LngLat` object as an argument or option
   * can also accept an `Array` of two numbers and will perform an implicit conversion.
   * This flexible type is documented as {@link LngLatLike}.
   *
   * @param {number} lng Longitude, measured in degrees.
   * @param {number} lat Latitude, measured in degrees.
   * @example
   * var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
   * @see [Get coordinates of the mouse pointer](https://www.mapbox.com/mapbox-gl-js/example/mouse-position/)
   * @see [Display a popup](https://www.mapbox.com/mapbox-gl-js/example/popup/)
   * @see [Highlight features within a bounding box](https://www.mapbox.com/mapbox-gl-js/example/using-box-queryrenderedfeatures/)
   * @see [Create a timeline animation](https://www.mapbox.com/mapbox-gl-js/example/timeline-animation/)
   */
  class LngLat {
      lng: number;
      lat: number;
  
      constructor(lng: number, lat: number) {
          if (isNaN(lng) || isNaN(lat)) {
              throw new Error(`Invalid LngLat object: (${lng}, ${lat})`);
          }
          this.lng = +lng;
          this.lat = +lat;
          if (this.lat > 90 || this.lat < -90) {
              throw new Error('Invalid LngLat latitude value: must be between -90 and 90');
          }
      }
  
      /**
       * Returns a new `LngLat` object whose longitude is wrapped to the range (-180, 180).
       *
       * @returns {LngLat} The wrapped `LngLat` object.
       * @example
       * var ll = new mapboxgl.LngLat(286.0251, 40.7736);
       * var wrapped = ll.wrap();
       * wrapped.lng; // = -73.9749
       */
      wrap() {
          return new LngLat(wrap(this.lng, -180, 180), this.lat);
      }
  
      /**
       * Returns the coordinates represented as an array of two numbers.
       *
       * @returns {Array<number>} The coordinates represeted as an array of longitude and latitude.
       * @example
       * var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
       * ll.toArray(); // = [-73.9749, 40.7736]
       */
      toArray() {
          return [this.lng, this.lat];
      }
  
      /**
       * Returns the coordinates represent as a string.
       *
       * @returns {string} The coordinates represented as a string of the format `'LngLat(lng, lat)'`.
       * @example
       * var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
       * ll.toString(); // = "LngLat(-73.9749, 40.7736)"
       */
      toString() {
          return `LngLat(${this.lng}, ${this.lat})`;
      }
  
      /**
       * Returns a `LngLatBounds` from the coordinates extended by a given `radius`.
       *
       * @param {number} radius Distance in meters from the coordinates to extend the bounds.
       * @returns {LngLatBounds} A new `LngLatBounds` object representing the coordinates extended by the `radius`.
       * @example
       * var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
       * ll.toBounds(100).toArray(); // = [[-73.97501862141328, 40.77351016847229], [-73.97478137858673, 40.77368983152771]]
       */
      toBounds(radius: number) {
          const earthCircumferenceInMetersAtEquator = 40075017;
          const latAccuracy = 360 * radius / earthCircumferenceInMetersAtEquator,
              lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
  
          const LngLatBounds = require('./lng_lat_bounds');
          return new LngLatBounds(new LngLat(this.lng - lngAccuracy, this.lat - latAccuracy),
              new LngLat(this.lng + lngAccuracy, this.lat + latAccuracy));
      }
  
      /**
       * Converts an array of two numbers to a `LngLat` object.
       *
       * If a `LngLat` object is passed in, the function returns it unchanged.
       *
       * @param {LngLatLike} input An array of two numbers to convert, or a `LngLat` object to return.
       * @returns {LngLat} A new `LngLat` object, if a conversion occurred, or the original `LngLat` object.
       * @example
       * var arr = [-73.9749, 40.7736];
       * var ll = mapboxgl.LngLat.convert(arr);
       * ll;   // = LngLat {lng: -73.9749, lat: 40.7736}
       */
      static convert(input: LngLatLike): LngLat {
          if (input instanceof LngLat) {
              return input;
          }
          if (Array.isArray(input) && (input.length === 2 || input.length === 3)) {
              return new LngLat(Number(input[0]), Number(input[1]));
          }
          if (!Array.isArray(input) && typeof input === 'object' && input !== null) {
              return new LngLat(Number(input.lng), Number(input.lat));
          }
          throw new Error("`LngLatLike` argument must be specified as a LngLat instance, an object {lng: <lng>, lat: <lat>}, or an array of [<lng>, <lat>]");
      }
  }
  
  /**
   * A {@link LngLat} object, an array of two numbers representing longitude and latitude,
   * or an object with `lng` and `lat` properties.
   *
   * @typedef {LngLat | {lng: number, lat: number} | [number, number]} LngLatLike
   * @example
   * var v1 = new mapboxgl.LngLat(-122.420679, 37.772537);
   * var v2 = [-122.420679, 37.772537];
   */
  export type LngLatLike = LngLat | {lng: number, lat: number} | [number, number];
  
  module.exports = LngLat;
  