
;(function() {

  /**
   * Pass lookup tables to override default behaviour
   * @param addressLookupTable
   * @param lookupTable
   */
  exports.config = function(lookupTable, addressLookupTable) {
    this.extLookupTable = lookupTable;
    this.extAddressLookupTable = addressLookupTable;
  }.bind(this);

  /**
   * geomaton.parse(results)
   * @param results
   * @returns {Array}
   */
  exports.parse = function(response) {
    this.init();
    var results = response.results;
    var sortFoo = function(x, y) {
      if (x.types[0] > y.types[0]) return 1;
      if (x.types[0] < y.types[0]) return -1;
      return 0;
    };

    var structAddr = results[0].address_components.sort(sortFoo);
    var formatAddr = results[0].formatted_address;

    var parsedElms = {};

    structAddr.forEach(function (element) {
      var elm = this.parseElement(element, formatAddr);

      Object.keys(elm).forEach(function(key) {
        parsedElms[key] = elm[key];
      });

    }.bind(this));

    parsedElms['address'] = this.generateAddress(this.addressParts);

    return parsedElms;
  }.bind(this);

  this.init = function() {
    this.addressParts = [];
    this.addressSeparator = ' ';
    this.addressLookupTable = this.extAddressLookupTable || [
      'street_address',
      'street_number',
      'route',
      'premise',
      'subpremise',
      'neighborhood',
      'point_of_interest',
      'park',
      'airport'
    ];
    this.lookupTable = this.extLookupTable || {
      country: [
        'country'
      ],
      city: [
        'locality',
        'sublocality',
        'sublocality_level_1',
        'sublocality_level_2',
        'sublocality_level_3',
        'sublocality_level_4',
        'sublocality_level_5'
      ],
      state: [
        'administrative_area_level_1',
        'administrative_area_level_2',
        'administrative_area_level_3',
        'administrative_area_level_4',
        'administrative_area_level_5'
      ],
      zip: [
        'postal_code'
      ]
    };
  };

  /**
   * Parse a single element of Google's `address_components`.
   * Makes use of Google's `formatted_address` to create a correctly ordered address
   * @param element
   * @param formattedString
   * @returns {string}
   */
  this.parseElement = function(element, formattedString) {

    var parsed = {};
    var match = false;

    if (this.addressLookupTable.indexOf(element.types[0]) !== -1 && formattedString.indexOf(element.long_name) !== -1) {
      this.addressParts.push({
        name: element['long_name'],
        idx: formattedString.indexOf(element.long_name)
      });
    }

    Object.keys(this.lookupTable).forEach(function(typeKey) {
      this.lookupTable[typeKey].forEach(function(subtype) {
        if (match === false && element.types.indexOf(subtype) !== -1) {
          parsed[typeKey] = element.long_name;
          this.lookupTable[typeKey] = [];
          match = true;
        }
      }.bind(this))
    }.bind(this));

    return parsed;
  };

  /**
   * Concatenate the parts of the address in a single string
   * @param addressParts
   * @returns {string}
   */
  this.generateAddress = function(addressParts) {
    var address = [];

    addressParts.sort(function(x,y){return x.idx - y.idx}).forEach(function(elm) {
      address.push(elm.name);
    });
    return address.join(this.addressSeparator);
  }

}.call(this));

@@ -580,16 +580,17 @@
 pes%5B0%5D %3C
+=
  y.types
@@ -609,24 +609,8 @@
 -1;%0A
-      return 0;%0A
     

tweak sorting of address_components