Source: josm/layers.mjs

/**
 * Provides access to the JOSM layers.
 *
 * @module josm/layers
 */

/* global Java */

// -- imports
const MainApplication = Java.type('org.openstreetmap.josm.gui.MainApplication')
const OsmDataLayer = Java.type('org.openstreetmap.josm.gui.layer.OsmDataLayer')
const DataSet = Java.type('org.openstreetmap.josm.data.osm.DataSet')
const Layer = Java.type('org.openstreetmap.josm.gui.layer.Layer')
import * as util from './util'


/**
 * Provides access to JOSM layers.
 */
export class Layers {

  /**
   * Replies the number of currently open layers.
   *
   * @readOnly
   * @type {number}
   */
  get length() {
    return MainApplication.getLayerManager().getLayers().size()
  }

  /**
   * Set or get the active layer.
   *
   * <dl>
   *   <dt>get</dt>
   *   <dd class="param-desc">Replies the active layer or undefined.</dd>
   *
   *   <dt>set</dt>
   *   <dd class="param-desc">Assign either an existing {@class org.openstreetmap.josm.gui.layer.Layer},
   *   the name of a layer as string, or a layer index as number.</dd>
   * </dl>
   *
   * @type {org.openstreetmap.josm.gui.layer.Layer}
   */
  get activeLayer() {
    return MainApplication.getLayerManager().getActiveLayer()
  }

  set activeLayer(value) {
    util.assert(util.isSomething(value),'Value must not be null or undefined)')
    let layer = null
    if (value instanceof Layer) {
      layer = value
    } else if (util.isNumber(value) || util.isString(value)) {
      layer = layers.get(value)
    } else {
      util.assert(false, 'Unexpected type of value, got {0}', value)
    }
    util.assert(util.isSomething(layer),
      'Layer \'\'{0}\'\' doesn\'\'t exist. It can\'\'t be set as active layer.',
      value)
    MainApplication.getLayerManager().setActiveLayer(layer)
  }

  #getLayerByName (key) {
    key = util.trim(key).toLowerCase()
    if (this.length === 0) return undefined
    const layers = MainApplication.getLayerManager().getLayers()
    for (let it = layers.iterator(); it.hasNext();) {
      const l = it.next()
      if (l.getName().trim().toLowerCase() === key) return l
    }
    return undefined
  }

  #getLayerByIndex (idx) {
    if (idx < 0 || idx >= this.length) return undefined
    const layers = MainApplication.getLayerManager().getLayers()
    return layers.get(idx)
  }

  /**
   * Replies one of the layers given a key.
   *
   * <ul>
   *   <li>If <code>key</code> is a number, replies the layer with index key, or
   *   undefined, if no layer for this index exists.</li>
   *    <li>If <code>key</code> is a string, replies the first layer whose name
   *    is identical to key (case insensitive, without leading/trailing
   *    whitespace), or undefined, if no layer with such a name exists.</li>
   * </ul>
   *
   * @example
   * import layers from 'josm/layers'
   *
   * // get the first layer
   * const layer1  = layers.get(0)
   *
   * // get the first layer with name "data layer"
   * const layer2 = layers.get('data layer')
   *
   * @param {number|string} key the key to retrieve the layer
   * @returns {org.openstreetmap.josm.gui.layer.Layer}
   */
  get(key) {
    if (util.isNothing(key)) return undefined
    if (util.isString(key)) return this.#getLayerByName(key)
    if (util.isNumber(key)) return this.#getLayerByIndex(key)
    return undefined
  }


  /**
   * Checks whether <code>layer</code> is a currently registered layer.
   *
   * @example
   * import layers from 'josm/layers'
   *
   * // is there a layer with name "my layer"?
   * let b = layers.has('my layer')
   *
   * // is there a layer at index position 2
   * b = layers.has(2)
   *
   * // is there a specific layer?
   * let l = layers.get(0)
   * b = layers.has(l)
   *
   * @param {org.openstreetmap.josm.gui.layer.Layer|string|number} layer a layer,
   *     a layer name, or a layer index
   * @returns {boolean } true, if the layer or at least one layer with the given name exists.
   *     False, otherwise.
   */
  has(layer) {
    if (util.isNothing(layer)) return false
    const layerManager = MainApplication.getLayerManager()
    if (layer instanceof Layer) {
      return layerManager.getLayers().contains(layer)
    } else if (util.isString(layer)) {
      return util.isSomething(layers.get(layer))
    } else if (util.isNumber(layer)) {
      return layer >= 0 && layer < layers.length
    } else {
      return false
    }
  }


  /**
   * Adds a layer.
   * <p>
   * Either pass in a layer object or a data set. In the later case, an
   * {@class org.openstreetmap.josm.gui.layer.OsmDataLayer} is
   * automatically created.
   *
   * @example
   * import layers from 'josm/layers'
   * const OsmDataLayer = Java.type('org.openstreetmap.josm.gui.layer.OsmDataLayer')
   * const DataSet = Java.type('org.openstreetmap.josm.data.osm.DataSet')
   *
   * const dataLayer = new OsmDataLayer(new DataSet(), null, null);
   * // add a layer ...
   * layers.add(dataLayer)
   *
   * // or add a dataset, which will create a data layer
   * const ds = new DataSet()
   * layer.add(ds)
   *
   * @param {org.openstreetmap.josm.gui.layer.Layer
   *     |org.openstreetmap.josm.data.osm.DataSet} obj  a layer to add,
   *      or a dataset.  Ignored if null or undefined.
   * @returns {org.openstreetmap.josm.gui.layer.Layer} the added layer
   */
  add(obj) {
    if (util.isNothing(obj)) return
    const layerManager = MainApplication.getLayerManager()
    if (obj instanceof Layer) {
      layerManager.addLayer(obj)
    } else if (obj instanceof DataSet) {
      layerManager.addLayer(new OsmDataLayer(obj, null, null))
    } else {
      util.assert(false,
        'Expected an instance of Layer or DataSet, got {0}', obj)
    }
  }

  #removeLayerByIndex (idx) {
    const layer = this.get(idx)
    if (util.isNothing(layer)) return
    MainApplication.getLayerManager().removeLayer(layer)
  }
  
  #removeLayerByName (name) {
    const layer = this.get(name)
    if (util.isNothing(layer)) return
    MainApplication.getLayerManager().removeLayer(layer)
  }
  
  /**
   * Removes a layer with the given key.
   *
   * <ul>
   *   <li>If <code>key</code> is a <code>Number</code>, removes the layer with
   *   the index key. If the index doesn't isn't a valid layer index, nothing
   *   is removed.</li>
   *   <li>If <code>key</code> is a <code>string</code>, removes the layer with
   *   the name <code>key</code>. Leading and trailing white space is removed,
   *   matching is a case-insensitive sub-string match.</li>
   * </ul>
   * @example
   * import josm from 'josm'
   *
   * // remove the first layer
   * josm.layers.remove(0)
   *
   * // remove the first layer matching with the supplied name
   * josm.layers.remove('myLayerName')
   *
   * @param {number|string} key  indicates the layer to remove
   */
  remove(key) {
    if (util.isNothing(key)) return
    if (util.isNumber(key)) {
      this.#removeLayerByIndex(key)
    } else if (util.isString(key)) {
      this.#removeLayerByName(key)
    } else {
      util.assert(false, 'Expected a number or a string, got {0}', key)
    }
  }

  
  /**
   * Creates and adds a new data layer. The new layer becomes the new edit
   * layer.
   * <p>
   *
   * <string>Signatures</string>
   * <dl>
   *   <dt><code class="signature">addDataLayer()</code></dt>
   *   <dd class="param-desc">create data layer with a new dataset and default name</dd>
   *   <dt><code class="signature">addDataLayer(ds)</code></dt>
   *   <dd class="param-desc">create data layer with dataset ds and default name</dd>
   *   <dt><code class="signature">addDataLayer(name)</code></dt>
   *   <dd class="param-desc">create data layer with a new  dataset and name <code>name</code></dd>
   *   <dt><code class="signature">addDataLayer({name: ..., ds: ...})</code></dt>
   *   <dd class="param-desc">create data layer with a new  dataset and name <code>name</code></dd>
   * </dl>
   * @example
   * import josm from 'josm'
   * const DataSet = Java.type('org.openstreetmap.josm.data.osm.DataSet')
   *
   * // creates a new data layer
   * const l1 = josm.layers.addDataLayer()
   *
   * // creates a new data layer with name 'test'
   * const l2 = josm.layers.addDataLayer('test')
   *
   * // creates a new data layer for the dataset ds
   * const ds = new DataSet()
   * const l3 = josm.layers.addDataLayer(ds)
   *
   * @returns {org.openstreetmap.josm.gui.layer.OsmDataLayer} the added layer
   * @param {string | org.openstreetmap.josm.data.osm.DataSet | object } args see description
   */
  addDataLayer() {
    let name, ds
    switch (arguments.length) {
      case 0: break
      case 1:
        if (util.isString(arguments[0])) {
          name = util.trim(arguments[0])
        } else if (arguments[0] instanceof DataSet) {
          ds = arguments[0]
        } else if (typeof arguments[0] === 'object') {
          if (util.isString(arguments[0].name)) {
            name = util.trim(arguments[0].name)
          }
          if (arguments[0].ds instanceof DataSet) {
            ds = arguments[0].ds
          }
        } else {
          util.assert(false, 'unsupported type of argument, got {0}',
            arguments[0])
        }
        break
      default:
        util.assert(false, 'Unsupported number of arguments, got {0}',
          arguments.length)
    }
    ds = ds || new DataSet()
    name = name || OsmDataLayer.createNewName()
    const layer = new OsmDataLayer(ds, name, null /* no file */)
    layers.add(layer)
    return layer
  }
}


/**
 * the singleton instance of the layers class
 */
 const layers = new Layers()
 export default layers