<?php

namespace Tainacan\Metadata_Types;

require_once(__DIR__ . '/class-tainacan-geocoordinate-helper.php');

use Tainacan\Entities\Item_Metadata_Entity;

defined( 'ABSPATH' ) or die( 'No script kiddies please!' );

/**
 * Class GeoCoordinate
 */
class GeoCoordinate extends Metadata_Type {

	function __construct() {
		// call metadatum type constructor
		parent::__construct();
		$this->set_primitive_type('geo');
		$this->set_component('tainacan-geocoordinate');
		$this->set_form_component('tainacan-form-geocoordinate');
		$this->set_name( __('GeoCoordinate', 'tainacan') );
		$this->set_description( __('Represents a geographical location that is determined by latitude and longitude coordinates.', 'tainacan') );
		$this->set_sortable( false );
		$this->set_default_options([
			'map_provider' => 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
			'attribution' => '&copy; <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors',
			'initial_zoom' => 5,
			'maximum_zoom' => 12,
			'initial_latitude' => -14.4086569,
			'initial_longitude' => -51.31668
		]);
		$this->set_preview_template('
			<div>
				<div class="control">
					<img src="' . plugin_dir_url( __FILE__ ) . '/../../../../../../assets/images/geocoordinate_preview.png" alt="' . __('Image of a marker in a map.' , 'tainacan' ) . '" />
				</div>
			</div>
		');
	}

	/**
	 * @inheritdoc
	*/
	public function get_form_labels(){
		return [
			'map_provider' => [
				'title' => __( 'Map Tiles provider', 'tainacan' ),
				'description' => __( 'Link to the service used as source for displaying tile layers on the map.', 'tainacan' ),
			],
			'attribution' => [
				'title' => __( 'Attribution', 'tainacan' ),
				'description' => __( 'Text/HTML to be shown in the attribution control, e.g. "© OpenStreetMap contributors". It describes source of map data and is often a legal obligation towards copyright holders and tile providers.', 'tainacan' ),
			],
			'initial_zoom' => [
				'title' => __( 'Initial zoom', 'tainacan' ),
				'description' => __( 'Initial zoom level of the map.', 'tainacan' ),
			],
			'maximum_zoom' => [
				'title' => __( 'Maximum zoom', 'tainacan' ),
				'description' => __( 'Maximum zoom level of the map.', 'tainacan' ),
			],
			'initial_position' => [
				'title' => __( 'Initial center position', 'tainacan' ),
				'description' => __( 'Define latitude and longitude for the initial center of the map input.', 'tainacan' ),
			]
		];
	}

	/**
	 * Validates a given coordinate
	 *
	 * @param float|int|number $lat Latitude
	 * @param float|int|number $long Longitude
	 * @return bool `true` if the coordinate is valid, `false` if not
	 */
	private function validateLatLong($lat, $long) {
		if ( !is_numeric($lat) || !is_numeric($long) )
			return false;
			
		$validataLat = ($lat + 0) >= -90.0 && ($lat + 0) <= 90.0;
		$validataLong = ($long + 0) >= -180.0 && ($long + 0) <= 180.0;
		return $validataLat & $validataLong;
	}

	public function validate( Item_Metadata_Entity $item_metadata) {
		$value = $item_metadata->get_value();
		$value = is_array($value) ? $value : [$value];
		foreach ($value as $coordinate) {
			$arr_coordinate = explode(",", $coordinate);
			if ( count($arr_coordinate) != 2 || !$this->validateLatLong($arr_coordinate[0], $arr_coordinate[1])) {
				/* translators: %s is the value of the geo coordinate */
				$this->add_error( sprintf(__('The value (%s) is not a valid geo coordinate', 'tainacan'), $coordinate ) );
				return false;
			}
		}
		return true;
	}

	/**
	 * Return the value of an Item_Metadata_Entity using a metadatum of this metadatum type as a string
	 * 
	 * @param Item_Metadata_Entity $item_metadata 
	 * @return string The String representation of the value, containing one or multiple items names, linked to the item page
	 */
	public function get_value_as_string(\Tainacan\Entities\Item_Metadata_Entity $item_metadata) {
		$value = $item_metadata->get_value();

		$return = '';

		if ( $item_metadata->is_multiple() ) {
			$prefix = $item_metadata->get_multivalue_prefix();
			$suffix = $item_metadata->get_multivalue_suffix();
			$separator = $item_metadata->get_multivalue_separator();
			$total = count($value);
			$count = 0;

			foreach ($value as $v) {
				$return .= $prefix;
				$return .= (string) $v;
				$return .= $suffix;
				$count ++;
			
				if ($count < $total)
					$return .= $separator;
			}
		} else {
			$return = (string) $value;
		}

		return 
		/**
		 * Filter the STRING representation of the value of a geocoordinate metadatum
		 * 
		 * @param string $return The STRING representation of the value
		 * @param \Tainacan\Entities\Item_Metadata_Entity $item_metadata The Item_Metadata_Entity object
		 * 
		 * @return string The STRING representation of the item metadatum value
		 */
		apply_filters( 'tainacan-item-metadata-get-value-as-string--type-geocoordinate', $return, $item_metadata );
	}

	
	/**
	 * Get the value as a HTML string with proper date format set in admin
	 * @return string
	 */
	public function get_value_as_html(\Tainacan\Entities\Item_Metadata_Entity $item_metadata) {
		global $TAINACAN_BASE_URL;
		$value = $item_metadata->get_value();
		$options = $this->get_options();

		$return = '';

		if ( 
			!( is_string( $value ) && empty( $value ) ) &&
			!( is_array( $value ) && !count( $value ) )
		) {
			$metadatum = $item_metadata->get_metadatum();
			$item_metadatum_id = $metadatum->get_id();
			$item_metadatum_id .= ( $metadatum->get_parent() && $item_metadata->get_parent_meta_id() ) ? ( '_parent_meta_id-' . $item_metadata->get_parent_meta_id() ) : '';
			$zoom_geo_query = isset($options['initial_zoom']) ? ('z=' . $options['initial_zoom'] ) : '' ;

			if ( $item_metadata->is_multiple() ) {
				$html_formatting = $item_metadata->get_metadatum()->get_html_formatting();
				if ( $html_formatting === 'list' ) {
					$list_items = [];
					foreach ( $value as $coordinate ) {
						$coordinate_as_array = explode(",", $coordinate);
						$latitude = isset($coordinate_as_array[0]) ? $coordinate_as_array[0] : '';
						$longitude = isset($coordinate_as_array[1]) ? $coordinate_as_array[1] : '';
						$single_value = "<a class='tainacan-coordinates' data-latitude='{$latitude}' data-longitude='{$longitude}' href='geo:{$latitude},{$longitude}?q={$latitude},{$longitude}&{$zoom_geo_query}'>
											<span>{$latitude}</span>
											<span class='coordinates-separator'>,</span>
											<span>{$longitude}</span>
										</a>";
						$list_items[] = $single_value;
					}
					$total = count( $list_items );
					if ( $total === 1 ) {
						$return .= $list_items[0];
					} elseif ( $total > 1 ) {
						$return .= '<ul>';
						foreach ( $list_items as $item ) {
							$return .= '<li>' . $item . '</li>';
						}
						$return .= '</ul>';
					}
				} else {
					$prefix = $item_metadata->get_multivalue_prefix();
					$suffix = $item_metadata->get_multivalue_suffix();
					$separator = $item_metadata->get_multivalue_separator();
					foreach ( $value as $coordinate ) {
						$coordinate_as_array = explode(",", $coordinate);
						$latitude = isset($coordinate_as_array[0]) ? $coordinate_as_array[0] : '';
						$longitude = isset($coordinate_as_array[1]) ? $coordinate_as_array[1] : '';
						$single_value = "<a class='tainacan-coordinates' data-latitude='{$latitude}' data-longitude='{$longitude}' href='geo:{$latitude},{$longitude}?q={$latitude},{$longitude}&{$zoom_geo_query}'>
											<span>{$latitude}</span>
											<span class='coordinates-separator'>,</span>
											<span>{$longitude}</span>
										</a>";
						$return .= empty($return)
							? $prefix . $single_value . $suffix
							: $separator . $prefix . $single_value . $suffix;
					}
				}
			} else {
				$coordinate_as_array = explode(",", $value);
				$latitude = isset($coordinate_as_array[0]) ? $coordinate_as_array[0] : '';
				$longitude = isset($coordinate_as_array[1]) ? $coordinate_as_array[1] : '';

				$return .= "<a class='tainacan-coordinates' data-latitude='{$latitude}' data-longitude='{$longitude}' href='geo:{$latitude},{$longitude}?q={$latitude},{$longitude}&{$zoom_geo_query}'>
								<span>{$latitude}</span>
								<span class='coordinates-separator'>,</span>
								<span>{$longitude}</span>
							</a>";
			}
			
			wp_enqueue_style( 'tainacan-geocoordinate-item-metadatum', $TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-geocoordinate-item-metadatum.css', array(), TAINACAN_VERSION);

			$options_as_strings = '';
			foreach ( $options as $option_key => $option ) {
				if ( is_array($option) )
					$options_as_strings .= 'data-' . $option_key . '="' . json_encode($option) . '" ';
				else if ( $option_key == 'attribution' )
					$options_as_strings .= 'data-' . $option_key . '="' . htmlentities($option) . '" ';
				else
					$options_as_strings .= 'data-' . $option_key . '="' . $option . '" ';
			};

			$return = '<span id="tainacan-geocoordinatemetadatum--' . $item_metadatum_id . '" data-module="geocoordinate-item-metadatum" ' . $options_as_strings . '>
				' . $return . '
			</span>';
		}

		return 
			/**
			 * Filter the HTML representation of the value of a geocoordinate metadatum
			 * 
			 * @param string $return The HTML representation of the value
			 * @param \Tainacan\Entities\Item_Metadata_Entity $item_metadata The Item_Metadata_Entity object
			 * 
			 * @return string The HTML representation of the item metadatum value
			 */
			apply_filters( 'tainacan-item-metadata-get-value-as-html--type-geocoordinate', $return, $item_metadata );
	}

	public function get_options_as_html() {
		return "";
	}

    /**
     * @param \Tainacan\Entities\Metadatum $metadatum
     * @return array|bool true if is validate or array if has error
     */
    public function validate_options(\Tainacan\Entities\Metadatum $metadatum) {
        if ( !in_array($metadatum->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
            return true;

        if ( !$this->validateLatLong( $this->get_option('initial_latitude'), $this->get_option('initial_longitude') ) ) {
            return [
                /* translators: %s is the value of the geo coordinate */
                'initial_position' => sprintf(__('The value (%s) is not a valid geo coordinate', 'tainacan'), ('' . $this->get_option('initial_latitude') . ',' . $this->get_option('initial_longitude')) )
            ];
        }

        return true;
    }
}