<?php
/**
 * EventON Ajax Handlers
 * Handles AJAX requests via wp_ajax hook (both admin and front-end events)
 *
 * @author 		AJDE
 * @category 	Core
 * @package 	EventON/Functions/AJAX
 * @version     5.0
 */

class EVO_AJAX{
	/**
	 * Hook into ajax events
	 */

	private $helper;

	public static function init(){

		add_action( 'init', array( __CLASS__, 'define_ajax' ), 0 );
		add_action( 'template_redirect', array( __CLASS__, 'do_evo_ajax' ), 0 );
		self::add_ajax_events();

		// deprecating in 4.5
		add_filter('evo_ajax_general_send_results',array(__CLASS__, 'general_send_req'), 10,2);
	}	

	// AJAX via endpoints @since 4.4
		
		// Get Ajax Endpoint.	
		public static function get_endpoint( $request = '' ) {
			return esc_url_raw( apply_filters( 'eventon_ajax_get_endpoint', add_query_arg( 'evo-ajax', $request, remove_query_arg( array( '_wpnonce' ), home_url( '/', 'relative' ) ) ), $request ) );
		}

		// Set AJAX constant and headers.
		public static function define_ajax() {
			// phpcs:disable
			if ( ! empty( $_GET['evo-ajax'] ) ) {
				evo_maybe_define_constant( 'DOING_AJAX', true );
				evo_maybe_define_constant( 'EVO_DOING_AJAX', true );
				if ( ! WP_DEBUG || ( WP_DEBUG && ! WP_DEBUG_DISPLAY ) ) {
					@ini_set( 'display_errors', 0 ); // Turn off display_errors during AJAX events to prevent malformed JSON.
				}
				$GLOBALS['wpdb']->hide_errors();
			}
			// phpcs:enable
		}

		// Send headers for Ajax Requests.
		private static function evo_ajax_headers() {
			if ( ! headers_sent() ) {
				send_origin_headers();
				send_nosniff_header();
				evo_nocache_headers();
				header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
				header( 'X-Robots-Tag: noindex' );
				status_header( 200 );
			} elseif ( Constants::is_true( 'WP_DEBUG' ) ) {
				headers_sent( $file, $line );
				trigger_error( "evo_ajax_headers cannot set headers - headers already sent by {$file} on line {$line}", E_USER_NOTICE ); // @codingStandardsIgnoreLine
			}
		}

		// Ajax request and fire action
		public static function do_evo_ajax(){
			global $wp_query;

			// phpcs:disable WordPress.Security.NonceVerification.Recommended
			if ( ! empty( $_GET['evo-ajax'] ) ) {
				$wp_query->set( 'evo-ajax', sanitize_text_field( wp_unslash( $_GET['evo-ajax'] ) ) );
			}

			$action = $wp_query->get( 'evo-ajax' );

			if ( $action ) {
				self::evo_ajax_headers();
				$action = sanitize_text_field( $action );
				do_action( 'evo_ajax_' . $action );
				wp_die();
			}
			// phpcs:enable
		}

	// AJAX events
		public static function add_ajax_events(){
			$ajax_events = array(
				'init_load'=>'init_load',			
				'ajax_events_data'=>'ajax_events_data',			
				'get_events'=>'main_ajax_call',		
				'get_instant_cal'=> 'get_instant_calendar',	
				//'the_ajax_hook'=>'main_ajax_call',			
				'load_event_content'=>'load_event_content',
				'load_single_eventcard_content'=>'load_single_eventcard_content',
				'search_evo_events'=>'search_evo_events',
				'get_local_event_time'=>'get_local_event_time',
				'refresh_now_cal'=>'refresh_now_cal',
				'record_mod_joined'=>'record_mod_joined',
				'refresh_elm'=>'refresh_elm',
				'gen_trig_ajax'=>'gen_trig_ajax',
				'get_tax_card_content'=>'get_tax_card_content',
			);

			$restricted_actions = [];

			foreach ( $ajax_events as $ajax_event => $class ) {
				$prepend = ( in_array($ajax_event, array('the_ajax_hook','evo_dynamic_css','the_post_ajax_hook_3','the_post_ajax_hook_2')) )? '': 'eventon_';
				add_action( 'wp_ajax_'. $prepend . $ajax_event, array( __CLASS__, $class ) );				

				// for non loggedin user actions
				if( in_array( $ajax_event, $restricted_actions)){
					add_action( 'wp_ajax_nopriv_'. $prepend . $ajax_event, array( __CLASS__, 'restrict_unauthenticated' ) );
				}else{
					add_action( 'wp_ajax_nopriv_'. $prepend . $ajax_event, array( __CLASS__, $class ) );
				}

				// EVO AJAX can be used for frontend ajax requests.
				add_action( 'evo_ajax_' . $prepend . $ajax_event, array( __CLASS__ , $class ) );
			}

			//add_action('evo_ajax_rest_eventon_get_events', array(__CLASS__, 'main_ajax_call'));
		}

	// Handle unauthenticated requests
    public static function restrict_unauthenticated() {
        wp_send_json( array( 'status' => 'bad', 'msg' => __( 'Authentication required', 'eventon' )) );
        wp_die();
    }

	// Initial load
		public static function init_load($return = false){
			
			// nonce verification
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false, 'json',false, true, 'evo_load_events' );

			$post_data = EVO()->helper->recursive_sanitize_array_fields( $_POST);	

			// init load calendar events
			$calendars = [];
			if(isset($post_data['cals']) && is_array($post_data['cals'])){
				foreach($post_data['cals'] as $cal_id => $cal_data){
					if(!isset( $cal_data['sc'])) continue;

					$SC = EVO()->helper->sanitize_array( $cal_data['sc'] );
					EVO()->calendar->process_arguments( $SC );

					// get events for the calendar
					$events = EVO()->calendar->_generate_events('both', apply_filters('evo_init_ajax_wparg_additions', []));
					$calendars[$cal_id] = [
		                'sc' => $SC,
		                'json' => $events['data'],
		                'html' => $events['html']
		            ];
				}
			}

			$global = isset($post_data['global'])? 	EVO()->helper->sanitize_array( $post_data['global'] ): [];

			$response =  apply_filters('evo_init_ajax_data', array(
				'cal_def'=> EVO()->calendar->helper->get_calendar_defaults(),
				'temp'=> EVO()->temp->get_init(),
				'dms' => array(
					'd'=> EVO()->cal->get_all_day_names(),
					'd3'=> EVO()->cal->get_all_day_names('three'),
					'd1'=> EVO()->cal->get_all_day_names('one'),
					'm'=> EVO()->cal->_get_all_month_names(),
					'm3'=> EVO()->cal->_get_all_month_names('short'),
				),		
				'cals'=> apply_filters('evo_init_ajax_cals',$calendars),		
				'txt'=> array(
					'no_events'=> evo_lang('No Events'),
					'all_day'=> evo_lang_get('evcal_lang_allday','All Day'),
					'event_completed'=> evo_lang('Event Completed'),
				), 
				'html'=>array(
					'no_events' => EVO()->calendar->helper->get_no_event_content(),
				),	
				// language translated texts for client side
				'terms'=> [],
			), $global);

			wp_send_json( $response ); wp_die();

		}

	// General ajax call - added 3.1
		public static function gen_trig_ajax(){

			// nonce verification
			EVO()->helper->validate_request( 'nn', 'eventon_nonce', false, false, false );			
			$PP = $this->helper->recursive_sanitize_array_fields( $_POST );		
			wp_send_json(
				apply_filters('evo_ajax_general_send_results', array('status'=>'good'), $PP)
			);			
		}

	// get taxonomy lightbox card details u 4.6
		public static function get_tax_card_content(){
			$post = EVO()->helper->sanitize_array( $_POST );

			evo_set_global_lang( isset($post['lang'])? $post['lang']:'L1' ); // 4.6.3
			
			// not supported tax @4.8.1
			if( !in_array( $post['tax'], apply_filters('evo_supported_tax_for_lb', array('event_organizer', 'event_location')) )
			){
				wp_send_json(					
					array(
						'status'=>'bad',
						'content'=> __('This event category is not supported for more details')
					)
				); wp_die();
			}

			// supported tax
			$event_id = !empty($post['eventid']) ? $post['eventid']: '';
			$tax = new EVO_Tax($event_id);

			
			wp_send_json(					
				array(
					'status'=>'good',
					'content'=> $tax->get_lightbox_content( $post ) ,
				)
			);
			

			wp_die();
		}

	// get instant calendar anywhere
		public static function get_instant_calendar(){
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false );

			$postdata = EVO()->helper->sanitize_array( $_POST );

			EVO()->calendar->process_arguments( $postdata['shortcode'] );
			$SC = EVO()->calendar->shortcode_args;

			$DD = new DateTime('now');
			$DD->setTimezone( EVO()->calendar->cal_tz );
			//$DD->setDate($fixed_year,$fixed_month,1 );
			$DD->setTime(0,0,0);
			$SC['fixed_day'] = $DD->format('j');
			$SC['fixed_month'] = $DD->format('n');
			$SC['fixed_year'] = $DD->format('Y');
			$SC['focus_start_date_range'] = $DD->format('U');

			// end range
			$number_of_months = empty($SC['number_of_months']) ? 1: (int)$SC['number_of_months'];

			$DD->modify("+{$number_of_months} months")->modify('last day of this month');

			$DD->setTime(23,59,59);
			$SC['focus_end_date_range'] = $DD->format('U');	

			extract($SC);

			ob_start();

			// cal header
				$header_args = [
					'focused_month_num'=>$fixed_month,
					'focused_year'=>$fixed_year,
					'_classes_calendar'=> 'yes',
					'initial_ajax_loading_html'=> ($cal_init_nonajax=='yes'? false:true),
					'date_header'=> ($number_of_months>1? false:true),
				];

				echo EVO()->calendar->body->get_calendar_header($header_args);	

				$events = EVO()->calendar->_generate_events('both', apply_filters('evo_init_ajax_wparg_additions', []));	

				echo $events['html'];

				echo EVO()->calendar->body->get_calendar_footer();


			wp_send_json([
				'status'=> 'good',
				'html'=>  ob_get_clean(),
				'SC'=> $SC,
				'debug' => array(
						's' => date('y-m-d h:i:s', $focus_start_date_range),
						'e' => date('y-m-d h:i:s', $focus_end_date_range),
						'su'=> $focus_start_date_range, 
						'eu'=> $focus_end_date_range,
					),
			]);	
			wp_die();
		}
	// Primary function to load event data 
		public static function main_ajax_call(){

			// nonce verification
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false, 'json',false, true, 'evo_load_events' );

			$postdata = EVO()->helper->sanitize_array( $_POST );
			$shortcode_args = $focused_month_num = $focused_year = '';
			$status = 'GOOD';

			// shortcode processing
			$SC = isset($postdata['shortcode']) ? $postdata['shortcode']: [];
			if( isset( $SC['lang'])) evo_set_global_lang( sanitize_text_field( $SC['lang'] ) );		
			$ajaxtype = isset($postdata['ajaxtype'])? $postdata['ajaxtype']: '';

			extract($SC);

			if(empty($number_of_months)){ return false; exit; }
			if($number_of_months < 1){ return false; exit; }

			EVO()->calendar->shortcode_args = $SC;
							
			// date range calculation
				if( isset($SC['focus_start_date_range']) && isset($SC['focus_end_date_range']) ){
					$focus_start_date_range = (int)$SC['focus_start_date_range'];
					$focus_end_date_range = (int)$SC['focus_end_date_range'];
				}

				$calendar_type = 'default';

				// event list with more than one month
				if( $SC['number_of_months']==1){

					// calculate new date range if calendar direction is changing
					if($postdata['direction'] !='none'){
						if(!empty($fixed_month) && !empty($fixed_year)){

							$DD = new DateTime('now');
							$DD->setTimezone( EVO()->calendar->cal_tz );
							$DD->setDate($fixed_year,$fixed_month,1 );
							$DD->setTime(0,0,0);

							// get previous or next month
							( $postdata['direction']=='next' ) ?	
								$DD->modify('+1 month') : $DD->modify('-1 month');
							

							$SC['fixed_day'] = $DD->format('j');
							$SC['fixed_month'] = $DD->format('n');
							$SC['fixed_year'] = $DD->format('Y');
							$SC['focus_start_date_range'] = $DD->format('U');
							$DD->modify('last day of this month');
							$DD->setTime(23,59,59);
							$SC['focus_end_date_range'] = $DD->format('U');	

						}
					}else{ // not switching months

						// Going to today
						if($ajaxtype == 'today' || $ajaxtype == 'jumper'){
							$SC['focus_start_date_range']='';
							$SC['focus_end_date_range']='';	
							EVO()->calendar->shortcode_args = $SC;						
							EVO()->calendar->shell->set_calendar_range();	
							$SC = EVO()->calendar->shortcode_args;
						}
					}

				}else{	$calendar_type = 'list';	}
														

			// set calendar shortcode values
				$SC = apply_filters('eventon_ajax_arguments',$SC, $postdata, $ajaxtype);		
				ksort($SC);
				extract($SC);

				EVO()->calendar->shortcode_args = $SC; // set arguments to the calendar object
					
			// GET calendar header month year values
				$calendar_month_title = get_eventon_cal_title_month($fixed_month, $fixed_year, $lang);
						
			// Calendar content		
				$content = EVO()->evo_generator->_generate_events();

			// RETURN VALUES
				wp_send_json( 
					apply_filters('evo_ajax_query_returns', array(
					'status'=> 					$status,
					'json'=> 					$content['data'],	
					'html'=>					$content['html'],				
					'cal_month_title'=>			$calendar_month_title,
					'SC'=> 	$SC,
					'debug' => array(
						's' => date('y-m-d h:i:s', $focus_start_date_range),
						'e' => date('y-m-d h:i:s', $focus_end_date_range),
						'su'=> $focus_start_date_range, 
						'eu'=> $focus_end_date_range,
					),
					
				), 
				$SC, $content) );
		}

	// AJAX Events data
		function ajax_events_data(){
			$postdata = EVO()->helper->sanitize_array( $_POST );

			$SC = isset($postdata['shortcode']) ? $postdata['shortcode']: array();
			EVO()->calendar->shortcode_args = $SC;
		}

	// Now Calendar
		public static function refresh_now_cal(){

			// nonce verification
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false );

			$post_data = EVO()->helper->sanitize_array( $_POST );

			$calnow = new Evo_Calendar_Now();

			$SC = isset($post_data['SC']) ? $post_data['SC']: array();
			
			$defA = isset($post_data['defA']) ? $post_data['defA'] : array();

			$args = array_merge($defA, $SC);

			$calnow->process_a( $args );

			ob_start();
			$calnow->get_body( true );
			$html = ob_get_clean();

			wp_send_json(
				array(
					'status'=>'good',
					'html'=> $html,
				)
			);
		}

	// refresh elements
		public static function refresh_elm(){

			// nonce verification
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false );

			$PP = EVO()->helper->sanitize_array( $_POST );
			wp_send_json( self::get_refresh_elm_data( $PP ));	
		}

		//get ajax refresh element's data array
		public static function get_refresh_elm_data($PP, $type ='ajax'){
			$response = array();

			if(isset($PP['evo_data']) && is_array($PP['evo_data']) ){
				
				foreach($PP['evo_data'] as $ekey=>$classes){

					$ee = explode('_', $ekey);
					$EVENT = new EVO_Event($ee[0], '', (int)$ee[1] );

					foreach( $classes as $classnm=>$classdata){

						$response['evo_data'][ 'event_'.$EVENT->ID.'_'.$EVENT->ri][$classnm] = apply_filters('evo_ajax_refresh_elm', 
							array(
								'html'=> '',
								'data'=> $classdata,
							), $EVENT, $classnm, $classdata, $type, $PP
						);

						$response['status'] = 'good';
					}

					$response['evo_data'][ 'event_'.$EVENT->ID.'_'.$EVENT->ri] = apply_filters('evo_ajax_refresh_event_elms', 
						$response['evo_data'][ 'event_'.$EVENT->ID.'_'.$EVENT->ri],
						$EVENT , $classes, $type, $PP
					);
					
				}									
			}
			return $response;
		}

	// record moderator joined for virtual events
		public static function record_mod_joined(){			

			if(!isset($_POST['eid'])) return false;
			if(!isset($_POST['ri'])) return false;
			if(!isset($_POST['nonce'])) return false;
			if(!isset($_POST['joined'])) return false;

			if(!wp_verify_nonce($_POST['nonce'], 'eventon_nonce')) {echo 'nonce failed'; exit;}

			$postdata = EVO()->helper->sanitize_array( $_POST );

			$EVENT = new EVO_Event( (int)$postdata['eid'], (int)$postdata['eid'] );

			// joined in or left
			$joined = ($postdata['joined'] == 'yes') ? 'in': 'left';

			$EVENT->record_mod_joined($joined);

			wp_send_json(array(
				'status'=>'good',
				'msg'=> ( $joined =='in' ? __('Recorded as moderator joined','eventon') : 
						__('Recorded as moderator left','eventon') )
			));
		}


	// Load single event content
	// @2.6.13 
		public static function load_event_content(){

			// nonce verification
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false );

			$post_data = EVO()->helper->recursive_sanitize_array_fields( $_POST );

			if(!isset($post_data['eid'])) return false;
			if(!isset($post_data['nonce'])) return false;			

			$EVENT = new EVO_Event( (int)$post_data['eid']);

			wp_send_json(
				apply_filters('evo_single_event_content_data',array(), $EVENT)
			);
		}

	// load single eventcard content
	// @ 2.9.2 @u 4.4.4
		public static function load_single_eventcard_content(){

			// nonce verification
			EVO()->helper->validate_request( 'nn', 'eventon_nonce', false, false, false );
 

			$postdata = EVO()->helper->sanitize_array( $_POST );

			$event_id = (int) $postdata['event_id'];
			$ri = (int) $postdata['ri'];

			$SC = array();
			if( isset($postdata['SC']) ) $SC = $postdata['SC'];
			if( isset($postdata['sc']) ) $SC = $postdata['sc'];

			$lang = isset($SC['lang'])? $SC['lang']:'L1';

			$SC['show_exp_evc'] = 'yes';
			
			$event_data = EVO()->calendar->get_single_event_data( $event_id, $lang, $ri, $SC);

			if($event_data && is_array($event_data)) $event_data = $event_data[0];

			$event_html_content = $event_data['content'];

			unset($event_data['content']);

			wp_send_json(
				apply_filters('evoajax_single_eventcard_data',
					array(
						'status'=>'good',
						'content'=> $event_html_content, 
						'data'=> $event_data
					),
					$event_data, $postdata
				)
			); 
		}

	// OUTPUT: json headers
		private function json_headers() {		header( 'Content-Type: application/json; charset=utf-8' );	}



	

	// get event time based on local time on browswr
		public static function get_local_event_time(){
			$post_data = EVO()->helper->recursive_sanitize_array_fields( $_POST );
			
			$datetime = new evo_datetime();
			$offset = $datetime->get_UTC_offset();
			$brosweroffset = (int)$post_data['browser_offset'] *60;
			echo $brosweroffset.' '.$offset.' '.$object->evvals['evcal_srow'][0];

			$newunix = $object->evvals['evcal_srow'][0] + ($offset + $brosweroffset);
			echo date('Y-m-d h:ia', $newunix);
			wp_die();
		}


	// Search results for ajax search of events from search box
	// @updated 4.9.8
		public static function search_evo_events(){

			// nonce verification
			EVO()->helper->validate_request( 'nonce', 'eventon_nonce', false, false, false );
						
			$postdata = EVO()->helper->sanitize_array( $_POST );
			$searchfor = isset($postdata['search']) ? $postdata['search'] :'';
			$shortcode = isset($postdata['shortcode']) ? $postdata['shortcode']: array();
		
			$searchfor = str_replace("'","\'", $searchfor);

			
			// if search all events regardless of date
				if( !empty($shortcode['search_all'] ) && $shortcode['search_all']=='yes'){
					$DD = EVO()->calendar->DD;
					$DD->modify('first day of this month'); $DD->setTime(0,0,0);
					$DD->modify('-15 years');
					
					$__focus_start_date_range = $DD->format('U');
					
					$DD->modify('+30 years');
					$__focus_end_date_range = $DD->format('U');
				
				}else{	

					$DD = new DateTime();
					$DD->setTimezone( EVO()->calendar->cal_tz );
					$DD->setTimestamp( EVO()->calendar->current_time );

					$__focus_start_date_range = $DD->format('U');


					$current_timestamp = current_time('timestamp');

					// send end range based on number of months
						$number_of_months = !empty($shortcode['number_of_months'])? $shortcode['number_of_months']:12;

						$DD->modify( '+' . $number_of_months . 'months' );

						$__focus_end_date_range = $DD->format( 'U' );
				}
			

			// Add extra arguments to shortcode arguments			
				$new_arguments = array(
					'focus_start_date_range'=>$__focus_start_date_range,
					'focus_end_date_range'=>$__focus_end_date_range,
					's'=>$searchfor,
					'search_all'=> (isset($shortcode['search_all'])? $shortcode['search_all']:'no')
				);

				$args = (!empty($args) && is_array($args))? 
					wp_parse_args($new_arguments, $args): $new_arguments;

				// merge passed shortcode values
					if(!empty($shortcode))
						$args= wp_parse_args($shortcode, $args);

				EVO()->calendar->process_arguments($args);

				$content = EVO()->calendar->body->get_calendar_header(
					array(
						'date_header'=>false,
						'sortbar'=>true,
						'range_start'=>$__focus_start_date_range,
						'range_end'=>$__focus_end_date_range,
						'header_title'=>'',
						'send_unix'=>true
					)
				);

				$content .= EVO()->calendar->_generate_events('html');
				
				$content .= EVO()->calendar->body->get_calendar_footer();
				
				wp_send_json(array(
					'content'=>$content,
					'range'=> date('Y-m-d', $__focus_start_date_range).' '.date('Y-m-d', $__focus_end_date_range)
				));
				wp_die();
		}

	// deprecating
	public static function general_send_req($a1, $post){
		return $a1;
	}

}

EVO_AJAX::init();
