Source: OverpassNode.js

/* global L:false */

const OverpassObject = require('./OverpassObject')
const BoundingBox = require('boundingbox')
const OverpassFrontend = require('./defines')
const turf = require('./turf')

/**
 * A node
 * @extends OverpassObject
 * @property {string} id ID of this object, starting with 'n'.
 * @property {number} osm_id Numeric id.
 * @property {string} type Type: 'node'
 * @property {object} tags OpenStreetMap tags.
 * @property {object} meta OpenStreetMap meta information.
 * @property {Point} geometry of the object
 * @property {object} data Data as loaded from Overpass API.
 * @property {bit_array} properties Which information about this object is known?
 * @property {object[]} memberOf List of ways and relations where this object is member of.
 * @property {string} memberOf.id ID of the way or relation where this way is member of.
 * @property {string} memberOf.role Role of this object in the relation.
 * @property {number} memberOf.sequence This object is the nth member in the way resp. relation.
 * @property {BoundingBox} bounds Bounding box of this object.
 * @property {Point} center Centroid of the bounding box.
 */
class OverpassNode extends OverpassObject {
  GeoJSON () {
    const result = {
      type: 'Feature',
      id: this.type + '/' + this.osm_id,
      properties: this.GeoJSONProperties()
    }

    if (this.geometry) {
      result.geometry = {
        type: 'Point',
        coordinates: [this.geometry.lon, this.geometry.lat]
      }
    }

    return result
  }

  exportOSMXML (options, document, callback) {
    super.exportOSMXML(options, document,
      (err, result) => {
        if (err) {
          return callback(err)
        }

        if (!result) { // already included
          return callback(null)
        }

        result.setAttribute('lat', this.geometry.lat)
        result.setAttribute('lon', this.geometry.lon)

        callback(null, result)
      }
    )
  }

  exportOSMJSON (conf, elements, callback) {
    super.exportOSMJSON(conf, elements,
      (err, result) => {
        if (err) {
          return callback(err)
        }

        if (!result) { // already included
          return callback(null)
        }

        result.lat = this.geometry.lat
        result.lon = this.geometry.lon

        callback(null, result)
      }
    )
  }

  updateData (data, options) {
    super.updateData(data, options)

    if (data.lat) {
      this.geometry = {
        lat: data.lat,
        lon: data.lon
      }

      this.bounds = new BoundingBox(data)
      this.center = this.bounds.getCenter()

      this.properties = this.properties | OverpassFrontend.GEOM | OverpassFrontend.BBOX | OverpassFrontend.CENTER
    }

    this.properties |= OverpassFrontend.MEMBERS // node does not have members, so it always known all of them
  }

  /**
   * return a leaflet feature for this object
   * @param {object} [options] options Options will be passed to the leaflet function
   * @param {string} [options.nodeFeature='CircleMarker'] Which type of object should be returned: 'Marker' (L.marker), 'Circle' (L.circle) or 'CircleMarker' (L.circleMarker).
   * @param {number[]} [options.shiftWorld=[0, 0]] Shift western (negative) longitudes by shiftWorld[0], eastern (positive) longitudes by shiftWorld[1] (e.g. by 360, 0 to show objects around lon=180)
   * @return {L.layer}
   */
  leafletFeature (options = {}) {
    if (!this.geometry) {
      return null
    }

    if (!('shiftWorld' in options)) {
      options.shiftWorld = [0, 0]
    }

    const geom = { lat: this.geometry.lat, lon: this.geometry.lon + options.shiftWorld[this.geometry.lon < 0 ? 0 : 1] }

    switch ('nodeFeature' in options ? options.nodeFeature : null) {
      case 'Marker':
        return L.marker(geom, options)
      case 'Circle':
        return L.circle(geom, options.radius, options)
      case 'CircleMarker':
      default:
        return L.circleMarker(geom, options)
    }
  }

  intersects (bbox) {
    if (!this.bounds) {
      return 1
    }

    if (!bbox.intersects) { // GeoJSON detected
      const r = turf.booleanIntersects(this.GeoJSON(), bbox)
      return r ? 2 : 0
    }

    return bbox.intersects(this.bounds) ? 2 : 0
  }
}

module.exports = OverpassNode