<?php
use EM\Bookings\Uploads;

class EM_Booking_Form {

	use \EM\List_Table\Forms;

	static $validate;
	/**
	 * @var EM_Form
	 */
	static $form;
	static $form_id;
	static $event_id;
	static $form_name;
	static $form_template;
	static $form_meta_key              = 'booking-form';
	public static $default_form_option = 'em_booking_form_fields';

	public static function init() {
		include_once 'uploads.php';
		//Menu/admin page
		add_action( 'admin_init', array( 'EM_Booking_Form', 'admin_page_actions' ), 10 );
		add_action( 'emp_forms_admin_page', array( 'EM_Booking_Form', 'admin_page' ), 10 );
		//Booking admin and exports
		add_action( 'em_bookings_single_custom', array( 'EM_Booking_Form', 'em_bookings_single_custom' ), 1, 1 ); //show booking form and ticket summary
		//Booking Tables UI
		static::init_booking_table_hooks();
		add_filter( 'em_bookings_table_cols_template_groups', array( static::class, 'em_bookings_table_cols_template_groups' ), 10, 2 );
		add_filter( 'em_bookings_table_rows_col', array( static::class, 'em_bookings_table_rows_col' ), 10, 5 );
		// Actions and Filters
		add_action( 'em_booking_form_custom', array( 'EM_Booking_Form', 'booking_form' ), 10, 1 ); //handle the booking form template
		//Booking interception
		$booking_button_request = ! empty( $_REQUEST['action'] ) && $_REQUEST['action'] == 'booking_add_one' && is_user_logged_in(); //in order to disable the form if booking button is pressed
		if ( ! $booking_button_request ) {
			if ( get_option( 'dbem_multiple_bookings' ) ) {
				//Mulitiple Booking Mode
				add_filter( 'em_multiple_booking_get_post', array( 'EM_Booking_Form', 'em_booking_get_post' ), 10, 2 ); //get post data + validate
				add_filter( 'em_multiple_booking_validate', array( 'EM_Booking_Form', 'em_booking_validate' ), 10, 2 ); //validate object
			}
			//Normal bookings
			add_filter( 'em_booking_save', array( 'EM_Booking_Form', 'em_booking_save' ), 1, 2 ); // save files such as uplaods, add new user fields to current EM_Person instance for use on this run
			add_filter( 'em_booking_get_post', array( 'EM_Booking_Form', 'em_booking_get_post' ), 10, 2 ); //get post data + validate
			add_filter( 'em_booking_validate', array( 'EM_Booking_Form', 'em_booking_validate' ), 10, 2 ); //validate object
			add_action( 'em_bookings_added', array( 'EM_Booking_Form', 'em_bookings_added' ), 10, 1 ); //add extra user reg data
			add_action( 'em_booking_deleted', array( 'EM_Booking_Form', 'em_booking_deleted' ), 10, 1 );
			add_filter( 'em_register_new_user_pre', array( 'EM_Booking_Form', 'em_register_new_user_pre' ), 10, 1 ); //add extra use reg data
		}
		//Placeholder overriding
		add_filter( 'em_booking_output_placeholder', array( 'EM_Booking_Form', 'placeholders' ), 1, 5 ); //for emails
		//custom form chooser in event bookings meta box:
		add_action( 'em_events_admin_bookings_footer', array( 'EM_Booking_Form', 'event_bookings_meta_box' ), 20, 1 );
		add_action( 'em_event_save_meta_pre', array( 'EM_Booking_Form', 'em_event_save_meta_pre' ), 10, 1 );
		add_action( 'rest_api_init', array( 'EM_Booking_Form', 'register_api' ) );
		add_action( 'wp_abilities_api_init', array( 'EM_Booking_Form', 'api_register_abilities' ) );
		add_filter( 'em_api_prepare_event', array( 'EM_Booking_Form', 'api_prepare_event' ), 10, 3 );
		add_filter( 'em_api_event_input_schema', array( 'EM_Booking_Form', 'api_event_input_schema' ), 10, 2 );
		add_action( 'em_api_event_save_pre', array( 'EM_Booking_Form', 'api_event_save_pre' ), 10, 3 );
		add_action( 'em_api_event_save', array( 'EM_Booking_Form', 'api_event_save' ), 10, 3 );
		//Data Privacy
		add_filter( 'em_data_privacy_export_bookings_item', 'EM_Booking_Form::data_privacy_export', 10, 2 );
	}

	/**
	 * Gets the default form structure for creating a new form
	 * @return array
	 */
	public static function get_form_template() {
		if ( empty( self::$form_template ) ) {
			self::$form_template = apply_filters(
				'em_booking_form_get_form_template',
				array(
					'name'            => array(
						'label'    => emp__( 'Name', 'events-manager' ),
						'type'     => 'name',
						'fieldid'  => 'user_name',
						'required' => 1,
					),
					'user_email'      => array(
						'label'    => emp__( 'Email', 'events-manager' ),
						'type'     => 'user_email',
						'fieldid'  => 'user_email',
						'required' => 1,
					),
					'dbem_address'    => array(
						'label'    => emp__( 'Address', 'events-manager' ),
						'type'     => 'dbem_address',
						'fieldid'  => 'dbem_address',
						'required' => 1,
					),
					'dbem_city'       => array(
						'label'    => emp__( 'City/Town', 'events-manager' ),
						'type'     => 'dbem_city',
						'fieldid'  => 'dbem_city',
						'required' => 1,
					),
					'dbem_state'      => array(
						'label'    => emp__( 'State/County', 'events-manager' ),
						'type'     => 'dbem_state',
						'fieldid'  => 'dbem_state',
						'required' => 1,
					),
					'dbem_zip'        => array(
						'label'    => __( 'Zip/Post Code', 'em-pro' ),
						'type'     => 'dbem_zip',
						'fieldid'  => 'dbem_zip',
						'required' => 1,
					),
					'dbem_country'    => array(
						'label'    => emp__( 'Country', 'events-manager' ),
						'type'     => 'dbem_country',
						'fieldid'  => 'dbem_country',
						'required' => 1,
					),
					'dbem_phone'      => array(
						'label'   => emp__( 'Phone', 'events-manager' ),
						'type'    => 'dbem_phone',
						'fieldid' => 'dbem_phone',
					),
					'dbem_fax'        => array(
						'label'   => __( 'Fax', 'em-pro' ),
						'type'    => 'dbem_fax',
						'fieldid' => 'dbem_fax',
					),
					'booking_comment' => array(
						'label'   => emp__( 'Comment', 'events-manager' ),
						'type'    => 'textarea',
						'fieldid' => 'booking_comment',
					),
				)
			);
		}
		return self::$form_template;
	}

	/**
	 * @param EM_Booking $EM_Booking
	 *
	 * @return EM_Form
	 */
	public static function get_form( $EM_Event = false, $custom_form_id = false ) {
		//special lookup for multiple bookings
		if ( is_object( $custom_form_id ) ) {
			if ( $custom_form_id instanceof EM_Multiple_Booking ) {
				$EM_Booking     = $custom_form_id;
				$custom_form_id = get_option( 'dbem_multiple_bookings_form' );
			} elseif ( $custom_form_id instanceof EM_Booking ) {
				$EM_Booking = $custom_form_id;
			}
		}
		//make sure we don't need to get another form rather than the one already stored in this object
		$event_id = EM_Event::is_id( $EM_Event ); // we don't need to store and refer to the full uid of an event, just the event id itself without timeslots
		$reload   = ( $event_id && $event_id['id'] != self::$event_id ) || ( ! empty( $EM_Event->event_id ) && $EM_Event->event_id != self::$event_id ) || ( empty( $EM_Event ) && $custom_form_id && $custom_form_id != self::$form_id );
		//get the right form
		if ( empty( self::$form ) || $reload ) {
			global $wpdb;
			if ( EM_Event::is_id( $EM_Event ) ) {
				$EM_Event = em_get_event( $EM_Event ); }
			$custom_form_id = ( ! empty( $EM_Event->post_id ) ) ? get_post_meta( $EM_Event->post_id, '_custom_booking_form', true ) : $custom_form_id;
			$form_id        = ! empty( $custom_form_id ) && is_numeric( $custom_form_id ) ? $custom_form_id : get_option( 'em_booking_form_fields' );
			$sql            = $wpdb->prepare( 'SELECT meta_id, meta_value FROM ' . EM_META_TABLE . ' WHERE meta_key = %s AND meta_id=%d', static::$form_meta_key, $form_id );
			$form_data_row  = $wpdb->get_row( $sql, ARRAY_A );
			if ( empty( $form_data_row ) ) {
				$form_data       = array( 'form' => self::get_form_template() );
				self::$form_name = __( 'Default', 'em-pro' );
			} else {
				$form_data       = unserialize( $form_data_row['meta_value'] );
				self::$form_id   = $form_data_row['meta_id'];
				self::$form_name = $form_data['name'];
			}
			self::$event_id                  = ! empty( $EM_Event ) ? $EM_Event->get_event_id() : false;
			self::$form                      = new EM_Form( $form_data['form'], 'em_bookings_form' );
			self::$form->form_required_error = get_option( 'dbem_emp_booking_form_error_required' );
			// set upload folder settings and create this folder if it doesn't exist
		}
		self::$form->uploads_subfolder     = 'bookings';
		self::$form->form_id               = self::$form_id;
		self::$form->uploads_endpoint_uuid = ! empty( $EM_Booking ) ? $EM_Booking->uuid : '';
		return self::$form;
	}

	public static function get_forms() {
		global $wpdb;
		$forms_data = $wpdb->get_results( 'SELECT meta_id, meta_value FROM ' . EM_META_TABLE . " WHERE meta_key = '" . static::$form_meta_key . "'" );
		foreach ( $forms_data as $form_data ) {
			$form                         = unserialize( $form_data->meta_value );
			$forms[ $form_data->meta_id ] = $form['form'];
		}
		return $forms;
	}

	public static function get_forms_names() {
		global $wpdb;
		$forms_data = $wpdb->get_results( 'SELECT meta_id, meta_value FROM ' . EM_META_TABLE . " WHERE meta_key = '" . static::$form_meta_key . "'" );
		$forms      = array();
		foreach ( $forms_data as $form_data ) {
			$form = unserialize( $form_data->meta_value );
			if ( ! empty( $form ) ) {
				$forms[ $form_data->meta_id ] = $form['name'];
			}
		}
		return $forms;
	}

	/**
	 * Shows the actual booking form.
	 * @param EM_Event $event
	 */
	public static function booking_form( $event = false ) {
		global $EM_Event;
		//emp_booking_form_booking_form depreciated, use em_booking_form filter instead at later priority to override this
		if ( ! empty( $event ) ) {
			echo self::get_form( $event );
		} else {
			echo self::get_form( $EM_Event );
		}
	}

	public static function em_register_new_user_pre( $user_array ) {
		global $EM_Booking;
		if ( ! empty( $EM_Booking->booking_meta['registration']['user_login'] ) ) {
			$user_array['user_login'] = $EM_Booking->booking_meta['registration']['user_login'];
		}
		if ( ! empty( $EM_Booking->temporary_password ) ) {
			$user_array['user_pass'] = $EM_Booking->temporary_password;
		}
		return $user_array;
	}

	/**
	 * @param boolean $result
	 * @param EM_Booking $EM_Booking
	 * @return bool
	 */
	public static function em_booking_get_post( $result, $EM_Booking ) {
		//get, store and validate post data
		$EM_Form = self::get_form( $EM_Booking->event_id, $EM_Booking );
		//skip registration fields if manually booking someone that already is a user
		$manual_assigned_booking = ! empty( $_REQUEST['manual_booking'] ) && ! empty( $_REQUEST['person_id'] ) && $_REQUEST['person_id'] > 0 && wp_verify_nonce( $_REQUEST['manual_booking'], 'em_manual_booking_' . $EM_Booking->event_id );
		//get form fields
		if ( $EM_Booking->booking_id ) {
			// merge in old values into form, including user fields if applicable but using the field ID of the main form
			foreach ( $EM_Form->form_fields as $fieldid => $value ) {
				if ( ! empty( $EM_Booking->booking_meta['booking'][ $fieldid ] ) ) {
					$EM_Form->field_values[ $fieldid ] = $EM_Booking->booking_meta['booking'][ $fieldid ];
				}
			}
		} else {
			// add user fields if a new booking, so we don't overwrite things like uploads
			foreach ( $EM_Form->form_fields as $fieldid => $value ) {
				if ( array_key_exists( $fieldid, $EM_Form->user_fields ) ) {
					// get field id of registration
					$user_meta = $EM_Booking->get_user_meta( $fieldid );
					if ( $user_meta ) {
						$EM_Form->field_values[ $fieldid ] = $user_meta;
					}
				}
			}
		}
		if ( $EM_Form->get_post() ) {
			foreach ( $EM_Form->get_values() as $fieldid => $value ) {
				if ( $fieldid == 'user_password' ) {
					$EM_Booking->temporary_password = $value; //assign a random property so it's never saved
				} else {
					//get results and put them into booking meta
					if ( ! $manual_assigned_booking && ( array_key_exists( $fieldid, $EM_Form->user_fields ) || in_array( $fieldid, array( 'user_email', 'user_name' ) ) ) ) {
						//                      if( !(!empty($EM_Booking->booking_id) && $EM_Booking->can_manage()) || empty($EM_Booking->booking_id) ){ //only save reg fields on first go
						if ( empty( $EM_Booking->booking_id ) ) { //only save reg fields on first go
							//registration fields
							$EM_Booking->booking_meta['registration'][ $fieldid ] = $value;
						}
					} elseif ( $fieldid != 'captcha' ) { //ignore captchas only for verification
						//booking fields
						$EM_Booking->booking_meta['booking'][ $fieldid ] = $value;
					}
				}
			}
		} elseif ( count( $EM_Form->get_errors() ) > 0 ) {
			$result = false;
			$EM_Booking->add_error( $EM_Form->get_errors() );
		}
		return $result;
	}

	/**
	 * @param boolean $result
	 * @param EM_Booking $EM_Booking
	 * @return boolean
	 */
	public static function em_booking_validate( $result, $EM_Booking ) {
		$EM_Form                  = self::get_form( $EM_Booking->event_id, $EM_Booking );
		$EM_Form->uploads_user_id = $EM_Booking->person_id;
		if ( ! empty( $EM_Booking->booking_id ) ) {
			//no validation of user fields for current bookings
			add_filter( 'option_dbem_emp_booking_form_reg_input', '__return_false' );
		}
		if ( empty( $EM_Form->field_values ) ) {
			//in the event we're validating a booking that wasn't retrieved by post, with booking meta
			$values = array();
			if ( ! empty( $EM_Booking->booking_meta['booking'] ) ) {
				$values = $EM_Booking->booking_meta['booking'];
			}
			if ( ! empty( $EM_Booking->booking_meta['registration'] ) ) {
				$values = array_merge( $values, $EM_Booking->booking_meta['registration'] );
			}
			$EM_Form->field_values = $values;
		}
		if ( ! empty( $EM_Booking->mb_validate_bookings ) ) {
			$EM_Form->ignore_captcha = true; //MB Mode doing a final validation, so no need to re-check captcha
		}
		if ( ! $EM_Form->validate() ) {
			$EM_Booking->add_error( $EM_Form->get_errors() );
			return false;
		}
		if ( ! empty( $EM_Booking->mb_validate_bookings ) ) {
			unset( $EM_Form->ignore_captcha );  //MB Mode doing a final validation, so no need to re-check captcha
		}
		return $result;
	}

	/**
	 * @param $result
	 * @param EM_Booking $EM_Booking
	 *
	 * @return false|mixed
	 */
	public static function em_booking_save( $result, $EM_Booking ) {
		$EM_Form = self::get_form( $EM_Booking->event_id, $EM_Booking );
		// add file prefix for saving uploaded files
		$EM_Form->uploads_filename = $EM_Booking->booking_id . '-{field_id}-{uuid}';
		$EM_Form->uploads_user_id  = $EM_Booking->person_id;
		$saved_fields              = $EM_Form->save();
		if ( $saved_fields === false ) {
			$EM_Booking->add_error( $EM_Form->get_errors() );
			$result = false;
		} else {
			foreach ( $saved_fields as $field_id => $field_value ) {
				if ( array_key_exists( $field_id, $EM_Form->user_fields ) ) {
					$user_field_id = $EM_Form->form_fields[ $field_id ]['type']; // type is user form field ID for a user field in booking form
					$EM_Booking->booking_meta['registration'][ $user_field_id ] = $field_value;
					$save_registration_meta                                     = true;
				} else {
					$EM_Booking->booking_meta['booking'][ $field_id ] = $field_value;
					$save_booking_meta                                = true;
				}
			}
			if ( ! empty( $save_booking_meta ) ) {
				$EM_Booking->update_meta( 'booking', $EM_Booking->booking_meta['booking'] );
			}
			if ( ! empty( $save_registration_meta ) ) {
				$EM_Booking->update_meta( 'registration', $EM_Booking->booking_meta['registration'] );
			}
		}
		if ( ! empty( $EM_Booking->booking_meta['registration'] ) && is_array( $EM_Booking->booking_meta['registration'] ) ) {
			//assign the common registration fields to person object in case used in this instance
			foreach ( $EM_Booking->booking_meta['registration'] as $fieldid => $field_value ) {
				if ( ! empty( $EM_Form->form_fields[ $fieldid ]['type'] ) && array_key_exists( $EM_Form->form_fields[ $fieldid ]['type'], $EM_Form->core_user_fields ) && EM_Form::show_reg_fields( $EM_Form->form_fields[ $fieldid ] ) ) {
					$user_field_type                            = $EM_Form->form_fields[ $fieldid ]['type'];
					$EM_Booking->get_person()->$user_field_type = $field_value;
				}
			}
		}
		return $result;
	}

	/**
	 * When booking is added for first time, we save user data, subsequent saves shouldn't meddle with user data, the user can be edited directly for that.
	 * @param $EM_Booking
	 *
	 * @return void
	 */
	public static function em_bookings_added( $EM_Booking ) {
		$EM_Form = self::get_form( $EM_Booking->event_id, $EM_Booking );
		if ( ! empty( $EM_Booking->booking_meta['registration'] ) && is_array( $EM_Booking->booking_meta['registration'] ) && ! $EM_Booking->is_no_user() ) {
			$user_data = array();
			foreach ( $EM_Booking->booking_meta['registration'] as $fieldid => $field_value ) {
				if ( ! empty( $field_value ) && ( is_array( $field_value ) || trim( $field_value ) !== '' ) && array_key_exists( $fieldid, $EM_Form->form_fields ) ) {
					$user_data[ $fieldid ] = $field_value;
				}
			}
			foreach ( $user_data as $userkey => $uservalue ) {
				EM_User_Fields::update_user_meta( $EM_Booking->person_id, $userkey, $uservalue );
			}
		}
	}

	/**
	 * Remove all files related to the booking.
	 * @param EM_Booking $EM_Booking
	 *
	 * @return void
	 */
	public static function em_booking_deleted( $EM_Booking ) {
		// go through each meta to make sure all files are deleted
		$keys = $EM_Booking->person_id == 0 ? array( 'registration', 'booking' ) : array( 'booking' );
		foreach ( $keys as $k ) {
			if ( ! empty( $EM_Booking->booking_meta[ $k ] ) ) {
				foreach ( $EM_Booking->booking_meta[ $k ] as $field_value ) {
					if ( ! empty( $field_value['files'] ) ) {
						foreach ( $field_value['files'] as $file ) {
							@unlink( $file['file'] );
						}
					}
				}
			}
		}
		// go through tickets too, same thing
		foreach ( $EM_Booking->tickets_bookings as $EM_Ticket_Bookings ) {
			foreach ( $EM_Ticket_Bookings as $EM_Ticket_Booking ) {
				foreach ( $EM_Ticket_Booking->meta as $meta_value ) {
					if ( ! empty( $meta_value['files'] ) ) {
						foreach ( $meta_value['files'] as $file ) {
							@unlink( $file['file'] );
						}
					}
				}
			}
		}
	}

	/**
	 * Returns a formatted multi-dimensional associative array of booking form and user information for a specific booking (not including attendees).
	 * example : array('booking' => array('Label'=>'Value', 'Label 2'=>'Value 2'), 'registration' => array(...)...);
	 * @param EM_Booking $EM_Booking
	 */
	public static function get_booking_data( $EM_Booking, $include_registration_info = false ) {
		$booking_data = array( 'booking' => array() );
		if ( $include_registration_info ) {
			$booking_data['registration'] = array();
		}
		if ( ( ! empty( $EM_Booking->booking_meta['booking'] ) && is_array( $EM_Booking->booking_meta['booking'] ) ) || ( $include_registration_info && ! empty( $EM_Booking->booking_meta['registration'] ) && is_array( $EM_Booking->booking_meta['registration'] ) ) ) {
			$EM_Form = self::get_form( $EM_Booking->get_event(), $EM_Booking );
			foreach ( $EM_Form->form_fields as $fieldid => $field ) {
				$field       = $EM_Form->translate_field( $field );
				$input_value = $field_value = ( isset( $EM_Booking->booking_meta['booking'][ $fieldid ] ) ) ? $EM_Booking->booking_meta['booking'][ $fieldid ] : 'n/a';
				if ( ! array_key_exists( $fieldid, $EM_Form->user_fields ) && ! in_array( $fieldid, array( 'user_email', 'user_name' ) ) && $field['type'] != 'html' ) {
					if ( in_array( $field['type'], array( 'date', 'time' ) ) && $input_value == 'n/a' ) {
						$input_value = '';
					}
					$booking_data['booking'][ $field['label'] ] = $EM_Form->get_formatted_value( $field, $input_value );
				} elseif ( $field['type'] != 'html' ) {
					$booking_data['registration'][ $field['label'] ] = $EM_Form->get_formatted_value( $field, $input_value );
				}
			}
		}
		return $booking_data;
	}

	/**
	 * @param string $replace
	 * @param EM_Booking $EM_Booking
	 * @param string $full_result
	 * @param string $target
	 * @param array $placeholder_atts
	 * @return string
	 */
	public static function placeholders( $replace, $EM_Booking, $full_result, $target, $placeholder_atts = array() ) {
		if ( empty( $replace ) || $replace == $full_result ) {
			$user    = $EM_Booking->get_person();
			$EM_Form = self::get_form( $EM_Booking->event_id, $EM_Booking );
			if ( $full_result == '#_BOOKINGFORMCUSTOMREG{user_name}' || $full_result == '#_BOOKINGFORMCUSTOM{user_name}' ) {
				//special user_name case
				if ( ! is_user_logged_in() ) {
					$replace = $EM_Booking->get_person()->get_name();
				} else {
					$replace = $user->get_name();
				}
			} elseif ( $full_result == '#_BOOKINGFORMCUSTOMFIELDS' ) {
				$replace = '';
				foreach ( $EM_Form->form_fields as $field ) {
					if ( $field['type'] != 'html' ) {
						$replace .= "\r\n" . $field['label'] . ': ';
						$field_id = $field['fieldid'];
						if ( ! empty( $user->$field_id ) ) {
							//user profile is freshest, using this
							if ( ! empty( $user->$field_id['files'] ) ) {
								// Uploads - dirty trick for now, TODO - a more elegant way to present any field textually
								$values = array();
								foreach ( $user->$field_id['files'] as $file ) {
									$values[] = $file['name'];
								}
								$replace .= implode( ', ', $values );
							} elseif ( ! isset( $user->$field_id['post'] ) ) {
								$replace .= is_array( $user->$field_id ) ? implode( ', ', $user->$field_id ) : $user->$field_id;
							}
						} elseif ( ! empty( $EM_Booking->booking_meta['registration'][ $field['fieldid'] ] ) ) {
							//reg fields only exist as reg fields
							$replace .= $EM_Form->get_formatted_value( $field, $EM_Booking->booking_meta['registration'][ $field['fieldid'] ] );
						} elseif ( ! empty( $EM_Booking->booking_meta['booking'][ $field['fieldid'] ] ) ) {
							//match for custom field value
							$replace .= $EM_Form->get_formatted_value( $field, $EM_Booking->booking_meta['booking'][ $field['fieldid'] ] );
						}
					}
				}
			} elseif ( ! empty( $placeholder_atts ) && $placeholder_atts[0] == '#_BOOKINGUSERMETA' && ! empty( $placeholder_atts[1] ) ) {
				$EM_User_Form = EM_User_Fields::get_form();
				$meta_key     = $placeholder_atts[1];
				$replace      = '';
				if ( ! empty( $user->$meta_key ) ) {
					//user profile is freshest, using this
					$meta_value = $user->$meta_key;
				} elseif ( ! empty( $EM_Booking->booking_meta['registration'][ $meta_key ] ) ) {
					//reg fields only exist as reg fields
					$meta_value = $EM_Booking->booking_meta['registration'][ $meta_key ];
				}
				if ( ! empty( $meta_value ) ) {
					if ( array_key_exists( $meta_key, $EM_User_Form->form_fields ) ) {
						$replace = $EM_User_Form->get_formatted_value( $EM_User_Form->form_fields[ $meta_key ], $meta_value );
					} elseif ( is_array( $meta_value ) ) {
						$replace = implode( ', ', $meta_value );
					} else {
						$replace = (string) $meta_value;
					}
				}
			} else {
				if ( ! empty( $placeholder_atts[0] ) && ! empty( $placeholder_atts[1] ) ) {
					if ( $placeholder_atts[0] == '#_BOOKINGFORMCUSTOM' || $placeholder_atts[0] == '#_BOOKINGFORMCUSTOMREG' ) {
						$field = null;
						if ( array_key_exists( $placeholder_atts[1], $EM_Form->form_fields ) ) {
							$field = $EM_Form->form_fields[ $placeholder_atts[1] ];
						} elseif ( $placeholder_atts[0] == '#_BOOKINGFORMCUSTOMREG' && array_key_exists( $placeholder_atts[1], EM_User_Fields::get_form()->form_fields ) ) {
							$field = EM_User_Fields::get_form()->form_fields[ $placeholder_atts[1] ];
						}
						if ( ! empty( $field ) ) {
							$replace  = '';
							$field_id = $field['fieldid'];
							if ( ! empty( $user->$field_id ) ) {
								//user profile is freshest, using this
								$replace = $EM_Form->get_formatted_value( $field, $user->$field_id );
							} elseif ( ! empty( $EM_Booking->booking_meta['registration'][ $field['fieldid'] ] ) ) {
								//reg fields only exist as reg fields
								$replace = $EM_Form->get_formatted_value( $field, $EM_Booking->booking_meta['registration'][ $field['fieldid'] ] );
							} elseif ( ! empty( $EM_Booking->booking_meta['booking'][ $field['fieldid'] ] ) ) {
								//match for custom field value
								$replace = $EM_Form->get_formatted_value( $field, $EM_Booking->booking_meta['booking'][ $field['fieldid'] ] );
							} elseif ( $field['type'] == 'html' ) {
								//output HTML content if requested specifically
								$replace = $field['options_html_content'];
							}
						}
					}
				}
			}
		}
		return $replace; //no need for a filter, use the em_booking_email_placeholders filter
	}

	/*
	 * ----------------------------------------------------------
	 * Booking Table and CSV Export
	 * ----------------------------------------------------------
	 */

	public static $booking_table_prefix        = 'booking_meta_';
	public static $booking_table_cols_template = 'cols_bookings_template';

	/**
	 * Gets a default value for a booking form field
	 * @param string $value
	 * @param string $col
	 * @param EM_Booking|EM_Ticket_Booking|EM_Ticket_Bookings $EM_Object
	 * @param EM_Bookings_Table $EM_Bookings_Table
	 * @param string $format
	 *
	 * @return mixed|string|null
	 */
	public static function em_bookings_table_rows_col( $value, $col, $EM_Object, $EM_Bookings_Table, $format ) {
		// only need to deal with prefixed columns belonging to booking form fields
		if ( preg_match( '/^' . static::$booking_table_prefix . '/', $col ) ) {
			$field_id = preg_replace( '/^' . static::$booking_table_prefix . '/', '', $col );
			// get the booking object, we'll always have a booking object
			extract( $EM_Bookings_Table->get_item_objects( $EM_Object ) ); /* @var EM_Booking $EM_Booking */ /* @var EM_Ticket_Bookings $EM_Ticket_Bookings */ /* @var EM_Ticket_Booking $EM_Ticket_Booking */
			// get the right form for the current context
			$EM_Form = static::get_bookings_table_form( $EM_Bookings_Table );
			// check for whether this column exists in the booking, and if so, get the value from this form
			if ( isset( $EM_Booking->booking_meta['booking'][ $field_id ] ) && array_key_exists( $field_id, $EM_Form->form_fields ) ) {
				// get the field data, run it through EM_Form to format it properly for display
				$field = $EM_Form->form_fields[ $field_id ];
				$value = $EM_Form->get_formatted_value( $field, $EM_Booking->booking_meta['booking'][ $field_id ], 'table' );
				if ( $field['type'] == 'upload' ) {
					EM_Bookings_Table::$cols_allowed_html[ $col ] = true;
				} else {
					$value = esc_html( $value );
				}
			}
		}
		return $value;
	}

	// make a function for em_bookings_table_cols_template_groups which adds a Booking Custom Fields section with all booking form fields which aren't user fields
	public static function em_bookings_table_cols_template_groups( $template_groups, $EM_Bookings_Table ) {
		$form_fields = static::get_bookings_table_fields( $EM_Bookings_Table );
		// add it to a new template group
		$template_groups['booking_meta']['fields'] = array_merge( $template_groups['booking_meta']['fields'], array_keys( $form_fields ) );
		return $template_groups;
	}

	/*
	 * ----------------------------------------------------------
	 * Event Admin Functions
	 * ----------------------------------------------------------
	 */

	/**
	 * Outputs booking form information when viewing a booking in the admin area.
	 * @param EM_Booking $EM_Booking
	 */
	public static function em_bookings_single_custom( $EM_Booking ) {
		//if you want to mess with these values, intercept the em_bookings_single_custom instead
		$EM_Form = self::get_form( $EM_Booking->event_id, $EM_Booking );
		foreach ( $EM_Form->form_fields as $fieldid => $field ) {
			$field = $EM_Form->translate_field( $field );
			if ( ! array_key_exists( $fieldid, $EM_Form->user_fields ) && ! in_array( $fieldid, array( 'user_email', 'user_name' ) ) && $field['type'] != 'html' && $field['type'] != 'captcha' ) {
				//get value of field
				if ( strlen( $fieldid ) >= 246 ) {
					// legacy bug, user can create fields with greater than 255 chars but db is max 255 char key including the array field
					$fieldid = substr( $fieldid, 0, 246 );
				}
				$input_value = $field_value = ( isset( $EM_Booking->booking_meta['booking'][ $fieldid ] ) ) ? $EM_Booking->booking_meta['booking'][ $fieldid ] : 'n/a';
				//account for the free version and the booking_comment field so that old booking info still shows
				if ( $input_value == 'n/a' && $fieldid == 'booking_comment' && ! empty( $EM_Booking->booking_comment ) ) {
					$input_value = $field_value = $EM_Booking->booking_comment;
				}
				//input value should be blank, not n/a
				if ( $input_value == 'n/a' ) {
					$input_value = '';
				}
				?>
				<tr>
					<th><?php echo $field['label']; ?></th>
					<td>
						<span class="em-booking-single-info"><?php echo $EM_Form->get_formatted_value( $field, $field_value ); ?></span>
						<div class="em-booking-single-edit"><?php echo $EM_Form->output_field_input( $field, $input_value ); ?></div>
					</td>
				</tr>
				<?php
			}
		}
	}

	/**
	 * Saves the custom booking form as post meta. This is done on em_event_save_meta_pre since at that point we know the post id and this will get passed onto recurrences as well.
	 * @param EM_Event $EM_Event
	 */
	public static function em_event_save_meta_pre( $EM_Event ) {
		global $wpdb;
		if ( ! empty( $EM_Event->duplicated ) ) {
			return; //if just duplicated, we ignore this and let EM carry over duplicate event data
		}
		if ( $EM_Event->event_rsvp && ! empty( $_REQUEST['custom_booking_form'] ) && is_numeric( $_REQUEST['custom_booking_form'] ) ) {
			//Make sure form id exists
			$id = $wpdb->get_var( 'SELECT meta_id FROM ' . EM_META_TABLE . " WHERE meta_id='{$_REQUEST['custom_booking_form']}'" );
			if ( $id == $_REQUEST['custom_booking_form'] ) {
				//add or modify custom booking form id in post data
				update_post_meta( $EM_Event->post_id, '_custom_booking_form', $id );
			}
		} else {
			delete_post_meta( $EM_Event->post_id, '_custom_booking_form' );
		}
	}

	public static function register_api() {
		if ( ! class_exists( '\EM_Pro\API\REST' ) ) {
			return;
		}
		$route_args = array(
			'type' => array(
				'type' => 'string',
				'enum' => array( 'booking', 'attendee' ),
				'required' => true,
				'description' => __( 'Form type.', 'em-pro' ),
				'sanitize_callback' => 'sanitize_key',
			),
		);
		register_rest_route( \EM_Pro\API\REST::NAMESPACE, '/bookings/forms/(?P<type>booking|attendee)', array(
			array(
				'methods' => 'GET',
				'callback' => array( static::class, 'api_list_forms' ),
				'permission_callback' => array( static::class, 'api_can_manage_forms' ),
				'args' => $route_args,
			),
			array(
				'methods' => 'POST',
				'callback' => array( static::class, 'api_create_form' ),
				'permission_callback' => array( static::class, 'api_can_manage_forms' ),
				'args' => array_merge( $route_args, static::api_form_args() ),
			),
		) );
		register_rest_route( \EM_Pro\API\REST::NAMESPACE, '/bookings/forms/(?P<type>booking|attendee)/(?P<id>\d+)', array(
			array(
				'methods' => 'GET',
				'callback' => array( static::class, 'api_get_form' ),
				'permission_callback' => array( static::class, 'api_can_manage_forms' ),
				'args' => array_merge( $route_args, static::api_id_args() ),
			),
			array(
				'methods' => 'PATCH',
				'callback' => array( static::class, 'api_update_form' ),
				'permission_callback' => array( static::class, 'api_can_manage_forms' ),
				'args' => array_merge( $route_args, static::api_id_args(), static::api_form_args() ),
			),
			array(
				'methods' => 'DELETE',
				'callback' => array( static::class, 'api_delete_form' ),
				'permission_callback' => array( static::class, 'api_can_manage_forms' ),
				'args' => array_merge( $route_args, static::api_id_args() ),
			),
		) );
		register_rest_route( \EM_Pro\API\REST::NAMESPACE, '/bookings/forms/(?P<type>booking|attendee)/(?P<id>\d+)/default', array(
			'methods' => 'POST',
			'callback' => array( static::class, 'api_set_default_form' ),
			'permission_callback' => array( static::class, 'api_can_manage_forms' ),
			'args' => array_merge( $route_args, static::api_id_args() ),
		) );
		register_rest_route( \EM_Pro\API\REST::NAMESPACE, '/bookings/forms/(?P<type>booking|attendee)/(?P<id>\d+)/duplicate', array(
			'methods' => 'POST',
			'callback' => array( static::class, 'api_duplicate_form' ),
			'permission_callback' => array( static::class, 'api_can_manage_forms' ),
			'args' => array_merge( $route_args, static::api_id_args() ),
		) );
	}

	public static function api_prepare_event( $api, $EM_Event, $context ) {
		if ( ! is_array( $api ) ) {
			$api = array();
		}
		if ( empty( $api['bookings'] ) || ! is_array( $api['bookings'] ) ) {
			$api['bookings'] = array();
		}
		if ( empty( $api['bookings']['forms'] ) || ! is_array( $api['bookings']['forms'] ) ) {
			$api['bookings']['forms'] = array();
		}
		$api['bookings']['forms']['booking'] = static::api_prepare_event_form_selection( 'booking', $EM_Event );
		if ( class_exists( 'EM_Attendees_Form' ) ) {
			$api['bookings']['forms']['attendee'] = static::api_prepare_event_form_selection( 'attendee', $EM_Event );
		}
		return $api;
	}

	public static function api_event_input_schema( $schema, $require_id = false ) {
		if ( empty( $schema['properties'] ) || ! is_array( $schema['properties'] ) ) {
			$schema['properties'] = array();
		}
		$schema['properties']['booking_form_id'] = array(
			'type' => array( 'integer', 'string', 'null' ),
			'description' => __( 'Booking form ID for this event, or "default" to use the site default.', 'em-pro' ),
		);
		$schema['properties']['attendee_form_id'] = array(
			'type' => array( 'integer', 'string', 'null' ),
			'description' => __( 'Attendee form ID for this event, "none" to disable attendee fields, or "default" to use the site default.', 'em-pro' ),
		);
		return $schema;
	}

	public static function api_event_save_pre( $EM_Event, $data, $id = 0 ) {
		// This hook fires before EM_Event::get_post() copies event_rsvp from the request, so on a new event $EM_Event->event_rsvp is still empty here. Read the intended booking state from the incoming data (falling back to the loaded event for a partial edit that doesn't resend it) so enabling bookings and selecting a form in the same request validates correctly.
		$rsvp_enabled = array_key_exists( 'event_rsvp', $data ) ? ! empty( $data['event_rsvp'] ) : ! empty( $EM_Event->event_rsvp );
		$booking_form = static::api_get_event_form_value( $data, 'booking' );
		if ( $booking_form['provided'] ) {
			static::api_validate_event_form_selection( $EM_Event, 'booking', $booking_form['value'], $rsvp_enabled );
		}
		if ( class_exists( 'EM_Attendees_Form' ) ) {
			$attendee_form = static::api_get_event_form_value( $data, 'attendee' );
			if ( $attendee_form['provided'] ) {
				static::api_validate_event_form_selection( $EM_Event, 'attendee', $attendee_form['value'], $rsvp_enabled );
			}
		}
	}

	public static function api_event_save( $EM_Event, $data, $id = 0 ) {
		if ( empty( $EM_Event->post_id ) ) {
			return;
		}
		$booking_form = static::api_get_event_form_value( $data, 'booking' );
		if ( $booking_form['provided'] ) {
			static::api_save_event_form_selection( $EM_Event, 'booking', $booking_form['value'] );
		}
		if ( class_exists( 'EM_Attendees_Form' ) ) {
			$attendee_form = static::api_get_event_form_value( $data, 'attendee' );
			if ( $attendee_form['provided'] ) {
				static::api_save_event_form_selection( $EM_Event, 'attendee', $attendee_form['value'] );
			}
		}
	}

	public static function api_list_forms( $request ) {
		$type = sanitize_key( $request['type'] );
		$config = static::api_form_config( $type );
		if ( is_wp_error( $config ) ) {
			return $config;
		}
		global $wpdb;
		$rows = $wpdb->get_results( $wpdb->prepare( 'SELECT meta_id, meta_value FROM ' . EM_META_TABLE . ' WHERE meta_key=%s ORDER BY meta_id ASC', $config['meta_key'] ) );
		$items = array();
		foreach ( $rows as $row ) {
			$items[] = static::api_prepare_form_row( $type, $row );
		}
		return static::api_respond( array(
			'type' => $type,
			'enabled' => static::api_form_type_enabled( $type ),
			'default_id' => absint( get_option( $config['default_option'] ) ),
			'items' => $items,
			'pagination' => array(
				'total' => count( $items ),
				'total_pages' => 1,
				'page' => 1,
				'per_page' => count( $items ),
			),
		) );
	}

	public static function api_get_form( $request ) {
		$row = static::api_get_form_row( $request['type'], $request['id'] );
		if ( is_wp_error( $row ) ) {
			return $row;
		}
		return static::api_respond( static::api_prepare_form_row( $request['type'], $row ) );
	}

	public static function api_create_form( $request ) {
		$type = sanitize_key( $request['type'] );
		$config = static::api_form_config( $type );
		if ( is_wp_error( $config ) ) {
			return $config;
		}
		$data = static::api_request_data( $request );
		$name = ! empty( $data['name'] ) ? wp_kses_data( $data['name'] ) : static::api_default_form_name( $type );
		$fields = array_key_exists( 'fields', $data ) ? $data['fields'] : ( array_key_exists( 'form', $data ) ? $data['form'] : call_user_func( $config['template_callback'] ) );
		$form_data = static::api_prepare_form_data( $type, $name, $fields );
		if ( is_wp_error( $form_data ) ) {
			return $form_data;
		}
		global $wpdb;
		$saved = $wpdb->insert( EM_META_TABLE, array(
			'meta_key' => $config['meta_key'],
			'meta_value' => serialize( $form_data ),
			'object_id' => 0,
		) );
		if ( ! $saved ) {
			return static::api_error( 'emp_api_form_save_failed', __( 'Form could not be saved.', 'em-pro' ), 500 );
		}
		if ( $type === 'attendee' && ! get_option( $config['default_option'] ) ) {
			update_option( $config['default_option'], absint( $wpdb->insert_id ) );
		}
		$row = static::api_get_form_row( $type, $wpdb->insert_id );
		return is_wp_error( $row ) ? $row : static::api_respond( static::api_prepare_form_row( $type, $row ), 201 );
	}

	public static function api_update_form( $request ) {
		$type = sanitize_key( $request['type'] );
		$row = static::api_get_form_row( $type, $request['id'] );
		if ( is_wp_error( $row ) ) {
			return $row;
		}
		$current = static::api_unserialize_form_data( $row->meta_value );
		$data = static::api_request_data( $request );
		$name = array_key_exists( 'name', $data ) ? wp_kses_data( $data['name'] ) : ( $current['name'] ?? static::api_default_form_name( $type ) );
		$fields = array_key_exists( 'fields', $data ) ? $data['fields'] : ( array_key_exists( 'form', $data ) ? $data['form'] : ( $current['form'] ?? array() ) );
		$form_data = static::api_prepare_form_data( $type, $name, $fields );
		if ( is_wp_error( $form_data ) ) {
			return $form_data;
		}
		global $wpdb;
		$saved = $wpdb->update( EM_META_TABLE, array( 'meta_value' => serialize( $form_data ) ), array( 'meta_id' => absint( $request['id'] ), 'meta_key' => static::api_form_config( $type )['meta_key'] ) );
		if ( $saved === false ) {
			return static::api_error( 'emp_api_form_save_failed', __( 'Form could not be saved.', 'em-pro' ), 500 );
		}
		$row = static::api_get_form_row( $type, $request['id'] );
		return is_wp_error( $row ) ? $row : static::api_respond( static::api_prepare_form_row( $type, $row ) );
	}

	public static function api_delete_form( $request ) {
		$type = sanitize_key( $request['type'] );
		$row = static::api_get_form_row( $type, $request['id'] );
		if ( is_wp_error( $row ) ) {
			return $row;
		}
		$previous = static::api_prepare_form_row( $type, $row );
		global $wpdb;
		$config = static::api_form_config( $type );
		$deleted = $wpdb->delete( EM_META_TABLE, array( 'meta_id' => absint( $request['id'] ), 'meta_key' => $config['meta_key'] ) );
		if ( $deleted === false ) {
			return static::api_error( 'emp_api_form_delete_failed', __( 'Form could not be deleted.', 'em-pro' ), 500 );
		}
		if ( absint( get_option( $config['default_option'] ) ) === absint( $request['id'] ) ) {
			update_option( $config['default_option'], 0 );
		}
		return static::api_respond( array( 'deleted' => true, 'previous' => $previous ) );
	}

	public static function api_set_default_form( $request ) {
		$type = sanitize_key( $request['type'] );
		$row = static::api_get_form_row( $type, $request['id'] );
		if ( is_wp_error( $row ) ) {
			return $row;
		}
		$config = static::api_form_config( $type );
		update_option( $config['default_option'], absint( $request['id'] ) );
		return static::api_respond( static::api_prepare_form_row( $type, $row ) );
	}

	public static function api_duplicate_form( $request ) {
		$type = sanitize_key( $request['type'] );
		$row = static::api_get_form_row( $type, $request['id'] );
		if ( is_wp_error( $row ) ) {
			return $row;
		}
		$config = static::api_form_config( $type );
		$form_data = static::api_unserialize_form_data( $row->meta_value );
		$form_data['name'] = sprintf( __( '%s (Duplicate)', 'em-pro' ), $form_data['name'] ?? static::api_default_form_name( $type ) );
		global $wpdb;
		$saved = $wpdb->insert( EM_META_TABLE, array(
			'meta_key' => $config['meta_key'],
			'meta_value' => serialize( $form_data ),
			'object_id' => 0,
		) );
		if ( ! $saved ) {
			return static::api_error( 'emp_api_form_save_failed', __( 'Form could not be saved.', 'em-pro' ), 500 );
		}
		$row = static::api_get_form_row( $type, $wpdb->insert_id );
		return is_wp_error( $row ) ? $row : static::api_respond( static::api_prepare_form_row( $type, $row ), 201 );
	}

	public static function api_can_manage_forms() {
		return current_user_can( get_option( 'dbem_capability_forms_editor', 'list_users' ) );
	}

	protected static function api_form_args() {
		return array(
			'name' => array(
				'type' => 'string',
				'description' => __( 'Form name.', 'em-pro' ),
				'sanitize_callback' => 'wp_kses_data',
			),
			'fields' => array(
				'type' => 'object',
				'description' => __( 'Form fields keyed by field ID.', 'em-pro' ),
			),
			'form' => array(
				'type' => 'object',
				'description' => __( 'Alias for fields.', 'em-pro' ),
			),
		);
	}

	protected static function api_id_args() {
		return array(
			'id' => array(
				'type' => 'integer',
				'required' => true,
				'description' => __( 'Form ID.', 'em-pro' ),
				'sanitize_callback' => 'absint',
			),
		);
	}

	protected static function api_prepare_event_form_selection( $type, $EM_Event ) {
		$config = static::api_form_config( $type );
		if ( is_wp_error( $config ) ) {
			return array( 'enabled' => false );
		}
		$meta_value = ! empty( $EM_Event->post_id ) ? get_post_meta( $EM_Event->post_id, $config['event_meta_key'], true ) : '';
		$default_id = absint( get_option( $config['default_option'] ) );
		$selection = array(
			'enabled' => static::api_form_type_enabled( $type ),
			'default_id' => $default_id,
			'custom_id' => null,
			'id' => $default_id ?: null,
			'name' => $default_id ? static::api_get_form_name( $type, $default_id ) : __( 'Default', 'em-pro' ),
			'uses_default' => empty( $meta_value ),
			'disabled' => false,
		);
		if ( $type === 'attendee' && $meta_value === 'none' ) {
			$selection['custom_id'] = 'none';
			$selection['id'] = null;
			$selection['name'] = emp__( 'None', 'events-manager' );
			$selection['uses_default'] = false;
			$selection['disabled'] = true;
		} elseif ( is_numeric( $meta_value ) && absint( $meta_value ) > 0 ) {
			$selection['custom_id'] = absint( $meta_value );
			$selection['id'] = absint( $meta_value );
			$selection['name'] = static::api_get_form_name( $type, absint( $meta_value ) );
			$selection['uses_default'] = false;
		}
		return $selection;
	}

	protected static function api_get_event_form_value( $data, $type ) {
		$data = is_array( $data ) ? $data : array();
		$keys = $type === 'booking' ? array( 'custom_booking_form', 'booking_form_id' ) : array( 'custom_attendee_form', 'attendee_form_id' );
		foreach ( $keys as $key ) {
			if ( array_key_exists( $key, $data ) ) {
				return array( 'provided' => true, 'value' => $data[ $key ] );
			}
		}
		if ( isset( $data['bookings']['forms'][ $type ] ) && is_array( $data['bookings']['forms'][ $type ] ) && array_key_exists( 'id', $data['bookings']['forms'][ $type ] ) ) {
			return array( 'provided' => true, 'value' => $data['bookings']['forms'][ $type ]['id'] );
		}
		if ( isset( $data['forms'][ $type ] ) && is_array( $data['forms'][ $type ] ) && array_key_exists( 'id', $data['forms'][ $type ] ) ) {
			return array( 'provided' => true, 'value' => $data['forms'][ $type ]['id'] );
		}
		return array( 'provided' => false, 'value' => null );
	}

	protected static function api_validate_event_form_selection( $EM_Event, $type, $value, $rsvp_enabled = null ) {
		// Caller may pass the intended booking state (from the request) since $EM_Event->event_rsvp isn't populated yet during the pre-save hook; default to the object for any other caller.
		if ( $rsvp_enabled === null ) {
			$rsvp_enabled = ! empty( $EM_Event->event_rsvp );
		}
		if ( ! $rsvp_enabled && ! static::api_is_default_form_value( $value ) && ! ( $type === 'attendee' && $value === 'none' ) ) {
			$EM_Event->add_error( __( 'Bookings must be enabled before selecting a custom booking form.', 'em-pro' ) );
			return false;
		}
		if ( static::api_is_default_form_value( $value ) || ( $type === 'attendee' && $value === 'none' ) ) {
			return true;
		}
		if ( ! is_numeric( $value ) || ! static::api_form_exists( $type, absint( $value ) ) ) {
			$EM_Event->add_error( $type === 'booking' ? __( 'Booking form not found.', 'em-pro' ) : __( 'Attendee form not found.', 'em-pro' ) );
			return false;
		}
		return true;
	}

	protected static function api_save_event_form_selection( $EM_Event, $type, $value ) {
		$config = static::api_form_config( $type );
		if ( is_wp_error( $config ) ) {
			return;
		}
		if ( static::api_is_default_form_value( $value ) || empty( $EM_Event->event_rsvp ) ) {
			delete_post_meta( $EM_Event->post_id, $config['event_meta_key'] );
		} elseif ( $type === 'attendee' && $value === 'none' ) {
			update_post_meta( $EM_Event->post_id, $config['event_meta_key'], 'none' );
		} elseif ( is_numeric( $value ) && static::api_form_exists( $type, absint( $value ) ) ) {
			update_post_meta( $EM_Event->post_id, $config['event_meta_key'], absint( $value ) );
		}
		if ( $type === 'booking' ) {
			self::$form = false;
		} elseif ( class_exists( 'EM_Attendees_Form' ) ) {
			EM_Attendees_Form::$form = false;
		}
	}

	protected static function api_is_default_form_value( $value ) {
		return $value === null || $value === '' || $value === false || $value === 0 || $value === '0' || $value === 'default';
	}

	protected static function api_form_config( $type ) {
		$type = sanitize_key( $type );
		if ( $type === 'booking' ) {
			return array(
				'type' => 'booking',
				'meta_key' => static::$form_meta_key,
				'default_option' => static::$default_form_option,
				'event_meta_key' => '_custom_booking_form',
				'template_callback' => array( static::class, 'get_form_template' ),
			);
		}
		if ( $type === 'attendee' && class_exists( 'EM_Attendees_Form' ) ) {
			return array(
				'type' => 'attendee',
				'meta_key' => EM_Attendees_Form::$form_meta_key,
				'default_option' => EM_Attendees_Form::$default_form_option,
				'event_meta_key' => '_custom_attendee_form',
				'template_callback' => array( 'EM_Attendees_Form', 'get_form_template' ),
			);
		}
		return static::api_error( 'emp_api_form_type_invalid', __( 'Form type is invalid.', 'em-pro' ), 400 );
	}

	protected static function api_form_type_enabled( $type ) {
		return $type === 'booking' || ( $type === 'attendee' && get_option( 'em_attendee_fields_enabled' ) );
	}

	protected static function api_get_form_row( $type, $id ) {
		$config = static::api_form_config( $type );
		if ( is_wp_error( $config ) ) {
			return $config;
		}
		global $wpdb;
		$row = $wpdb->get_row( $wpdb->prepare( 'SELECT meta_id, meta_value FROM ' . EM_META_TABLE . ' WHERE meta_key=%s AND meta_id=%d', $config['meta_key'], absint( $id ) ) );
		if ( empty( $row ) ) {
			return static::api_error( 'emp_api_form_not_found', __( 'Form not found.', 'em-pro' ), 404 );
		}
		return $row;
	}

	protected static function api_form_exists( $type, $id ) {
		return ! is_wp_error( static::api_get_form_row( $type, $id ) );
	}

	protected static function api_prepare_form_row( $type, $row ) {
		$config = static::api_form_config( $type );
		$form_data = static::api_unserialize_form_data( $row->meta_value );
		$fields = isset( $form_data['form'] ) && is_array( $form_data['form'] ) ? $form_data['form'] : array();
		return array(
			'id' => absint( $row->meta_id ),
			'type' => sanitize_key( $type ),
			'name' => $form_data['name'] ?? static::api_default_form_name( $type ),
			'fields' => $fields,
			'field_count' => count( $fields ),
			'default' => ! is_wp_error( $config ) && absint( get_option( $config['default_option'] ) ) === absint( $row->meta_id ),
		);
	}

	protected static function api_prepare_form_data( $type, $name, $fields ) {
		$fields = static::api_sanitize_form_fields( $fields );
		if ( empty( $fields ) ) {
			return static::api_error( 'emp_api_form_fields_invalid', __( 'Form fields are invalid.', 'em-pro' ), 400 );
		}
		if ( $type === 'booking' && ! static::api_booking_form_has_email( $fields ) ) {
			return static::api_error( 'emp_api_form_email_required', __( 'Booking forms must include an email field.', 'em-pro' ), 400 );
		}
		return array(
			'name' => $name ?: static::api_default_form_name( $type ),
			'form' => $fields,
		);
	}

	protected static function api_sanitize_form_fields( $fields ) {
		if ( ! is_array( $fields ) ) {
			return array();
		}
		$sanitized = array();
		foreach ( $fields as $key => $field ) {
			if ( ! is_array( $field ) ) {
				continue;
			}
			$field_id = ! empty( $field['fieldid'] ) ? sanitize_key( $field['fieldid'] ) : sanitize_key( $key );
			if ( empty( $field_id ) ) {
				continue;
			}
			$field['fieldid'] = $field_id;
			$sanitized[ $field_id ] = static::api_sanitize_form_field_value( $field );
		}
		return $sanitized;
	}

	protected static function api_sanitize_form_field_value( $value ) {
		if ( is_array( $value ) ) {
			$sanitized = array();
			foreach ( $value as $key => $item ) {
				$sanitized[ is_string( $key ) ? sanitize_key( $key ) : $key ] = static::api_sanitize_form_field_value( $item );
			}
			return $sanitized;
		}
		return is_scalar( $value ) ? wp_kses_post( (string) $value ) : '';
	}

	protected static function api_booking_form_has_email( $fields ) {
		foreach ( $fields as $field_id => $field ) {
			if ( $field_id === 'user_email' || ( isset( $field['fieldid'] ) && $field['fieldid'] === 'user_email' ) || ( isset( $field['type'] ) && $field['type'] === 'user_email' ) ) {
				return true;
			}
		}
		return false;
	}

	protected static function api_get_form_name( $type, $id ) {
		$row = static::api_get_form_row( $type, $id );
		if ( is_wp_error( $row ) ) {
			return __( 'Unknown', 'em-pro' );
		}
		$form_data = static::api_unserialize_form_data( $row->meta_value );
		return $form_data['name'] ?? __( 'Default', 'em-pro' );
	}

	protected static function api_unserialize_form_data( $value ) {
		$form_data = is_serialized( $value ) ? unserialize( $value ) : $value;
		return is_array( $form_data ) ? $form_data : array();
	}

	protected static function api_default_form_name( $type ) {
		return $type === 'attendee' ? __( 'Attendee Form', 'em-pro' ) : __( 'Booking Form', 'em-pro' );
	}

	protected static function api_request_data( $request ) {
		$params = is_object( $request ) && method_exists( $request, 'get_params' ) ? $request->get_params() : array();
		$json = is_object( $request ) && method_exists( $request, 'get_json_params' ) ? $request->get_json_params() : array();
		return array_merge( is_array( $params ) ? $params : array(), is_array( $json ) ? $json : array() );
	}

	protected static function api_respond( $result, $status = 200 ) {
		if ( is_wp_error( $result ) ) {
			return $result;
		}
		if ( class_exists( '\EM_Pro\API\REST' ) ) {
			return \EM_Pro\API\REST::respond( $result, $status );
		}
		return new WP_REST_Response( $result, $status );
	}

	protected static function api_error( $code, $message, $status = 400 ) {
		if ( class_exists( '\EM_Pro\API\Utils' ) ) {
			return \EM_Pro\API\Utils::error( $code, $message, $status );
		}
		return new WP_Error( $code, $message, array( 'status' => $status ) );
	}

	public static function api_register_abilities() {
		if ( ! function_exists( 'wp_register_ability' ) ) {
			return;
		}
		foreach ( array( 'booking', 'attendee' ) as $type ) {
			if ( is_wp_error( static::api_form_config( $type ) ) ) {
				continue;
			}
			$label_type = $type === 'attendee' ? __( 'attendee form', 'em-pro' ) : __( 'booking form', 'em-pro' );
			static::api_register_form_ability( "list-{$type}-forms", sprintf( __( 'List %s forms', 'em-pro' ), $label_type ), sprintf( __( 'Retrieves Events Manager Pro %s forms.', 'em-pro' ), $label_type ), $type, 'list', static::api_form_collection_input(), true, array( 'readonly' => true, 'destructive' => false, 'idempotent' => true ) );
			static::api_register_form_ability( "get-{$type}-form", sprintf( __( 'Get %s', 'em-pro' ), $label_type ), sprintf( __( 'Retrieves one Events Manager Pro %s.', 'em-pro' ), $label_type ), $type, 'get', static::api_form_id_input(), true, array( 'readonly' => true, 'destructive' => false, 'idempotent' => true ) );
			static::api_register_form_ability( "create-{$type}-form", sprintf( __( 'Create %s', 'em-pro' ), $label_type ), sprintf( __( 'Creates an Events Manager Pro %s.', 'em-pro' ), $label_type ), $type, 'create', static::api_form_ability_input(), false, array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) );
			static::api_register_form_ability( "update-{$type}-form", sprintf( __( 'Update %s', 'em-pro' ), $label_type ), sprintf( __( 'Updates an Events Manager Pro %s.', 'em-pro' ), $label_type ), $type, 'update', static::api_form_ability_input( true ), false, array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) );
			static::api_register_form_ability( "delete-{$type}-form", sprintf( __( 'Delete %s', 'em-pro' ), $label_type ), sprintf( __( 'Deletes an Events Manager Pro %s.', 'em-pro' ), $label_type ), $type, 'delete', static::api_form_id_input(), false, array( 'readonly' => false, 'destructive' => true, 'idempotent' => true ) );
			static::api_register_form_ability( "set-default-{$type}-form", sprintf( __( 'Set default %s', 'em-pro' ), $label_type ), sprintf( __( 'Sets the default Events Manager Pro %s.', 'em-pro' ), $label_type ), $type, 'default', static::api_form_id_input(), false, array( 'readonly' => false, 'destructive' => true, 'idempotent' => true ) );
			static::api_register_form_ability( "duplicate-{$type}-form", sprintf( __( 'Duplicate %s', 'em-pro' ), $label_type ), sprintf( __( 'Duplicates an Events Manager Pro %s.', 'em-pro' ), $label_type ), $type, 'duplicate', static::api_form_id_input(), false, array( 'readonly' => false, 'destructive' => false, 'idempotent' => false ) );
		}
	}

	protected static function api_register_form_ability( $name, $label, $description, $type, $action, $input_schema, $readonly, $annotations ) {
		$category = class_exists( '\EM_Pro\API\Abilities' ) ? ( $readonly ? \EM_Pro\API\Abilities::CATEGORY_DATA : \EM_Pro\API\Abilities::CATEGORY_MANAGEMENT ) : ( $readonly ? 'events-manager-pro-data' : 'events-manager-pro-management' );
		wp_register_ability( 'events-manager-pro/' . $name, array(
			'label' => $label,
			'description' => $description,
			'category' => $category,
			'input_schema' => $input_schema,
			'output_schema' => static::api_form_object_output(),
			'execute_callback' => function( $input ) use ( $type, $action ) {
				return EM_Booking_Form::api_execute_form_ability( $type, $action, $input );
			},
			'permission_callback' => array( static::class, 'api_can_manage_forms' ),
			'meta' => static::api_form_ability_meta( $annotations, $name, $category ),
		) );
	}

	public static function api_execute_form_ability( $type, $action, $input ) {
		$input = is_array( $input ) ? $input : array();
		$request = new WP_REST_Request( 'GET', '/' );
		$request->set_param( 'type', $type );
		foreach ( $input as $key => $value ) {
			$request->set_param( $key, $value );
		}
		switch ( $action ) {
			case 'list':
				$response = static::api_list_forms( $request );
				break;
			case 'get':
				$response = static::api_get_form( $request );
				break;
			case 'create':
				$response = static::api_create_form( $request );
				break;
			case 'update':
				$response = static::api_update_form( $request );
				break;
			case 'delete':
				$response = static::api_delete_form( $request );
				break;
			case 'default':
				$response = static::api_set_default_form( $request );
				break;
			case 'duplicate':
				$response = static::api_duplicate_form( $request );
				break;
			default:
				$response = static::api_error( 'emp_api_form_action_invalid', __( 'Form action is invalid.', 'em-pro' ), 400 );
		}
		return static::api_ability_response_data( $response );
	}

	protected static function api_ability_response_data( $response ) {
		if ( is_wp_error( $response ) ) {
			return $response;
		}
		if ( $response instanceof WP_REST_Response ) {
			return $response->get_data();
		}
		return $response;
	}

	protected static function api_form_collection_input() {
		return array(
			'type' => 'object',
			'properties' => array(),
		);
	}

	protected static function api_form_id_input() {
		return array(
			'type' => 'object',
			'properties' => array(
				'id' => array( 'type' => 'integer' ),
			),
			'required' => array( 'id' ),
		);
	}

	protected static function api_form_ability_input( $require_id = false ) {
		$schema = array(
			'type' => 'object',
			'properties' => array(
				'id' => array( 'type' => 'integer' ),
				'name' => array( 'type' => 'string' ),
				'fields' => array( 'type' => 'object' ),
				'form' => array( 'type' => 'object' ),
			),
		);
		if ( $require_id ) {
			$schema['required'] = array( 'id' );
		}
		return $schema;
	}

	protected static function api_form_object_output() {
		return array( 'type' => 'object' );
	}

	protected static function api_form_ability_meta( $annotations, $name, $category ) {
		return array(
			'annotations' => $annotations,
			'show_in_rest' => true,
			'mcp' => array(
				'public' => (bool) apply_filters( 'emp_api_ability_mcp_public', true, $name, $annotations, $category ),
			),
		);
	}

	public static function event_bookings_meta_box() {
		//Get available coupons for user
		global $wpdb, $EM_Event;
		//get booking form id directly from event meta, since self::get_form() returns the default form if 0 is the form id.
		$event_form_id   = get_post_meta( $EM_Event->post_id, '_custom_booking_form', true );
		$default_form_id = get_option( 'em_booking_form_fields' );
		?>
		<div class="em-booking-options">
			<h4><?php esc_html_e_emp( 'Booking Form' ); ?> </h4>
			<p><em><?php _e( 'You can choose to use a custom booking form, or leave as is to use the default booking form.', 'em-pro' ); ?></em></p>
			<div>
				<?php _e( 'Selected Booking Form', 'em-pro' ); ?> :
				<select name="custom_booking_form" onchange="this.parentNode.submit()">
					<option value="0" 
					<?php
					if ( empty( $event_form_id ) ) {
						echo 'selected="selected"';}
					?>
					>[ <?php _e( 'Default', 'em-pro' ); ?> ]</option>
					<?php foreach ( self::get_forms_names() as $form_key => $form_name_option ) : ?>
					<option value="<?php echo $form_key; ?>" 
						<?php
						if ( $form_key == $event_form_id ) {
							echo 'selected="selected"';}
						?>
						>
						<?php echo $form_name_option; ?>
						<?php
						if ( $form_key == $default_form_id ) {
							echo ' [' . esc_html__( 'Default', 'em-pro' ) . ']';}
						?>
					</option>
					<?php endforeach; ?>
				</select>
				<?php do_action( 'emp_bookings_form_select_footer' ); ?>
			</div>
		</div>
		<?php
	}

	/*
	 * ----------------------------------------------------------
	 * ADMIN Functions
	 * ----------------------------------------------------------
	 */

	public static function admin_page_actions() {
		global $EM_Notices, $wpdb;
		if ( ! empty( $_REQUEST['page'] ) && $_REQUEST['page'] == 'events-manager-forms-editor' ) {
			//Load the right form
			if ( ! empty( $_REQUEST['form_id'] ) ) {
				$sql             = $wpdb->prepare( 'SELECT meta_value FROM ' . EM_META_TABLE . ' WHERE meta_key=%s AND meta_id=%d', static::$form_meta_key, $_REQUEST['form_id'] );
				$form_data       = unserialize( $wpdb->get_var( $sql ) );
				$EM_Form         = self::$form = new EM_Form( $form_data['form'], 'em_bookings_form' );
				self::$form_name = $form_data['name'];
				self::$form_id   = $_REQUEST['form_id'];
			} else {
				$EM_Form = self::get_form();
			}
			if ( ! empty( $_REQUEST['form_name'] ) && $EM_Form->form_name == $_REQUEST['form_name'] && empty( $_REQUEST['bookings_form_action'] ) ) {
				//set up booking form field map and save/retreive previous data
				if ( $EM_Form->editor_get_post() ) {
					foreach ( $EM_Form->form_fields as $form_field ) {
						if ( $form_field['fieldid'] == 'user_email' ) {
							$user_email_in_form = true;
						}
					}
					//Save into DB rather than as an option
					$booking_form_data = array(
						'name' => self::$form_name,
						'form' => $EM_Form->form_fields,
					);
					$saved             = false;
					if ( empty( $user_email_in_form ) ) {
						$EM_Notices->add_error( __( 'You must include an E-mail field type for booking forms to work. These are used to create the user account and aren\'t shown to logged in users.', 'em-pro' ) );
					} else {
						$saved = $wpdb->update( EM_META_TABLE, array( 'meta_value' => serialize( $booking_form_data ) ), array( 'meta_id' => self::$form_id ) );
					}
					//Update Values
					if ( $saved !== false ) {
						$EM_Notices->add_confirm( __( 'Changes Saved', 'em-pro' ) );
					} elseif ( count( $EM_Form->get_errors() ) > 0 ) {
						$EM_Notices->add_error( $EM_Form->get_errors() );
					}
				}
			} elseif ( ! empty( $_REQUEST['bookings_form_action'] ) ) {
				if ( $_REQUEST['bookings_form_action'] == 'default' && wp_verify_nonce( $_REQUEST['_wpnonce'], 'bookings_form_default' ) ) {
					//make this booking form the default
					update_option( 'em_booking_form_fields', $_REQUEST['form_id'] );
					$EM_Notices->add_confirm( sprintf( __( 'The form <em>%s</em> is now the default booking form. All events without a pre-defined booking form will start using this form from now on.', 'em-pro' ), self::$form_name ) );
				} elseif ( $_REQUEST['bookings_form_action'] == 'delete' && wp_verify_nonce( $_REQUEST['_wpnonce'], 'bookings_form_delete' ) ) {
					//load and save booking form object with new name
					$saved = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . EM_META_TABLE . " WHERE meta_id='%s'", $_REQUEST['form_id'] ) );
					if ( $saved ) {
						self::$form = false;
						$EM_Notices->add_confirm( sprintf( __( '%s Deleted', 'em-pro' ), __( 'Booking Form', 'em-pro' ) ), 1 );

					}
				} elseif ( $_REQUEST['bookings_form_action'] == 'rename' && wp_verify_nonce( $_REQUEST['_wpnonce'], 'bookings_form_rename' ) ) {
					//load and save booking form object with new name
					$booking_form_data = array(
						'name' => wp_kses_data( $_REQUEST['form_name'] ),
						'form' => $EM_Form->form_fields,
					);
					self::$form_name   = $booking_form_data['name'];
					$saved             = $wpdb->update( EM_META_TABLE, array( 'meta_value' => serialize( $booking_form_data ) ), array( 'meta_id' => self::$form_id ) );
					$EM_Notices->add_confirm( sprintf( __( 'Form renamed to <em>%s</em>.', 'em-pro' ), self::$form_name ) );
				} elseif ( $_REQUEST['bookings_form_action'] == 'add' && wp_verify_nonce( $_REQUEST['_wpnonce'], 'bookings_form_add' ) ) {
					//create new form with this name and save first off
					$EM_Form           = new EM_Form( self::get_form_template(), 'em_bookings_form' );
					$booking_form_data = array(
						'name' => wp_kses_data( $_REQUEST['form_name'] ),
						'form' => $EM_Form->form_fields,
					);
					self::$form        = $EM_Form;
					self::$form_name   = $booking_form_data['name'];
					$saved             = $wpdb->insert(
						EM_META_TABLE,
						array(
							'meta_value' => serialize( $booking_form_data ),
							'meta_key'   => static::$form_meta_key,
							'object_id'  => 0,
						)
					);
					self::$form_id     = $wpdb->insert_id;
					$EM_Notices->add_confirm( __( 'New form created. You are now editing your new form.', 'em-pro' ), true );
					wp_redirect( add_query_arg( array( 'form_id' => self::$form_id ), em_wp_get_referer() ) );
					exit();
				} elseif ( $_REQUEST['bookings_form_action'] == 'duplicate' && wp_verify_nonce( $_REQUEST['_wpnonce'], 'bookings_form_duplicate' ) ) {
					$sql           = $wpdb->prepare( 'SELECT meta_id, meta_value FROM ' . EM_META_TABLE . ' WHERE meta_key=%s AND meta_id=%d', static::$form_meta_key, $_REQUEST['form_id'] );
					$form_data_row = $wpdb->get_row( $sql, ARRAY_A );
					if ( ! empty( $form_data_row ) ) {
						$booking_form_data          = unserialize( $form_data_row['meta_value'] );
						$booking_form_data['name'] .= ' (' . esc_html__( 'Duplicate', 'em-pro' ) . ')';
						$saved                      = $wpdb->insert(
							EM_META_TABLE,
							array(
								'meta_value' => serialize( $booking_form_data ),
								'meta_key'   => static::$form_meta_key,
								'object_id'  => 0,
							)
						);
						$duplicate_form_id          = $wpdb->insert_id;
						$EM_Notices->add_confirm( __( 'New form created. You are now editing your new form.', 'em-pro' ), true );
						wp_redirect( add_query_arg( array( 'form_id' => $duplicate_form_id ), em_wp_get_referer() ) );
						exit();
					}
				}
			}
		}
	}

	public static function admin_page() {
		$EM_Form = self::get_form();
		?>
					<?php do_action( 'em_booking_form_custom_admin_page_header' ); ?>
					<div id="em-booking-form-editor" class="postbox">
						<div class="handlediv" title=""><br></div>
						<h3 id="booking-form">
							<span><?php _e( 'Booking Form - General Information', 'em-pro' ); ?></span>
						</h3>
						<div class="inside">
							<p><?php _e( 'You can customize the fields shown in your booking forms below. ', 'em-pro' ); ?> <?php _e( 'It is required that you have at least an email and name field so guest users can register.', 'em-pro' ); ?></p>
							<p><?php echo sprintf( __( 'Registration fields are only shown to guest visitors by default. You can choose to show these fields and make them editable by logged in user in your <a href="%s">PRO Booking Form Options</a>.', 'em-pro' ), '?post_type=event&page=events-manager-options#bookings' ); ?>
							<div>
								<form method="get" action="#booking-form"> 
									<?php _e( 'Selected Booking Form', 'em-pro' ); ?> :
									<select name="form_id" onchange="this.parentNode.submit()">
										<?php foreach ( self::get_forms_names() as $form_key => $form_name_option ) : ?>
										<option value="<?php echo $form_key; ?>" 
											<?php
											if ( $form_key == self::$form_id ) {
												echo 'selected="selected"';}
											?>
										><?php echo $form_name_option; ?></option>
										<?php endforeach; ?>
									</select>
									<input type="hidden" name="post_type" value="<?php echo EM_POST_TYPE_EVENT; ?>" />
									<input type="hidden" name="page" value="<?php echo esc_attr( $_REQUEST['page'] ); ?>" />
								</form>
								<?php if ( self::$form_id != get_option( 'em_booking_form_fields' ) ) : ?>
								<form method="post" action="<?php echo add_query_arg( array( 'form_id' => null ) ); ?>#booking-form"> 
									<input type="hidden" name="form_id" value="<?php echo esc_attr( $_REQUEST['form_id'] ); ?>" />
									<input type="hidden" name="bookings_form_action" value="default" />
									<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'bookings_form_default' ); ?>" />
									<input type="submit" value="<?php _e( 'Make Default', 'em-pro' ); ?> &raquo;" class="button-secondary" onclick="return confirm('
									<?php
										_e( 'You are about to make this your default booking form. All events without an existing specifically chosen booking form will use this new default form from now on.', 'em-pro' );
									?>
										\n\n
										<?php
										_e( 'Are you sure you want to do this?', 'em-pro' );
										?>
										');" />
								</form>
								<?php endif; ?> | 
								<form method="post" action="<?php echo add_query_arg( array( 'form_id' => null ) ); ?>#booking-form" id="bookings-form-add">
									<input type="text" name="form_name" />
									<input type="hidden" name="bookings_form_action" value="add" />
									<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'bookings_form_add' ); ?>" />
									<input type="submit"  value="<?php _e( 'Add New', 'em-pro' ); ?> &raquo;" class="button-secondary" />
								</form>
								<?php if ( self::$form_id == get_option( 'em_booking_form_fields' ) ) : ?>
								<br /><em><?php _e( 'This is the default bookings form and will be used for any event where you have not chosen a specific form to use.', 'em-pro' ); ?></em>
								<?php endif; ?>
							</div>
							<br />
							<form method="post" action="<?php echo add_query_arg( array( 'form_id' => self::$form_id ) ); ?>#booking-form" id="bookings-form-rename">
								<span style="font-weight:bold;"><?php echo sprintf( __( 'You are now editing ', 'em-pro' ), self::$form_name ); ?></span>
								<input type="text" name="form_name" value="<?php echo self::$form_name; ?>" />
								<input type="hidden" name="form_id" value="<?php echo self::$form_id; ?>" />
								<input type="hidden" name="bookings_form_action" value="rename" />
								<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'bookings_form_rename' ); ?>" />
								<input type="submit" value="<?php _e( 'Rename', 'em-pro' ); ?> &raquo;" class="button-secondary" />
							</form>
							<form method="post" action="<?php echo add_query_arg( array( 'form_id' => self::$form_id ) ); ?>#booking-form" id="bookings-form-duplicate">
								<input type="hidden" name="form_id" value="<?php echo self::$form_id; ?>" />
								<input type="hidden" name="bookings_form_action" value="duplicate" />
								<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'bookings_form_duplicate' ); ?>" />
								<input type="submit" value="<?php _e( 'Duplicate', 'em-pro' ); ?> &raquo;" class="button-secondary" />
							</form>
							<?php if ( self::$form_id != get_option( 'em_booking_form_fields' ) ) : ?>
							<form method="post" action="<?php echo add_query_arg( array( 'form_id' => null ) ); ?>#booking-form" id="bookings-form-delete">
								<input type="hidden" name="form_id" value="<?php echo esc_attr( $_REQUEST['form_id'] ); ?>" />
								<input type="hidden" name="bookings_form_action" value="delete" />
								<input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'bookings_form_delete' ); ?>" />
								<input type="submit" value="<?php _e( 'Delete', 'em-pro' ); ?> &raquo;" class="button-secondary" onclick="return confirm('
								<?php
									_e( 'Are you sure you want to delete this form?', 'em-pro' );
								?>
									\n\n
									<?php
									_e( 'All events using this form will start using the default form automatically.', 'em-pro' );
									?>
									');" />
							</form>
							<?php endif; ?>
							<br /><?php _e( '<strong>Important:</strong> When editing this form, to make sure your old booking information is displayed, make sure new field ids correspond with the old ones.', 'em-pro' ); ?>
							<br /><br />
							<?php echo $EM_Form->editor(); ?>
						</div>
					</div>
		<?php
	}

	public static function data_privacy_export( $export_item, EM_Booking $EM_Booking ) {
		$EM_Form = EM_Booking_Form::get_form( $EM_Booking->event_id, $EM_Booking );
		foreach ( $EM_Form->form_fields as $fieldid => $field ) {
			if ( ! array_key_exists( $fieldid, $EM_Form->user_fields ) && ! in_array( $fieldid, array( 'user_email', 'user_name' ) ) && $field['type'] != 'html' && $field['type'] != 'captcha' ) {
				//get value of field
				$field_value = ( isset( $EM_Booking->booking_meta['booking'][ $fieldid ] ) ) ? $EM_Booking->booking_meta['booking'][ $fieldid ] : '';
				//account for the free version and the booking_comment field so that old booking info still shows
				if ( empty( $field_value ) && $fieldid == 'booking_comment' && ! empty( $EM_Booking->booking_comment ) ) {
					$field_value = $EM_Booking->booking_comment;
				}
				if ( $field_value !== '' ) {
					$export_item['data'][] = array(
						'name'  => $field['label'],
						'value' => $EM_Form->get_formatted_value( $field, $field_value ),
					);
				}
			}
		}
		return $export_item;
	}
}
EM_Booking_Form::init();
require 'attendee-forms.php';
