<?php
/**
 * CMB2 Field Ajax Search
 * 
 * Based on https://github.com/rubengc/cmb2-field-ajax-search
 */

if(!class_exists('CMB2_Field_Ajax_Search')){

	/**
	 * Class CMB2_Field_Ajax_Search
	 */
	class CMB2_Field_Ajax_Search {

		/**
		 * Current version number
		 */
		const VERSION = '2.0.0';

		/**
		 * Initialize the plugin by hooking into CMB2
		 */
		public function __construct() {
			add_action('admin_enqueue_scripts', array($this, 'setup_admin_scripts'));

			// Render
			add_action('cmb2_render_post_ajax_search', array($this, 'render'), 10, 5);
			add_action('cmb2_render_user_ajax_search', array($this, 'render'), 10, 5);
			add_action('cmb2_render_term_ajax_search', array($this, 'render'), 10, 5);

			// Display
			add_filter('cmb2_pre_field_display_post_ajax_search', array($this, 'display'), 10, 3 );
			add_filter('cmb2_pre_field_display_user_ajax_search', array($this, 'display'), 10, 3 );
			add_filter('cmb2_pre_field_display_term_ajax_search', array($this, 'display'), 10, 3 );

			// Sanitize
			add_action('cmb2_sanitize_post_ajax_search', array($this, 'sanitize'), 10, 4);
			add_action('cmb2_sanitize_user_ajax_search', array($this, 'sanitize'), 10, 4);
			add_action('cmb2_sanitize_term_ajax_search', array($this, 'sanitize'), 10, 4);

			// Ajax request
			add_action('wp_ajax_cmb_ajax_search_get_results', array($this, 'get_results'));
		}

		public function convert_as_id_css($name){
			return str_replace('__', '_', str_replace('[', '_', str_replace(']', '_', $name)));
		}

		/**
		 * Render field
		 */
		public function render($field, $value, $object_id, $object_type, $field_type){
			$field_name = $this->convert_as_id_css($field->_name());
			$default_limit = 1;

			// Current filter is cmb2_render_{$object_to_search}_ajax_search ( post, user or term )
			$object_to_search = str_replace('cmb2_render_', '', str_replace('_ajax_search', '', current_filter()));

			if(!is_array($value) && strpos($value, ', ')){
				$value = explode(', ', $value);
			}

			if($field->args('multiple-item') == true){
				$default_limit = -1; // 0 or -1 means unlimited
			?>
				<ul id="<?php echo $field_name; ?>_results" class="cmb-ajax-search-results cmb-<?php echo $object_to_search; ?>-ajax-search-results">
				<?php
					if(isset($value) && !empty($value)){
						if(!is_array($value)){
							$value = array($value);
						}

					foreach($value as $val):
				?>
					<li>
						<?php if($field->args('sortable')): ?>
							<span class="hndl"></span>
						<?php endif; ?>
						<input type="hidden" name="<?php echo $field->_name(); ?>[]" value="<?php echo $val; ?>">
						<a href="<?php echo $this->object_link($field->_name(), $val, $object_to_search); ?>" target="_blank" class="edit-link">
							<?php echo $this->object_text($field->_name(), $val, $object_to_search); ?>
						</a>
						<a class="remover"><span class="dashicons dashicons-no"></span><span class="dashicons dashicons-dismiss"></span></a>
					</li>
				<?php
					endforeach;
				}

				?>
			</ul>
			<?php

			$input_value = '';
			} else {
				if(is_array($value)){
					$value = $value[0];
				}

				echo $field_type->input(array(
					'type' 	=> 'hidden',
					'name' 	=> $field->_name(),
					'value' => $value,
					'desc'	=> false
				));

				$input_value = ($value ? $this->object_text($field_name, $value, $object_to_search) : '' );
			}

			echo $field_type->input(array(
				'type' => 'text',
				'name' => '_' . $field->_name(),
				'id' => '_' . $field->_name(),
				'class' => 'cmb-ajax-search cmb-' . $object_to_search . '-ajax-search',
				'value' => $input_value,
				'desc' => false,
				'data-value' => $input_value,
				'data-multiple' => $field->args('multiple-item') ? $field->args('multiple-item') : '0',
				'data-limit' => $field->args('limit') ? $field->args('limit') : $default_limit,
				'data-sortable'	=> $field->args('sortable') ? $field->args('sortable') : '0',
				'data-object-type' => $object_to_search,
				'data-query-args'	=> $field->args('query_args') ? htmlspecialchars(json_encode($field->args('query_args')), ENT_QUOTES, 'UTF-8') : ''
			));

			echo '<img src="' . admin_url('images/spinner.gif') . '" class="cmb-ajax-search-spinner" />';

			$field_type->_desc(true, true);
		}

		/**
		 * Display field
		 */
		public function display($pre_output, $field, $display){
			$object_type = str_replace('cmb2_pre_field_display_', '', str_replace('_ajax_search', '', current_filter()));

			ob_start();

			$field->peform_param_callback('before_display_wrap');

			printf("<div class=\"cmb-column %s\" data-fieldtype=\"%s\">\n", $field->row_classes('display'), $field->type());

			$field->peform_param_callback('before_display');

			if(is_array($field->value)): ?>
				<?php foreach($field->value as $value): ?>
					<a href="<?php echo $this->object_link($field->args['id'], $value, $object_type); ?>" class="edit-link">
						<?php echo $this->object_text( $field->args['id'], $value, $object_type ); ?>
					</a>
					<br />
				<?php endforeach; ?>
			<?php else : ?>
				<a href="<?php echo $this->object_link($field->args['id'], $field->value, $object_type); ?>" class="edit-link">
					<?php echo $this->object_text($field->args['id'], $field->value, $object_type); ?>
				</a>
			<?php 
			endif;
			
			$field->peform_param_callback('after_display');

			echo "\n</div>";

			$field->peform_param_callback('after_display_wrap');

			$pre_output = ob_get_clean();

			return $pre_output;
		}

		/**
		 * Optionally save the latitude/longitude values into two custom fields
		 */
		public function sanitize($override_value, $value, $object_id, $field_args) {
			if(!is_array($value) || !(array_key_exists('repeatable', $field_args) && $field_args['repeatable'] == TRUE)){
				return $override_value;
			}

			$new_values = array();
			foreach($value as $key => $val){
				$new_values[$key] = array_filter(array_map('sanitize_text_field', $val));
			}

			return array_filter(array_values($new_values));
		}

		/**
		 * Enqueue scripts and styles
		 */
		public function setup_admin_scripts() {
			$baseUrl = apply_filters('cmb2_field_ajax_search_url', get_template_directory_uri() . '/vendor/ed-itsolutions/cmb2-field-ajax-search/');

			wp_register_script('jquery-autocomplete-ajax-search', $baseUrl . 'js/jquery.autocomplete.min.js', array('jquery'), self::VERSION, true);
			wp_register_script('cmb-ajax-search', $baseUrl . 'js/ajax-search.js', array('jquery', 'jquery-autocomplete-ajax-search', 'jquery-ui-sortable' ), self::VERSION, true);

			wp_localize_script('cmb-ajax-search', 'cmb_ajax_search', array(
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
				'nonce'	=> wp_create_nonce('cmb_ajax_search_get_results'),
				'options' => apply_filters('cmb_field_ajax_search_autocomplete_options', array())
			));

			wp_enqueue_script('cmb-ajax-search');
			wp_enqueue_style('cmb-ajax-search', $baseUrl . 'css/ajax-search.css', array(), self::VERSION);

		}

		/**
		 * Ajax request : get results
		 */
		public function get_results(){
			$nonce = $_POST['nonce'];

			if(!wp_verify_nonce($nonce, 'cmb_ajax_search_get_results')){
				// Wrong nonce
				die(json_encode(array(
					'error' => __('Error : Unauthorized action')
				)));
			} else if(
				(!isset($_POST['field_id']) || empty($_POST['field_id']))
				||
				(!isset($_POST['object_type']) || empty($_POST['object_type']))
			){
				// Wrong request parameters (field_id and object_type are mandatory)
				die(json_encode(array(
					'error' => __( 'Error : Wrong request parameters' )
				)));
			} else {
				$query_args	= json_decode(stripslashes(htmlspecialchars_decode($_POST['query_args'])), true);
				$data = array();
				$results = array();
				
				switch($_POST['object_type']){
					case 'post':
						$query_args['s'] = $_POST['query'];
						$query = new WP_Query($query_args);
						$results = $query->posts;
						break;
					case 'user':
						$query_args['search'] = '*' . $_POST['query'] . '*';
						$query = new WP_User_Query( $query_args );
						$results = $query->results;
						break;
					case 'term':
						$query_args['search'] = $_POST['query'];
						$query = new WP_Term_Query( $query_args );
						$results = $query->terms;
						break;
				}

				foreach ($results as $result):
					if($_POST['object_type'] == 'term'){
						$result_id = $result->term_id;
					}else{
						$result_id = $result->ID;
					}

					$data[] = array(
						'id'	=> $result_id,
						'value' => $this->object_text( $_POST['field_id'], $result_id, $_POST['object_type'] ),
						'link'	=> $this->object_link( $_POST['field_id'], $result_id, $_POST['object_type'] )
					);
				endforeach;

				wp_send_json($data);
				exit;
			}
		}

		public function object_text($field_id, $object_id, $object_type){
			$text = '';

			if($object_type == 'post'){
				$text = get_the_title($object_id);
			} else if($object_type == 'user'){
				$text = get_the_author_meta('display_name', $object_id);
			} else if($object_type == 'term'){
				$term = get_term($object_id);

				$text = $term->name;
			}

			$text = apply_filters("cmb_{$field_id}_ajax_search_result_text", $text, $object_id, $object_type);

			return $text;
		}

		public function object_link( $field_id, $object_id, $object_type ) {
			$link = '#';

			if($object_type == 'post'){
				$link = get_edit_post_link($object_id);
			} else if($object_type == 'user'){
				$link = get_edit_user_link($object_id);
			} else if($object_type == 'term'){
				$link = get_edit_term_link($object_id);
			}

			$link = apply_filters( "cmb_{$field_id}_ajax_search_result_link", $link, $object_id, $object_type );

			return $link;
		}
	}

	$cmb2_field_ajax_search = new CMB2_Field_Ajax_Search();
}
