<?php
/**
 * ACFE Base Form Action Class.
 *
 * Holds methods common to ACFE Form Action classes.
 *
 * @package Conditional_Form_Actions_For_ACFE
 * @since 0.1
 */

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * CiviCRM Profile Sync "Base" ACFE Form Action Class.
 *
 * A class that is extended by CiviCRM Profile Sync ACFE Form Action classes.
 *
 * @since 0.1
 */
class CFAFA_Form_Action_Base {

	/**
	 * Form Action Name.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $action_name The unique name of the Form Action.
	 */
	public $action_name = '';

	/**
	 * Form Action Label.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $action_label The label of the Form Action.
	 */
	public $action_label = '';

	/**
	 * Form Action Alias Placeholder.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $alias_placeholder The alias placeholder for the Form Action.
	 */
	public $alias_placeholder = '';

	/**
	 * Field Key Prefix.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $field_key The prefix for the Field Key.
	 */
	public $field_key = '';

	/**
	 * Field Name Prefix.
	 *
	 * @since 0.1
	 * @access public
	 * @var string $field_name The prefix for the Field Name.
	 */
	public $field_name = '';

	/**
	 * Constructor.
	 *
	 * @since 0.1
	 */
	public function __construct() {

		// Callback for the "acfe/form/load/..." hook.
		add_filter( 'acfe/form/load/' . $this->action_name, [ $this, 'load' ], 10, 3 );

		// Callback for the "acfe/form/make/..." hook.
		add_action( 'acfe/form/make/' . $this->action_name, [ $this, 'make' ], 10, 3 );

		// Generic callback for ACFE Form Actions hook.
		add_filter( 'acfe/form/actions', [ $this, 'action_add' ] );

	}

	/**
	 * Allow classes to configure themselves prior to the Layout being returned.
	 *
	 * @since 0.1
	 */
	public function configure() {}

	/**
	 * Performs tasks when the Form that the Action is attached to is loaded.
	 *
	 * @since 0.1
	 *
	 * @param array   $form The array of Form data.
	 * @param integer $current_post_id The ID of the Post in which the Form has been embedded.
	 * @param string  $action The customised name of the action.
	 */
	public function load( $form, $current_post_id, $action ) {
		return $form;
	}

	/**
	 * Saves the result of the Action for use by subsequent Actions.
	 *
	 * @since 0.1
	 *
	 * @param string $action The name of the Action.
	 * @param array  $data The result of the Action.
	 */
	public function load_action_save( $action, $data ) {

		// Get the existing array of Action results.
		$actions = get_query_var( 'acfe_form_actions', [] );

		$actions[ $this->action_name ] = $data;
		if ( ! empty( $action ) ) {
			$actions[ $action ] = $data;
		}

		// Update array of Action results.
		set_query_var( 'acfe_form_actions', $actions );

	}

	/**
	 * Performs the Action when the Form the Action is attached to is submitted.
	 *
	 * @since 0.1
	 *
	 * @param array   $form The array of Form data.
	 * @param integer $current_post_id The ID of the Post from which the Form has been submitted.
	 * @param string  $action The customised name of the action.
	 */
	public function make( $form, $current_post_id, $action ) {}

	/**
	 * Maybe skip the Action when the Form the Action is attached to is submitted.
	 *
	 * @since 0.1
	 *
	 * @param array   $form The array of Form data.
	 * @param integer $current_post_id The ID of the Post from which the Form has been submitted.
	 * @param string  $action The customised name of the Form Action.
	 * @return bool $prepare The net result of the set of filters.
	 */
	public function make_skip( $form, $current_post_id, $action ) {

		// Get some Form details.
		$form_name = acf_maybe_get( $form, 'name' );
		$form_id = acf_maybe_get( $form, 'ID' );

		// Assume we're good to go.
		$prepare = true;

		/**
		 * Allow others to prevent Form Action.
		 *
		 * Returning false for any of these filters will skip the Action.
		 *
		 * @since 0.1
		 *
		 * @param bool $prepare True by default so that the Form Action goes ahead.
		 * @param array $form The array of Form data.
		 * @param integer $current_post_id The ID of the Post from which the Form has been submitted.
		 * @param string $action The customised name of the Form Action.
		 */
		$filter = 'acfe/form/prepare/' . $this->action_name;
		$prepare = apply_filters( $filter, $prepare, $form, $current_post_id, $action );
		$prepare = apply_filters( $filter . '/form=' . $form_name, $prepare, $form, $current_post_id, $action );
		if ( ! empty( $action ) ) {
			$prepare = apply_filters( $filter . '/action=' . $action, $prepare, $form, $current_post_id, $action );
		}

		// --<
		return $prepare;

	}

	/**
	 * Saves the result of the Action for use by subsequent Actions.
	 *
	 * @since 0.1
	 *
	 * @param string $action The name of the Action.
	 * @param array  $data The result of the Action.
	 */
	public function make_action_save( $action, $data ) {

		// Get the existing array of Action results.
		$actions = get_query_var( 'acfe_form_actions', [] );

		$actions[ $this->action_name ] = $data;
		if ( ! empty( $action ) ) {
			$actions[ $action ] = $data;
		}

		// Update array of Action results.
		set_query_var( 'acfe_form_actions', $actions );

	}

	/**
	 * Defines the action by adding a layout.
	 *
	 * The "name" value of the layout determines the construction of the
	 * "acfe/form/load/..." and "acfe/form/make/..." actions.
	 *
	 * @since 0.1
	 *
	 * @param array $layouts The existing layouts.
	 * @return array $layouts The modified layouts.
	 */
	public function action_add( $layouts ) {

		// Let the classes that extend this one configure themselves.
		$this->configure();

		// Init our layout.
		$layout = [
			'key' => 'layout_' . $this->action_name,
			'name' => $this->action_name,
			'label' => $this->action_label,
			'display' => 'row',
			'min' => '',
			'max' => '',
		];

		// Build Action Tab.
		$action_tab_fields = $this->tab_action_add();

		// Build Mapping Tab.
		$mapping_tab_fields = $this->tab_mapping_add();

		// Build Attachments Tab.
		$attachments_tab_fields = $this->tab_attachments_add();

		// Combine Sub-Fields.
		$sub_fields = array_merge(
			$action_tab_fields,
			$mapping_tab_fields,
			$attachments_tab_fields
		);

		/**
		 * Let the classes that extend this one modify the Sub-Fields.
		 *
		 * @since 0.1
		 *
		 * @param array $sub_fields The array of Sub-Fields.
		 */
		$layout['sub_fields'] = apply_filters( 'cfafa/acfe/form/actions/sub_fields', $sub_fields );

		// Add our completed layout to the layouts array.
		$layouts[ 'layout_' . $this->action_name ] = $layout;

		// --<
		return $layouts;

	}

	/**
	 * Defines the "Action" Tab.
	 *
	 * These Fields are required to configure the Form Action.
	 *
	 * The ACFE "Action name" Field has a pre-defined format, e.g. it must be
	 * assigned the "acfe_slug" Field Type and have "acfe_form_custom_alias" as
	 * its "name". Only its "placeholder" attribute needs to be configured.
	 *
	 * @since 0.1
	 *
	 * @return array $fields The array of Fields for this section.
	 */
	public function tab_action_add() {

		// Init Fields array.
		$fields = [];

		// "Action" Tab wrapper.
		$fields[] = [
			'key' => $this->field_key . 'tab_action',
			'label' => __( 'Action', 'conditional-form-actions-for-acfe' ),
			'name' => '',
			'type' => 'tab',
			'instructions' => '',
			'required' => 0,
			'conditional_logic' => 0,
			'wrapper' => [
				'width' => '',
				'class' => '',
				'id' => '',
				'data-no-preference' => true,
			],
			'acfe_permissions' => '',
			'placement' => 'top',
			'endpoint' => 0,
		];

		// "Action name" Field.
		$fields[] = [
			'key' => $this->field_key . 'custom_alias',
			'label' => __( 'Action name', 'conditional-form-actions-for-acfe' ),
			'name' => 'acfe_form_custom_alias',
			'type' => 'acfe_slug',
			'instructions' => __( '(Required) Name this action so it can be referenced.', 'conditional-form-actions-for-acfe' ),
			'required' => 1,
			'conditional_logic' => 0,
			'wrapper' => [
				'width' => '',
				'class' => '',
				'id' => '',
				'data-instruction-placement' => 'field',
			],
			'acfe_permissions' => '',
			'default_value' => '',
			'placeholder' => $this->alias_placeholder,
			'prepend' => '',
			'append' => '',
			'maxlength' => '',
		];

		// Add any further Fields.
		$action_extras = $this->tab_action_append();
		if ( ! empty( $action_extras ) ) {
			$fields = array_merge(
				$fields,
				$action_extras
			);
		}

		// --<
		return $fields;

	}

	/**
	 * Defines additional Fields for the "Action" Tab.
	 *
	 * @since 0.1
	 *
	 * @return array $fields The array of Fields for this section.
	 */
	public function tab_action_append() {
		$fields = [];
		return $fields;
	}

	/**
	 * Defines the "Mapping" Tab.
	 *
	 * @since 0.1
	 *
	 * @return array $fields The array of Fields for this section.
	 */
	public function tab_mapping_add() {
		$fields = [];
		return $fields;
	}

	/**
	 * Defines the "Mapping" Tab Header.
	 *
	 * @since 0.1
	 *
	 * @param string $label The label for this section.
	 * @return array $fields The array of Fields for this section.
	 */
	public function tab_mapping_header( $label = '' ) {

		// Set a default label.
		if ( empty( $label ) ) {
			$label = __( 'Mapping', 'conditional-form-actions-for-acfe' );
		}

		// "Mapping" Tab wrapper.
		$mapping_tab = [
			[
				'key' => $this->field_key . 'tab_load',
				'label' => $label,
				'name' => '',
				'type' => 'tab',
				'instructions' => '',
				'required' => 0,
				'conditional_logic' => 0,
				'wrapper' => [
					'width' => '',
					'class' => '',
					'id' => '',
					'data-no-preference' => true,
				],
				'acfe_permissions' => '',
				'placement' => 'top',
				'endpoint' => 0,
			],
		];

		// Combine Fields.
		$fields = array_merge(
			$mapping_tab
		);

		// --<
		return $fields;

	}

	/**
	 * Defines the "Attachments" Tab.
	 *
	 * @since 0.1
	 *
	 * @return array $fields The array of Fields for this section.
	 */
	public function tab_attachments_add() {
		$fields = [];
		return $fields;
	}

	/**
	 * Defines the "Attachments" Tab Header.
	 *
	 * @since 0.1
	 *
	 * @return array $fields The array of Fields for this section.
	 */
	public function tab_attachments_header() {

		// "Attachments" Tab wrapper.
		$attachments_tab = [
			[
				'key' => $this->field_key . 'tab_attachments',
				'label' => __( 'Attachments', 'conditional-form-actions-for-acfe' ),
				'name' => '',
				'type' => 'tab',
				'instructions' => '',
				'required' => 0,
				'conditional_logic' => 0,
				'wrapper' => [
					'width' => '',
					'class' => '',
					'id' => '',
					'data-no-preference' => true,
				],
				'acfe_permissions' => '',
				'placement' => 'top',
				'endpoint' => 0,
			],
		];

		// Combine Fields.
		$fields = array_merge(
			$attachments_tab
		);

		// --<
		return $fields;

	}

	/**
	 * Gets the array that defines a "Map Field" for the "Mapping" Tab.
	 *
	 * @since 0.1
	 *
	 * @param string $code The unique code for the Field.
	 * @param string $label The label for the Field.
	 * @param array  $conditional_logic The conditional logic for the Field.
	 * @return array $field The array of Field data.
	 */
	public function mapping_field_get( $code, $label, $conditional_logic = [] ) {

		// Build the Field array.
		$field = [
			'key' => $this->field_key . 'map_' . $code,
			'label' => $label,
			'name' => $this->field_name . 'map_' . $code,
			'type' => 'select',
			'instructions' => '',
			'required' => 0,
			'wrapper' => [
				'width' => '',
				'class' => '',
				'id' => '',
			],
			'acfe_permissions' => '',
			'choices' => [],
			'default_value' => [],
			'allow_null' => 1,
			'multiple' => 0,
			'ui' => 1,
			'return_format' => 'value',
			'placeholder' => __( 'Default', 'conditional-form-actions-for-acfe' ),
			'ajax' => 0,
			'search_placeholder' => __( 'Enter a custom value or template tag. (See "Cheatsheet" tab)', 'conditional-form-actions-for-acfe' ),
			'allow_custom' => 1,
		];

		// Default conditional logic.
		$field['conditional_logic'] = 0;

		// Maybe replace with custom conditional logic.
		if ( ! empty( $conditional_logic ) ) {
			$field['conditional_logic'] = $conditional_logic;
		}

		// --<
		return $field;

	}

	/**
	 * Adds filters that configure "Mapping Fields" when loaded.
	 *
	 * @since 0.1
	 *
	 * @param string $code The unique code for the Field.
	 */
	public function mapping_field_filters_add( $code ) {

		// Grab reference to ACFE Helper object.
		$helpers = acf_get_instance( 'acfe_dynamic_forms_helpers' );

		// Populate mapping Fields.
		add_filter( 'acf/prepare_field/name=' . $this->field_name . 'map_' . $code, [ $helpers, 'map_fields_deep_no_custom' ] );

	}

	/**
	 * Adds filters that configure a named Field when loaded.
	 *
	 * @since 0.1
	 *
	 * @param string $name The unique name for the Field.
	 */
	public function mapping_field_filter_deep( $name ) {

		// Grab reference to ACFE Helper object.
		$helpers = acf_get_instance( 'acfe_dynamic_forms_helpers' );

		// Populate named Field.
		add_filter( 'acf/prepare_field/name=' . $name, [ $helpers, 'map_fields_deep' ] );

	}

	/**
	 * Prepare the data from an ACFE Form.
	 *
	 * @since 0.1
	 *
	 * @param array $form_data The array of data from the ACFE Form.
	 * @return array $filtered_data The filtered data.
	 */
	public function form_data_prepare( $form_data ) {

		// Init filtered data.
		$filtered_data = [];

		// Bail if we have no Form data to save.
		if ( empty( $form_data ) ) {
			return $filtered_data;
		}

		// Populate Activity data from the Form data.
		foreach ( $form_data as $param => $value ) {
			// Allow (string) "0" as valid data.
			if ( ! empty( $value ) || $value === '0' ) {
				$filtered_data[ $param ] = $value;
			}
		}

		// --<
		return $filtered_data;

	}

} // Class ends.