<?php
namespace SabaiApps\Directories\Component\Location\Api;

class GoogleMapsGeocodingApi extends AbstractGoogleMapsApi implements IGeocodingApi {

	protected function _doGetInfo() {
		return array(
			'label'            => __( 'Google Maps Geocoding', 'directories-pro' ),
			'default_settings' => array(
				'geocoding' => array(
					'country'          => null,
					'house_number_pos' => 'before',
				),
			),
		);
	}

	public function locationApiLoad( array $settings ) {
		$geocoding_settings                  = isset( $settings['geocoding'] ) ? $settings['geocoding'] : array();
		$geocoding_settings['language']      = $this->_application->Map_Api_language();
		$geocoding_settings['addressFormat'] = '{street} {street2} {city} {province} {zip} {country}';
		$geocoding_settings                  = $this->_application->Filter( 'location_geocoding_googlemaps_settings', $geocoding_settings );
		$handle                              = $this->_load( 'geocoding', true );
		$this->_application->getPlatform()->addJsInline(
			$handle,
			sprintf(
				'var DRTS_Location_googlemapsGeocoding = %s;',
				$this->_application->System_Util_jsonEncode( $geocoding_settings )
			)
		);
	}

	public function locationApiSettingsForm( array $settings, array $parents ) {
		return array(
			'geocoding' => array(
				'#title'           => __( 'Google Maps Geocoding', 'directories-pro' ),
				'#class'           => 'drts-form-label-lg',
				'#states'          => array(
					'visible' => array(
						'[name="Map[lib][location_geocoding]"]' => array(
							'type'  => 'value',
							'value' => 'location_googlemaps',
						),
					),
				),
				'#weight'          => 10,
				'country'          => array(
					'#title'         => isset( $title ) ? $title : __( 'Country code', 'directories-pro' ),
					'#description'   => __( 'Enter a two-letter ISO 3166-1 Alpha-2 compatible country code to restrict geocoding results to a specific country.', 'directories-pro' ),
					'#type'          => 'textfield',
					'#default_value' => isset( $settings['geocoding']['country'] ) ? ( is_array( $settings['geocoding']['country'] ) ? $settings['geocoding']['country'][0] : $settings['geocoding']['country'] ) : null,
					'#min_length'    => 2,
					'#max_length'    => 2,
					'#horizontal'    => true,
					'#placeholder'   => 'US',
					'#alpha'         => true,
				),
				'house_number_pos' => array(
					'#type'          => 'select',
					'#title'         => __( 'House number position in geocoded address', 'directories-pro' ),
					'#options'       => array(
						'before' => __( 'Before street name', 'directories-pro' ),
						'after'  => __( 'After street name', 'directories-pro' ),
					),
					'#horizontal'    => true,
					'#default_value' => $settings['geocoding']['house_number_pos'],
				),
			),
		);
	}

	public function locationApiGeocode( $address, array $settings ) {
		$params = array(
			'address' => $address,
		);
		if ( ! empty( $settings['geocoding']['country'] ) ) {
			$countries = array();
			foreach ( (array) $settings['geocoding']['country'] as $country ) {
				$countries[] = 'country:' . $country;
			}
			$params['components'] = implode( '|', $countries );
		}
		return $this->_geocode( '/geocode/json', $params, $settings );
	}

	public function locationApiReverseGeocode( array $latlng, array $settings ) {
		return $this->_geocode(
			'/geocode/json',
			array(
				'latlng' => $latlng[0] . ',' . $latlng[1],
			),
			$settings
		);
	}

	protected function _geocode( $path, array $params, array $settings ) {
		$params   = array(
			'key'      => $settings['api']['key'],
			'language' => $this->_application->Map_Api_language(),
		) + $params;
		$url      = $this->_application->Map_GoogleMapsApi_url( $path, $params );
		$geocode  = $this->_application->Map_GoogleMapsApi_request( $url );
		$geometry = $geocode['results'][0]['geometry'];
		$viewport = $geometry['viewport'];
		return array(
			'lat'      => $geometry['location']['lat'],
			'lng'      => $geometry['location']['lng'],
			'address'  => $geocode['results'][0]['formatted_address'],
			'viewport' => array(
				$viewport['southwest']['lat'],
				$viewport['southwest']['lng'],
				$viewport['northeast']['lat'],
				$viewport['northeast']['lng'],
			),
		) + $this->_getAddressComponents( $geocode['results'][0]['address_components'], $settings );
	}

	protected function _getAddressComponents( array $components, array $settings ) {
		$ret = array(
			'street'   => '',
			'city'     => '',
			'province' => '',
			'zip'      => '',
			'country'  => '',
		);
		foreach ( $components as $component ) {
			foreach ( array_keys( $component['types'] ) as $i ) {
				switch ( $component['types'][ $i ] ) {
					case 'street_address':
						$ret['street'] = $component['long_name'];
						break;
					case 'locality':
					case 'sublocality':
						$ret['city'] = $component['long_name'];
						break;
					case 'administrative_area_level_1':
						$ret['province'] = $component['long_name'];
						break;
					case 'postal_code':
						$ret['zip'] = $component['long_name'];
						break;
					case 'country':
						$ret['country'] = strtoupper( $component['short_name'] );
						break;
					case 'political':
						break;
					default:
						$ret[ $component['types'][ $i ] ] = $component['long_name'];
				}
			}

			if ( empty( $ret['street'] ) ) {
				if ( isset( $ret['route'] ) ) {
					if ( isset( $ret['street_number'] ) ) {
						if ( isset( $settings['geocoding']['house_number_pos'] )
							&& $settings['geocoding']['house_number_pos'] === 'after'
						) {
							$ret['street'] = $ret['route'] . ' ' . $ret['street_number'];
						} else {
							$ret['street'] = $ret['street_number'] . ' ' . $ret['route'];
						}
					} else {
						$ret['street'] = $ret['route'];
					}
				}
			}

			if ( empty( $ret['city'] ) ) {
				if ( ! empty( $ret['administrative_area_level_3'] ) ) {
					$ret['city'] = $ret['administrative_area_level_3'];
				} elseif ( ! empty( $ret['administrative_area_level_2'] ) ) {
					$ret['city'] = $ret['administrative_area_level_2'];
				}
			}
		}
		return $ret;
	}
}
