<?php

namespace WPGMZA;

if(class_exists('WPGMZA\\GoogleMapsAPILoader'))
	return;

class GoogleMapsAPILoader
{
	private static $googleAPILoadCalled = false;
	private static $settings;
	
	const REMOVE_API_CHECKED			= 'REMOVE_API_CHECKED';
	const USER_CONSENT_NOT_GIVEN		= 'USER_CONSENT_NOT_GIVEN';
	const ENGINE_NOT_GOOGLE_MAPS		= 'ENGINE_NOT_GOOGLE_MAPS';
	const PAGE_EXPLICITLY_INCLUDED		= 'PAGE_EXPLICITLY_INCLUDED';
	const PAGE_EXPLICITLY_EXCLUDED		= 'PAGE_EXPLICITLY_EXCLUDED';
	const NEVER_LOAD_API_SELECTED		= 'NEVER_LOAD_API_SELECTED';
	const ONLY_LOAD_FRONT_END_SELECTED	= 'ONLY_LOAD_FRONT_END_SELECTED';
	const ONLY_LOAD_BACK_END_SELECTED	= 'ONLY_LOAD_BACK_END_SELECTED';
	const ENQUEUED						= 'ENQUEUED';
	
	public function __construct()
	{
		if(empty(GoogleMapsAPILoader::$settings))
		{
			global $wpgmza;
			GoogleMapsAPILoader::$settings = (array)$wpgmza->settings;
		}
		
		if(!$this->isIncludeAllowed($status))
		{
			echo "<script>var wpgmza_google_api_status = " . json_encode($status) . "</script>";
			return '';
		}
	}
	
	public static function _createInstance()
	{
		return new GoogleMapsAPILoader();
	}
	
	public static function createInstance()
	{
		return static::_createInstance();
	}
	
	/**
	 * Gets the parameters to be sent to the Google Maps API load call
	 * @return array
	 */
	protected function getGoogleMapsAPIParams()
	{
		// Locale
		$locale = get_locale();
		$suffix = '.com';
		
		switch($locale)
		{
			case 'he_IL':
				// Hebrew correction
				$locale = 'iw';
				break;
			
			case 'zh_CN':
				// Chinese integration
				$suffix = '.cn';
				break;
		}
		
		
		$locale = substr($locale, 0, 2);
		
		// Default params for google maps
		$params = array(
			'v' 		=> '3.31',
			'language'	=> $locale,
			'suffix'	=> $suffix
		);
		
		// API Key
		$key = get_option('wpgmza_google_maps_api_key');
		
		if($key)
			$params['key'] = $key;
		else if(is_admin())
			$params['key'] = get_option('wpgmza_temp_api');
		
		// API Version
		$settings = (array)GoogleMapsAPILoader::$settings;
		
		if(!empty($settings['wpgmza_api_version']))
			$params['v'] = $settings['wpgmza_api_version'];
		
		// Libraries
		$libraries = array('geometry', 'places', 'visualization');
		$params['libraries'] = implode(',', $libraries);
		
		$params = apply_filters( 'wpgmza_google_maps_api_params', $params );
		
		return $params;
	}
	
	/**
	 * This function loads the Google API if it hasn't been called already
	 * @return void
	 */
	public function registerGoogleMaps()
	{
		global $post;
		
		$settings = (array)GoogleMapsAPILoader::$settings;
		
		if(GoogleMapsAPILoader::$googleAPILoadCalled)
			return;
		
		$params = $this->getGoogleMapsAPIParams();
		
		$suffix = $params['suffix'];
		unset($params['suffix']);

		$url = '//maps.google' . $suffix . '/maps/api/js?' . http_build_query($params);
		
		wp_register_script('wpgmza_api_call', $url);
		
		// Are we always enqueuing?
		if(!empty($settings['wpgmza_load_engine_api_condition']) && $settings['wpgmza_load_engine_api_condition'] == 'always')
			$this->enqueueGoogleMaps();
		
		// Are we always enqueuing on this page?
		if($post && $this->isPageIncluded($post->ID))
			$this->enqueueGoogleMaps();
		
		GoogleMapsAPILoader::$googleAPILoadCalled = true;
		
		// Block other plugins from including the API
		if(!empty($settings['wpgmza_prevent_other_plugins_and_theme_loading_api']))
			add_filter('script_loader_tag', array($this, 'preventOtherGoogleMapsTag'), 9999999, 3);
	}
	
	public function enqueueGoogleMaps()
	{
		wp_enqueue_script('wpgmza_api_call');
	}
	
	public function isPageIncluded($page_id)
	{
		global $post;
		$settings = (array)GoogleMapsAPILoader::$settings;
		
		if(empty($settings['wpgmza_always_include_engine_api_on_pages']))
			return false;
		
		if(!preg_match_all('/\d+/', $settings['wpgmza_always_include_engine_api_on_pages'], $m))
			return false;
		
		if(empty($m[0]))
			return false;
		
		$page_ids = $m[0];
		
		return (array_search($page_id, $page_ids) !== false);
	}
	
	public function isPageExcluded($page_id)
	{
		$settings = (array)GoogleMapsAPILoader::$settings;
		
		if(empty($settings['wpgmza_always_exclude_engine_api_on_pages']))
			return false;
		
		if(!preg_match_all('/\d+/', $settings['wpgmza_always_exclude_engine_api_on_pages'], $m))
			return false;
			
		if(empty($m[0]))
			return false;
		
		$page_ids = $m[0];
			
		return (array_search($page_id, $page_ids) !== false);
	}
	
	public function isIncludeAllowed(&$status=null)
	{
		global $wpgmza;
		global $post;
		
		$status = (object)array(
			'message' => null,
			'code' => null
		);
		
		$settings = (array)$wpgmza->settings;
		
		// Correction for Pro <= 7.10.04
		if(!empty($settings['wpgmza_maps_engine']) && $settings['wpgmza_maps_engine'] == 'open-street-map')
			$settings['wpgmza_maps_engine'] = 'open-layers';
		
		if(!empty($settings['wpgmza_settings_remove_api']))
		{
			$status->message = 'Remove API checked in settings';
			$status->code = GoogleMapsAPILoader::REMOVE_API_CHECKED;
			
			return false;
		}
		
		if(!is_admin() && 
			!empty($settings['wpgmza_gdpr_enabled']) &&
			!empty($settings['wpgmza_gdpr_require_consent_before_load']) && 
			!isset($_COOKIE['wpgmza-api-consent-given']))
		{
			$status->message = 'User consent not given';
			$status->code = GoogleMapsAPILoader::USER_CONSENT_NOT_GIVEN;
			
			return false;
		}
		
		if(!empty($settings['wpgmza_maps_engine']) && $settings['wpgmza_maps_engine'] == 'open-layers')
		{
			$status->message = 'Engine is not google-maps';
			$status->code = GoogleMapsAPILoader::ENGINE_NOT_GOOGLE_MAPS;
			
			return false;
		}
		
		if($post)
		{
			if($this->isPageIncluded($post->ID))
			{
				$status->message = 'Page is explicitly included in settings';
				$status->code = GoogleMapsAPILoader::PAGE_EXPLICITLY_INCLUDED;
				
				return true;
			}
			
			if($this->isPageExcluded($post->ID))
			{
				$status->message = 'Page is explicitly excluded in settings';
				$status->code = GoogleMapsAPILoader::PAGE_EXPLICITLY_EXCLUDED;
				
				return false;
			}
		}
			
		if(!empty($settings['wpgmza_load_engine_api_condition']))
			switch($settings['wpgmza_load_engine_api_condition'])
			{
				case 'never':
					$status->message = 'Never load API chosen in settings';
					$status->code = GoogleMapsAPILoader::NEVER_LOAD_API_SELECTED;
					
					return false;
					break;
					
				case 'only-front-end':
					$status->message = 'Load API front end only chosen in settings';
					$status->code = GoogleMapsAPILoader::ONLY_LOAD_FRONT_END_SELECTED;
					
					return !is_admin();
					break;
					
				case 'only-back-end':
					$status->message = 'Load API back end only chosen in settings';
					$status->code = GoogleMapsAPILoader::ONLY_LOAD_BACK_END_SELECTED;
					
					return is_admin();
					break;
				
				default:
					break;
			}
		
		$status->message = 'Enqueued';
		$status->code = GoogleMapsAPILoader::ENQUEUED;
		
		return true;
	}
	
	public function preventOtherGoogleMapsTag($tag, $handle, $src)
	{
		if(preg_match('/maps\.google/i', $src))
		{
			if(!$this->isIncludeAllowed($status))
				return '';
			
			if($handle != 'wpgmza_api_call')
				return '';
			
			if(!preg_match('/\?.+$/', $src))
				return str_replace($src, $src . '?' . http_build_query($this->getGoogleMapsAPIParams()), $tag);
		}

		return $tag;
	}
	
	public function getSettingsHTML()
	{
		// Load our subclass of PHPs DOMDocument, for the populate function
		require_once(plugin_dir_path(__FILE__) . 'class.dom-document.php');
		
		// Load HTML
		$document = new DOMDocument();
		$document->loadPHPFile(plugin_dir_path(__DIR__) . 'html/google-maps-api-settings.html.php');
		
		// Populate options. This is a quick way to put key => value array/object values into elements with "name" matching "key"
		$document->populate(GoogleMapsAPILoader::$settings);
		
		return $document->saveInnerBody();
	}
	
}
