<?php
/**
 * @package      CMB2\Field_Ajax_Search
 * @author       Tsunoa
 * @copyright    Copyright (c) Tsunoa
 *
 * Plugin Name: CMB2 Field Type: Ajax Search
 * Plugin URI: https://github.com/rubengc/cmb2-field-ajax-search
 * GitHub Plugin URI: https://github.com/rubengc/cmb2-field-ajax-search
 * Description: CMB2 field type to attach posts, users or terms.
 * Version: 1.0.
 * Author: Tsunoa
 * Author URI: https://tsunoa.com/
 * License: GPLv2+
 */

// This plugin is based on CMB2 Field Type: Post Search Ajax (https://github.com/alexis-magina/cmb2-field-post-search-ajax)
// Special thanks to Magina (http://magina.fr/) for him awesome work

if( ! class_exists( 'CMB2_Field_Ajax_Search' ) ) {

	/**
	 * Class CMB2_Field_Ajax_Search
	 */
	class CMB2_Field_Ajax_Search {

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

		/**
		 * 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 endpoints.
			add_action( 'wjbp_ajax_cmb_ajax_search_get_results', array( $this, 'get_results' ) );
			
			// Ajax request
			add_action( 'wp_ajax_cmb_ajax_search_get_results', array( $this, 'get_results' ) );
		}

		/**
		 * Render field
		 */
		public function render( $field, $value, $object_id, $object_type, $field_type ) {

			$this->setup_admin_scripts();

			$value = $field->default() ? $field->default() : $value;
			$field_name = $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( $field->args( 'multiple' ) == 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_html( $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];
				}
				
				?>
				<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 ) ){
					
                    ?>
					<li>
                        <?php if( $field->args( 'sortable' ) ) : ?><span class="hndl"></span><?php endif; ?>
                        <a href="<?php echo $this->object_link( $field_name, $value, $object_to_search ); ?>" target="_blank" class="edit-link">
                            <?php echo $this->object_text_html( $field_name, $value, $object_to_search ); ?>
                        </a>
                    </li>
                    <?php
				}

                ?></ul><?php

				$input_value = '';


				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 . '_input',
				'id'				=> $field_name . '_input',
				'class'				=> 'cmb-ajax-search cmb-' . $object_to_search . '-ajax-search',
				'value' 			=> $input_value,
				'desc'				=> false,
				'data-multiple'		=> $field->args( 'multiple' ) ? $field->args( 'multiple' ) : '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_html( $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_html( $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 ) {
			$fid = $field_args['id'];

			if( !empty($field_args['render_row_cb'][0]->data_to_save[$field_args['id']]) ) {
				$value = $field_args['render_row_cb'][0]->data_to_save[$field_args['id']];
			} else {
				$value = false;
			}

			return $value;
		}

		/**
		 * Enqueue scripts and styles
		 */
		public function setup_admin_scripts() {

			wp_register_script( 'jquery-autocomplete-ajax-search', plugins_url( 'js/jquery.autocomplete.min.js', __FILE__ ), array( 'jquery' ), self::VERSION, true );
			wp_register_script( 'cmb-ajax-search', plugins_url( 'js/ajax-search.js', __FILE__ ), 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' ),
				'ajaxurl_endpoint' => WP_Job_Board_Pro_Ajax::get_endpoint(),
				'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', plugins_url( 'css/ajax-search.css', __FILE__ ), 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', 'wp-job-board-pro' )
                ) ) );
			} 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', 'wp-job-board-pro' )
                ) ) );
            } 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'] ),
                        'value_html' => $this->object_text_html( $_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' ) {
				if ( WP_Job_Board_Pro_User::is_employer($object_id) ) {
					$employer_id = WP_Job_Board_Pro_User::get_employer_by_user_id($object_id);
					$avatar = get_the_post_thumbnail( $employer_id, 'thumbnail' );
					$title = get_the_title($employer_id);
				} else {
					$avatar = get_avatar( $object_id, 80 );
					$title = get_the_author_meta('display_name', $object_id);
				}

				$text = $title.'('.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_text_html( $field_id, $object_id, $object_type ) {
			$text = '';

			if( $object_type == 'post' ) {
				$post_type = get_post_type($object_id);
				if ( $post_type == 'employer' || $post_type == 'candidate' ) {

					$avatar = get_the_post_thumbnail( $object_id, 'thumbnail' );
					$title = get_the_title($object_id);
					
					$text = '<div class="user-wrapper clearfix">';
					$text .= '<div class="user-avatar">'.$avatar.'</div>';
					$text .= '<div class="user-text">'.$title.'</div>';
					$text .= '</div>';
				} else {
					$text = get_the_title( $object_id );
				}
			} else if( $object_type == 'user' ) {
				if ( WP_Job_Board_Pro_User::is_employer($object_id) ) {
					$employer_id = WP_Job_Board_Pro_User::get_employer_by_user_id($object_id);
					$avatar = get_the_post_thumbnail( $employer_id, 'thumbnail' );
					$title = get_the_title($employer_id).' ('.get_the_author_meta('display_name', $object_id).')';
				} else {
					$avatar = get_avatar( $object_id, 80 );
					$title = get_the_author_meta('display_name', $object_id);
				}
				$text = '<div class="user-wrapper clearfix">';
				$text .= '<div class="user-avatar">'.$avatar.'</div>';
				$text .= '<div class="user-text">'.$title.'</div>';
				$text .= '</div>';
			} 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();

}

