'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _index = require('../index.js');

var _index2 = _interopRequireDefault(_index);

var _array = require('../array.js');

var _array2 = _interopRequireDefault(_array);

var _feature = require('../feature.js');

var _feature2 = _interopRequireDefault(_feature);

var _feature3 = require('../format/feature.js');

var _feature4 = _interopRequireDefault(_feature3);

var _xmlfeature = require('../format/xmlfeature.js');

var _xmlfeature2 = _interopRequireDefault(_xmlfeature);

var _geometrylayout = require('../geom/geometrylayout.js');

var _geometrylayout2 = _interopRequireDefault(_geometrylayout);

var _linestring = require('../geom/linestring.js');

var _linestring2 = _interopRequireDefault(_linestring);

var _point = require('../geom/point.js');

var _point2 = _interopRequireDefault(_point);

var _polygon = require('../geom/polygon.js');

var _polygon2 = _interopRequireDefault(_polygon);

var _obj = require('../obj.js');

var _obj2 = _interopRequireDefault(_obj);

var _proj = require('../proj.js');

var _proj2 = _interopRequireDefault(_proj);

var _xml = require('../xml.js');

var _xml2 = _interopRequireDefault(_xml);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

/**
 * @classdesc
 * Feature format for reading data in the
 * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).
 *
 * @constructor
 * @extends {ol.format.XMLFeature}
 * @api
 */
// FIXME add typedef for stack state objects
var _ol_format_OSMXML_ = function () {
  _xmlfeature2.default.call(this);

  /**
   * @inheritDoc
   */
  this.defaultDataProjection = _proj2.default.get('EPSG:4326');
};

_index2.default.inherits(_ol_format_OSMXML_, _xmlfeature2.default);

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @private
 */
_ol_format_OSMXML_.readNode_ = function (node, objectStack) {
  var options = /** @type {olx.format.ReadOptions} */objectStack[0];
  var state = /** @type {Object} */objectStack[objectStack.length - 1];
  var id = node.getAttribute('id');
  /** @type {ol.Coordinate} */
  var coordinates = [parseFloat(node.getAttribute('lon')), parseFloat(node.getAttribute('lat'))];
  state.nodes[id] = coordinates;

  var values = _xml2.default.pushParseAndPop({
    tags: {}
  }, _ol_format_OSMXML_.NODE_PARSERS_, node, objectStack);
  if (!_obj2.default.isEmpty(values.tags)) {
    var geometry = new _point2.default(coordinates);
    _feature4.default.transformWithOptions(geometry, false, options);
    var feature = new _feature2.default(geometry);
    feature.setId(id);
    feature.setProperties(values.tags);
    state.features.push(feature);
  }
};

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @private
 */
_ol_format_OSMXML_.readWay_ = function (node, objectStack) {
  var id = node.getAttribute('id');
  var values = _xml2.default.pushParseAndPop({
    id: id,
    ndrefs: [],
    tags: {}
  }, _ol_format_OSMXML_.WAY_PARSERS_, node, objectStack);
  var state = /** @type {Object} */objectStack[objectStack.length - 1];
  state.ways.push(values);
};

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @private
 */
_ol_format_OSMXML_.readNd_ = function (node, objectStack) {
  var values = /** @type {Object} */objectStack[objectStack.length - 1];
  values.ndrefs.push(node.getAttribute('ref'));
};

/**
 * @param {Node} node Node.
 * @param {Array.<*>} objectStack Object stack.
 * @private
 */
_ol_format_OSMXML_.readTag_ = function (node, objectStack) {
  var values = /** @type {Object} */objectStack[objectStack.length - 1];
  values.tags[node.getAttribute('k')] = node.getAttribute('v');
};

/**
 * @const
 * @private
 * @type {Array.<string>}
 */
_ol_format_OSMXML_.NAMESPACE_URIS_ = [null];

/**
 * @const
 * @type {Object.<string, Object.<string, ol.XmlParser>>}
 * @private
 */
_ol_format_OSMXML_.WAY_PARSERS_ = _xml2.default.makeStructureNS(_ol_format_OSMXML_.NAMESPACE_URIS_, {
  'nd': _ol_format_OSMXML_.readNd_,
  'tag': _ol_format_OSMXML_.readTag_
});

/**
 * @const
 * @type {Object.<string, Object.<string, ol.XmlParser>>}
 * @private
 */
_ol_format_OSMXML_.PARSERS_ = _xml2.default.makeStructureNS(_ol_format_OSMXML_.NAMESPACE_URIS_, {
  'node': _ol_format_OSMXML_.readNode_,
  'way': _ol_format_OSMXML_.readWay_
});

/**
 * @const
 * @type {Object.<string, Object.<string, ol.XmlParser>>}
 * @private
 */
_ol_format_OSMXML_.NODE_PARSERS_ = _xml2.default.makeStructureNS(_ol_format_OSMXML_.NAMESPACE_URIS_, {
  'tag': _ol_format_OSMXML_.readTag_
});

/**
 * Read all features from an OSM source.
 *
 * @function
 * @param {Document|Node|Object|string} source Source.
 * @param {olx.format.ReadOptions=} opt_options Read options.
 * @return {Array.<ol.Feature>} Features.
 * @api
 */
_ol_format_OSMXML_.prototype.readFeatures;

/**
 * @inheritDoc
 */
_ol_format_OSMXML_.prototype.readFeaturesFromNode = function (node, opt_options) {
  var options = this.getReadOptions(node, opt_options);
  if (node.localName == 'osm') {
    var state = _xml2.default.pushParseAndPop({
      nodes: {},
      ways: [],
      features: []
    }, _ol_format_OSMXML_.PARSERS_, node, [options]);
    // parse nodes in ways
    for (var j = 0; j < state.ways.length; j++) {
      var values = /** @type {Object} */state.ways[j];
      /** @type {Array.<number>} */
      var flatCoordinates = [];
      for (var i = 0, ii = values.ndrefs.length; i < ii; i++) {
        var point = state.nodes[values.ndrefs[i]];
        _array2.default.extend(flatCoordinates, point);
      }
      var geometry;
      if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {
        // closed way
        geometry = new _polygon2.default(null);
        geometry.setFlatCoordinates(_geometrylayout2.default.XY, flatCoordinates, [flatCoordinates.length]);
      } else {
        geometry = new _linestring2.default(null);
        geometry.setFlatCoordinates(_geometrylayout2.default.XY, flatCoordinates);
      }
      _feature4.default.transformWithOptions(geometry, false, options);
      var feature = new _feature2.default(geometry);
      feature.setId(values.id);
      feature.setProperties(values.tags);
      state.features.push(feature);
    }
    if (state.features) {
      return state.features;
    }
  }
  return [];
};

/**
 * Read the projection from an OSM source.
 *
 * @function
 * @param {Document|Node|Object|string} source Source.
 * @return {ol.proj.Projection} Projection.
 * @api
 */
_ol_format_OSMXML_.prototype.readProjection;

/**
 * Not implemented.
 * @inheritDoc
 */
_ol_format_OSMXML_.prototype.writeFeatureNode = function (feature, opt_options) {};

/**
 * Not implemented.
 * @inheritDoc
 */
_ol_format_OSMXML_.prototype.writeFeaturesNode = function (features, opt_options) {};

/**
 * Not implemented.
 * @inheritDoc
 */
_ol_format_OSMXML_.prototype.writeGeometryNode = function (geometry, opt_options) {};
exports.default = _ol_format_OSMXML_;
module.exports = exports['default'];