<?php
/**
 * The main class for Extra Action.
 */

/**
 * Class SG_Extra_Action
 */
class SG_Extra_Action {

	/**
	 * Action Icon
	 *
	 * @var string
	 */
	protected $icon = 'fal fa-plus-square';

	/**
	 * Action Slug
	 *
	 * @var string
	 */
	protected $slug = '';

	/**
	 * Instance ID
	 *
	 * @var integer
	 */
	protected $instance_id = 0;

	/**
	 * Giveaway ID
	 *
	 * @var integer
	 */
	protected $giveaway_id = 0;

	/**
	 * Action Title
	 *
	 * @var string
	 */
	protected $title = '';

	/**
	 * Action Description
	 *
	 * @var string
	 */
	protected $description = '';

	/**
	 * A category under which this action will be shown.
	 *
	 * @var string
	 */
	protected $category = 'general';

	/**
	 * Data for admin area.
	 *
	 * @var array
	 */
	protected $admin_data = array();

	/**
	 * Data given by the subscriber meta data.
	 *
	 * @var array
	 */
	protected $data = null;

	/**
     * Fields
     *
	 * @var array
	 */
	protected $fields = array();

	/**
     * Is this action using the action button.
     *
	 * @var bool
	 */
	protected $has_action_button = true;

	/**
     * Is the action auto submitted when the action is clicked?
     *
	 * @var bool
	 */
	protected $auto_submit = false;

	/**
     * Is the form complete button disabled at first?
     *
	 * @var bool
	 */
	protected $submit_disabled = true;

	/**
     * Subscriber ID.
     *
	 * @var int
	 */
	protected $subscriber_id = 0;

	/**
     * Admin Errors
     *
	 * @var array
	 */
	protected $admin_errors = array();

	/**
	 * @var null|string
	 */
	protected $complete_button_text = null;

	/**
     * If an action is internal only, it won't be display for the user to select them.
     *
	 * @var bool
	 */
	protected $internal_only = false;

	/**
     * Entries given by the action.
     *
	 * @var int
	 */
	protected $entries = 1;

	/**
     * Store option templates to load at the footer
	 * @var array
	 */
	public $option_templates = array();

	/**
     * If locked, it can't be submitted.
     *
	 * @var bool
	 */
	protected $locked = false;

	/**
     * On AJAX complete, should we reload the html?
	 * @return bool
	 */
	public function reload_html() {
	    return true;
    }

	/**
	 * Admin Form
	 */
	public function form_admin( $index = 0 ) {
	    $instance_id = isset( $this->admin_data['instance_id'] ) ? $this->admin_data['instance_id'] : '';
		$title       = isset( $this->admin_data['title'] ) ? $this->admin_data['title'] : '';
		if ( $instance_id ) {
			$this->validate_admin_data();
        }
		$hasErrors   = count( $this->admin_errors ) > 0;
		?>
        <div class="sg-admin-action <?php if ( $hasErrors ) { echo 'sg-admin-action-with-errors'; } ?>" data-index="<?php echo $index; ?>">
            <h3 class="sg-admin-action-title"><?php echo esc_html( $this->get_title() ); ?><?php echo $title ? ': ' . $title : ''; ?></h3>
		    <div class="sg-admin-form sg-action-form sg-action-form-<?php echo $this->slug; ?>">
                <input type="hidden" name="entries_actions[<?php echo $index; ?>][action]" value="<?php echo $this->slug; ?>" />
                <input type="hidden" name="entries_actions[<?php echo $index; ?>][instance_id]" value="<?php echo $instance_id; ?>" />
                <?php
                    if ( $hasErrors ) {
                        for( $i = 0; $i < count( $this->admin_errors ); $i++ ) {
                            $error = $this->admin_errors[ $i ];
                            echo '<div class="notice error"><p>' . esc_html( $error ) . '</p></div>';
                        }
                    }
                ?>
                <div class="sg-form-field">
                    <label for="entries_actions_<?php echo $index; ?>">
                        <?php esc_html_e( 'Title', 'giveasap' ); ?>
                    </label>
                    <div class="sg-action-input-container">
                        <input type="text" id="entries_actions_<?php echo $index; ?>" name="entries_actions[<?php echo $index; ?>][title]" class="widefat" value="<?php echo esc_attr( $title ); ?>" />
                    </div>
                </div>

                <?php
                    $fields = $this->get_fields();

                    if ( $fields ) {
                        foreach( $fields as $field ) {
                            $this->render_field( $index, $field );
                        }
                    }

                    do_action( 'sg_extra_action_admin_form', $index, $this );
                    do_action( 'sg_extra_action_admin_form_' . $this->slug, $index, $this );
                ?>

                <button type="button" class="button button-secondary small sg-admin-action-remove"><?php esc_html_e( 'Remove', 'giveasap' ); ?></button>
            </div>
        </div>
		<?php
	}

	/**
	 * Public Form
	 */
	public function form_public() {
	    $admin_data = $this->get_admin_data();
        $data       = $this->get_data();

        if ( $this->can_complete() ) {
            $this->submit_disabled = false;
        }

        $complete_text_button = null === $this->complete_button_text ? __( 'Complete', 'giveasap' ) : $this->complete_button_text;
	    ?>
        <div id="sgExtraAction<?php echo esc_attr( $admin_data['instance_id'] ); ?>" class="sg-extra-action sg-extra-action-<?php echo esc_attr( $this->get_slug() ); ?> sg-extra-action-category-<?php echo esc_attr( $this->category ); ?> <?php echo $this->is_locked() ? 'sg-extra-action-locked': ''; ?>" <?php echo $this->action_attributes(); ?>>
            <button aria-expanded="false" class="sg-extra-action-title">
                <?php
                echo $this->get_icon();
                echo '<span class="action-title">' . esc_html( $admin_data['title'] ) . '</span>';
                if ( $this->is_completed() ) {
	                echo $this->complete_mark();
                } else {
	                echo $this->action_entries();
                }

                ?>
            </button>
            <form method="POST" enctype="multipart/form-data">
                <input type="hidden" name="extra_action" value="<?php echo $this->get_slug(); ?>" />
                <input type="hidden" name="instance" value="<?php echo esc_attr( $this->get_instance_id() ); ?>" />
                <input type="hidden" name="subscriber_id" value="<?php echo esc_attr( $this->get_subscriber_id() ); ?>" />
                <input type="hidden" name="nonce" value="<?php echo wp_create_nonce( 'giveaway' ); ?>" />
                <?php
                    if ( $this->is_locked() ) {
                        ?>
                        <div class="sg-extra-action-locked">
                            <span class="fal fa-lock-alt sg-extra-action-locked-icon"></span>
                            <div class="sg-extra-action-locked-text">
                                <?php

                                $unlock_message = _n_noop( 'Complete %s action in total to unlock it', 'Complete %s actions in total to unlock it', 'giveasap' );

                                printf( translate_nooped_plural( $unlock_message, $this->get_mandatory(), 'giveasap' ), $this->get_mandatory() );

                                ?>
                            </div>
                        </div>
                        <?php
                    }
                ?>
                <div class="sg-extra-action-form-body">
                    <?php
                    $this->form_public_content();
                    if ( $this->has_action_button ) {
                        $this->action_button();
                    }
                    ?>
                </div>
                <div class="sg-extra-action-actions">
                    <?php if ( ! $this->is_completed() ) { ?>
                    <button type="submit" name="sg_extra_action_submit" class="sg-extra-action-button giveasap_button" <?php if ( $this->submit_disabled ) { echo 'disabled="disabled"'; } ?>>
                        <?php echo esc_html( $complete_text_button ); ?>
                    </button>
                    <?php } ?>
                    <button id="sgExtraActionClose<?php echo esc_attr( $admin_data['instance_id'] ); ?>"  type="button" class="giveasap_button giveasap_button-blank sg-extra-action-close"><?php esc_html_e( 'Cancel', 'giveasap' ); ?></button>
                </div>
            </form>
        </div>
        <?php
    }

	/**
	 * Get the action button.
	 * This is a general button for any action that can be used.
     * In most cases, it will enable the complete button to submit it.
	 */
    public function action_button() {
        $data = $this->get_admin_data();

        ?>
        <button type="button" data-check-action class="sg_extra_action_button giveasap_button">
	        <?php echo $data['button_text']; ?>
        </button>
        <?php
    }

	/**
	 * The form content of the public part.
	 */
    public function form_public_content() {}

	/**
     * Complete the action
     *
	 * @param integer $instance_id
	 * @param integer $subscriber_id
	 * @param array   $data Data posted from the front form.
	 *
	 * @return array|bool|WP_Error
	 */
	public function complete( $instance_id, $subscriber_id, $data = array() ) {
		$subscriber = sg_get_subscriber( $subscriber_id );

		if ( ! $subscriber ) {
			return new WP_Error( 'no-subscriber', __( 'Subscriber not found.', 'giveasap' ) );
		}

		$this->set_subscriber_id( $subscriber_id );
		$this->set_instance_id( $instance_id );
		$subscriber_data = $subscriber->get_data();
		$giveaway_id     = $subscriber_data['post_id'];
		$this->set_giveaway_id( $giveaway_id );

		if ( ! $this->is_action_instance_valid( $giveaway_id ) ) {
			return new WP_Error( 'no-valid-action', __( 'The Action and the Instance are not matching.', 'giveasap' ) );
		}

		$action_db = $this->get_action_from_db();

		if ( $this->needs_validation() && ( ! $action_db || 'invalid' === $action_db['status'] ) ) {
		    return new WP_Error( 'needs-validation', __( 'The action needs validation first.', 'giveasap' ) );
        }

		$this->set_admin_data_from_giveaway( $giveaway_id );

		if ( $this->get_mandatory() > 0 ) {
			$completed_actions = sg_get_public_completed_actions_for_subscriber( $subscriber_id );
			if ( count( $completed_actions ) < $this->get_mandatory() ) {
				$unlock_message = _n_noop( 'You need to complete %s action in total to submit it', 'You need to complete %s actions in total to submit it', 'giveasap' );

				$error = sprintf( translate_nooped_plural( $unlock_message, $this->get_mandatory(), 'giveasap' ), $this->get_mandatory() );

				return new WP_Error( 'no-mandatory-actions', $error );
			}
		}

		$complete = $this->complete_action( $action_db, $data );

		if ( is_wp_error( $complete ) ) {
			return $complete;
		}

        // We don't have any data of it. Let's create it then.
        if ( $action_db ) {
            if ( 'completed' === $action_db['status'] ) {
                $ret = new WP_Error( 'action-completed', __( 'Action was already completed', 'giveasap' ) ); // We have already completed it.
            } else {
	            $ret = $this->update_status( 'completed', $action_db['id'], $complete );
            }
        } else {
	        $ret = $this->create_action( 'completed', $giveaway_id, $complete );
	        $action_db = $this->get_action_from_db();
        }

        $this->set_admin_data( maybe_unserialize( $action_db['data'] ) );

		if ( ! is_wp_error( $ret ) && $ret ) {
		    $subscriber->add_entries( $this->get_action_entries() );
		    do_action( 'sg_extra_action_completed', $action_db, $this );
        }

        return $ret;
    }

	/**
     * Render the Field.
     *
	 * @param $index
	 * @param $field
     *
     * @return void
	 */
	public function render_field( $index, $field ) {

	    $defaults = array(
            'type'        => 'text',
            'id'          => '',
            'label'       => '',
            'required'    => false,
            'multioption' => false,
            'class'       => array( 'widefat' ),
            'default'     => '',
            'desc'        => '',
        );

	    $admin_data = $this->get_admin_data();

	    $field      = wp_parse_args( $field, $defaults );
	    $label      = '<label for="entries_actions_' . $index . '_' . $field['id'] . '">';
        $label     .= $field['label'] . ( $field['required'] ? '<span class="required">*</span>' : '' );
        $label     .= '</label>';
        $id         = 'entries_actions_' . $index . '_' . $field['id'];
        $name       = 'entries_actions[' . $index . '][' . $field['id'] . ']';
        $value      = isset( $admin_data[ $field['id'] ] ) ? $admin_data[ $field['id'] ] : $field['default'];
        $required   = $field['required'] ? 'required' : '';
        $class      = $field['class'] ? $field['class'] : '';
		$html_field = '<div class="sg-form-field sg-form-field-' . $field['type'] .'">%s</div>';

		$fieldClass = '';
        if ( $class ) {
            $fieldClass = 'class="';
            if ( is_array( $class ) ) {
                $fieldClass .= implode( ' ', $class );
            } else{
                $fieldClass .= $class;
            }
            $fieldClass .= '"';
        }

	    switch ( $field['type'] ) {
            case 'text':
            case 'url':
            case 'number':
                $input = '<div class="sg-action-input-container">';
                $input .= '<input ' . $fieldClass . ' type="' . esc_attr( $field['type'] ) . '" value="' . esc_attr( $value ) . '" id="' . esc_attr( $id ) .'" name="' . esc_attr( $name ) .'"/>';
                $input .= '</div>';
                if ( $field['desc'] ) {
                    $input .= '<span class="description">' . esc_html( $field['desc'] ) . '</span>';
                }
                printf( $html_field, $label . $input );
                break;
		    case 'textarea':
			    $input = '<div class="sg-action-input-container">';
			    $input .= '<textarea ' . $fieldClass . ' id="' . esc_attr( $id ) .'" name="' . esc_attr( $name ) .'">' . wp_kses_post( $value ) . '</textarea>';
			    $input .= '</div>';
			    if ( $field['desc'] ) {
				    $input .= '<span class="description">' . esc_html( $field['desc'] ) . '</span>';
			    }
			    printf( $html_field, $label . $input );
			    break;
            case 'checkbox':
	            $input = '<div class="sg-action-input-container">';
                $input .= '<div class="checkbox-container widefat">';
	            $input .= '<input ' . checked( $value, '1', false ) . ' ' . $fieldClass . ' type="' . esc_attr( $field['type'] ) . '" value="1" id="' . esc_attr( $id ) .'" name="' . esc_attr( $name ) .'"/>';
                if ( $field['desc'] ) {
                    $input .= '<span class="description">' . esc_html( $field['desc'] ) . '</span>';
                }
	            $input .= '</div>';
	            $input .= '</div>';
	            printf( $html_field, $label . $input );
	            break;
		    case 'multioption':
			    $input = '<div class="sg-action-input-container">';
			    $input .= '<div class="sg-multioption-container widefat">';
			    $input .= '<div class="sg-multioption-options-container" id="' . esc_attr( $id ) . '">';

		        if ( $value && is_array( $value ) ) {
		            foreach ( $value as $index => $val ) {
		                if ( '' === $val ) {
		                    continue;
                        }
		                $attr_name = $name . '[]';
		                $attr_id   = $id . '_' . $index;
			            $input .= '<div class="sg-multioption-input" data-index="' . esc_attr( $index ) . '"><input ' . $fieldClass . ' type="text" value="' . esc_attr( $val ) . '" id="' . esc_attr( $attr_id ) .'" name="' . esc_attr( $attr_name ) .'"/><button type="button" class="button button-secondary button-small sg-multioption-delete">X</button></div>';
		            }
			    }

			    $input .= '</div>';

			    $input .= '<button type="button" class="button sg-button sg-multioption-button" data-template="multioption-input" data-name="' . esc_attr( $name ) . '" data-id="' . esc_attr( $id ) . '">' . __( 'Add', 'giveasap' ) . '</button>';
			    $input .= '</div>';
			    $input .= '</div>';
			    ob_start();

			    ?>
                <script type="text/template" id="tmpl-multioption-input">
                   <?php echo '<div class="sg-multioption-input" data-index="{{ data.index }}"><input ' . $fieldClass . ' type="text" value="" id="{{ data.id }}_{{ data.index }}" name="{{ data.name }}[]"/><button type="button" class="button button-secondary button-small sg-multioption-delete">X</button></div>'; ?>
                </script>
                <?php

			    $this->option_templates['multioption-input'] = ob_get_clean();


			    printf( $html_field, $label . $input );
			    break;
            case 'select_search':
                if ( ! $fieldClass ) {
                    $fieldClass = 'class="sg-select-search"';
                } else {
                    $fieldClass = str_replace( 'class="', 'class="sg-select-search ', $fieldClass );
                }
	            $input = '<div class="sg-action-input-container">';
	            $input .= '<div class="sg-select-search-dropdown widefat">';
                $input .= '<select data-action="' . ( isset( $field['action'] ) ? $field['action'] : '' ) . '" ' . $fieldClass . ' name="' . esc_attr( $name ) .'" id="' . esc_attr( $id ) .'" >';
	            if ( $value ) {
	                if ( is_array( $value ) ) {
			            foreach ( $value as $index => $val ) {

				            if ( '' === $val ) {
					            continue;
				            }
				            if ( isset( $field['function_for_option'] ) ) {
                                $option = call_user_func( $field['function_for_option'], $val );
				            } else {
                                $option = $val;
				            }
				            $input .= '<option value="' . $val . '">' . $option . '</option>';
			            }
		            } else {
		                if ( isset( $field['function_for_option'] ) ) {
			                $option = call_user_func( $field['function_for_option'], $value );
		                } else {
			                $option = $value;
		                }
		                $input .= '<option value="' . $value . '">' . $option . '</option>';
	                }
	            }
	            $input .= '</select>';
	            $input .= '</div>';
	            $input .= '</div>';
	            printf( $html_field, $label . $input );
	            break;
            default:
                do_action( 'sg_extra_action_admin_field_' . $field['type'], $index, $field, $admin_data );
                break;
        }
    }

	/**
     * Display the action attributes.
     *
	 * @return string
	 */
    public function action_attributes() {
        $atts = $this->get_action_attributes();
        $html = '';
        if ( $atts ) {
            foreach ( $atts as $attribute => $value ) {
                $html .= 'data-' . $attribute . '="' . esc_attr( $value ) . '" ';
            }
        }
        return $html;
    }

	/**
     * Action Entries HTML
     *
	 * @return string
	 */
    public function action_entries() {
        $entries = $this->get_action_entries();
        $html    = '<span class="sg-extra-action-entries">' . $entries . '</span>';

        return apply_filters( 'sg_extra_action_entries_html', $html, $entries, $this );
    }

	/**
     * Returns the complete mark.
	 * @return string
	 */
    public function complete_mark() {
	    $html = '<span class="sg-extra-action-entries"><span class="fal fa-check"></span></span>';
	    return apply_filters( 'sg_extra_action_complete_mark_html', $html, $this );
    }

	/**
     * Perform a specific task for the validation action.
     *
	 * @param array $action An array ot from DB, in most cases, empty on validation.
	 *
	 * @return array|WP_Error
	 */
    public function validate_action( $action, $data = array() ) {
        return array();
    }

	/**
	 * Perform a specific task for the completing action.
	 *
	 * @param array $action An array ot from DB, in some cases, filled.
     * @param array $data   An array given from the front end.
	 *
	 * @return array|WP_Error
	 */
	public function complete_action( $action, $data = array() ) {
		return array();
	}

	/**
     * Validate the instance.
     *
	 * @param $instance_id
	 * @param $subscriber_id
	 */
    public function validate( $instance_id, $subscriber_id, $data ) {
	    $subscriber = sg_get_subscriber( $subscriber_id );

	    if ( ! $subscriber ) {
	        return new WP_Error( 'no-subscriber', __( 'Subscriber not found.', 'giveasap' ) );
        }

        $this->set_subscriber_id( $subscriber_id );
        $this->set_instance_id( $instance_id );
        $subscriber_data = $subscriber->get_data();
        $giveaway_id     = $subscriber_data['post_id'];
	    $this->set_giveaway_id( $giveaway_id );

        if ( ! $this->is_action_instance_valid( $giveaway_id ) ) {
            return new WP_Error( 'no-valid-action', __( 'The Action and the Instance are not matching.', 'giveasap' ) );
        }

	    $this->set_admin_data_from_giveaway($giveaway_id);

        if ( $this->get_mandatory() > 0 ) {
            $completed_actions = sg_get_public_completed_actions_for_subscriber( $subscriber_id );
            if ( count( $completed_actions ) < $this->get_mandatory() ) {
	            $unlock_message = _n_noop( 'You need to complete %s action in total to submit it', 'You need to complete %s actions in total to submit it', 'giveasap' );

	            $error = sprintf( translate_nooped_plural( $unlock_message, $this->get_mandatory(), 'giveasap' ), $this->get_mandatory() );

	            return new WP_Error( 'no-mandatory-actions', $error );
            }
        }

        $action_db = $this->get_action_from_db();

	    $complete = $this->validate_action( $action_db, $data );

	    if ( is_wp_error( $complete ) ) {
		    return $complete;
	    }

        if ( ! $action_db ) {
            $this->create_action( 'valid', $giveaway_id, $complete );
            return true;
        }

        if ( 'invalid' === $action_db['status'] ) {
            return new WP_Error( 'invalid-action', __( 'Something went wrong with this action before.', 'giveasap' ) );
        }

	    return true;
    }

	/**
     * This function is used when completing the action.
	 * @return bool
	 */
    public function needs_validation() {
        return true;
    }

	/**
     * Check if the Action instance is valid for the provided giveaway.
     *
	 * @param $giveaway_id
     *
     * @return bool
	 */
    public function is_action_instance_valid( $giveaway_id ) {
        $actions = sg_get_extra_actions( $giveaway_id );

        if ( ! $actions ) {
            return false;
        }

        $instance_id = $this->get_instance_id();

        if ( ! $instance_id ) {
            return false;
        }

        foreach ( $actions as $action ) {
            if ( $this->get_slug() !== $action['action'] ) {
                continue;
            }

            if ( absint( $action['instance_id'] ) === absint( $instance_id ) ) {
                return true;
            }
        }

        return false;
    }

	/**
     * Has Action Button
     *
	 * @return bool
	 */
    public function has_action_button() {
        return $this->has_action_button;
    }

	/**
     * Return if the action can be completed.
     *
	 * @return bool
	 */
    public function can_complete() {
        $can_complete = true;
        $data         = $this->get_data();

	    if ( $this->needs_validation() && ( ! $data || 'invalid' === $data['status'] ) ) {
		    $can_complete = false;
        }

        return apply_filters( 'sg_extra_action_can_complete', $can_complete, $this );
    }

	/**
     * Return if the current action has completed or not.
     *
	 * @return bool
	 */
    public function is_completed() {
	    $data = $this->get_data();
        $ret  = true;

	    if ( ! $data ) {
	        $ret = false;
        }

        // Invalid status is done through the admin area.
        $is_completed_statuses = apply_filters( 'sg_extra_action_completed_statuses', array( 'completed', 'invalid' ) );

        if ( $ret && ! in_array( $data['status'], $is_completed_statuses ) ) {
	        $ret = false;
        }

        return apply_filters( 'sg_extra_action_is_completed', $ret, $this );
    }

	/**
     * Return if this action is only to be used through code.
	 * @return bool
	 */
    public function is_internal_only() {
        return $this->internal_only;
    }

	/**
     * Create the Action.
     *
	 * @param string $status
	 * @param int    $giveaway_id
     * @param array $data
	 */
    public function create_action( $status = 'invalid', $giveaway_id = 0, $data = array() ) {
        global $wpdb;

        if ( ! is_array( $data ) ) {
            $data = (array) $data;
         }

        // Let's build the data that is saved in the db.
        if ( $giveaway_id && $this->get_instance_id() >= 0 ) {
	        $actions = sg_get_extra_actions( $giveaway_id );
	        if ( $actions ) {
	            foreach ( $actions as $action ) {
	                if ( absint( $this->get_instance_id() ) === absint( $action['instance_id'] ) ) {
	                    $this->set_admin_data( $action );
	                    $data = wp_parse_args( $action, $data );
                    }
                }
            }
        }

	    $ret = $wpdb->insert(
                $wpdb->giveasap_actions,
                array(
                    'subscriber_id' => $this->get_subscriber_id(),
                    'giveaway_id'   => $giveaway_id,
                    'action'        => $this->get_slug(),
                    'instance'      => $this->get_instance_id(),
                    'status'        => $status,
                    'entries'       => $this->get_action_entries(),
                    'data'          => maybe_serialize( $data ),
                    'datetime'      => current_time( 'mysql' ),
                )
        );

        return false !== $ret ? true : false;
    }

	/**
	 * Update the status
	 * @param $status
	 * @param $id
	 */
	public function update_status( $status, $id, $data = array() ) {
		global $wpdb;

		$update_data = array(
            'status' => $status,
        );

		$update_format = array(
		        '%s',
        );

		if ( $data ) {
		    $update_data['data'] = maybe_serialize( $data );
		    $update_format[] = '%s';
		}
		$ret = $wpdb->update(
			$wpdb->giveasap_actions,
			array(
				'status' => $status
			),
            array(
                'id' => $id
            ),
            array( '%s' ),
            array( '%d' )
		);

		return false !== $ret ? true : false;
	}

	/**
     * Validate Admin Data.
     *
	 * @param $admin_data
	 */
	public function validate_admin_data() {

	    $admin_data = $this->get_admin_data();

	    if ( ! isset( $admin_data['title'] ) || '' === $admin_data['title'] ) {
	        $this->admin_errors[] = $this->get_title() . ': ' . __( 'No Extra Action Title. Please enter one.', 'giveasap' );
        }

	    $fields = $this->get_fields();

	    foreach ( $fields as $field ) {
            if ( isset( $field['required'] ) && $field['required']
                 && ( ! isset( $admin_data[ $field['id'] ] ) || ! $admin_data[ $field['id'] ] ) ) {
	            $this->admin_errors[] = $this->get_title() . ': ' . sprintf( __( 'Field %s is required', 'giveasap' ), $field['label'] );
            }

            if ( isset( $field['validate'] ) && $field['validate'] && is_callable( $field['validate'] ) ) {
                $errors = call_user_func_array( $field['validate'], array( $field, $admin_data ) );
                if ( $errors ) {
                    if ( is_array( $errors ) ) {
                        $this->admin_errors = array_merge( $this->admin_errors, $errors );
                    } else {
                        $this->admin_errors[] = $errors;
                    }
                }
            }
        }
    }

	/**
	 * This is the value that we will show on the Entries table.
	 */
	public function prepare_value_for_entries_table( $row ) {
	    if ( $row ) {
	        $this->set_subscriber_id( $row['subscriber_id'] );
		    $this->set_admin_data( maybe_unserialize( $row['data'] ) );
	        $this->set_instance_id( $row['instance'] );
        }
	}

	/**
     * Return if locked.
     *
	 * @return bool
	 */
	public function is_locked() {
	    return $this->get_locked() === true;
	}

	/******************
	 * Getters
	 ******************/

	/**
     * Return the entries for the action.
     *
	 * @return integer
	 */
	public function get_action_entries() {
	    return apply_filters( 'sg_extra_action_entries', $this->entries, $this );
    }

	/**
     * Get action attributes.
     *
	 * @return array
	 */
	public function get_action_attributes() {
	    $data = $this->get_admin_data();
	    $atts = array(
            'instance' => $data['instance_id'],
            'action'   => $this->get_slug(),
            'mandatory' => $data['mandatory'] ?: 0
        );
	    return apply_filters( 'sg_extra_action_get_attributes', $atts, $this );
    }

	/**
	 * Get Fields
	 *
	 * @return array
	 */
	public function get_fields() {
		if ( $this->has_action_button ) {
		    $field_keys = wp_list_pluck( $this->fields, 'id' );
		    if ( ! in_array( 'button_text', $field_keys ) ) {
			    $this->fields[] = array(
				    'id'    => 'button_text',
				    'label' => __( 'Button text', 'giveasap' )
			    );
		    }
        }

		$this->fields['mandatory'] = array(
            'id'    => 'mandatory',
            'label' => __( 'Mandatory Actions', 'giveasap' ),
            'type'  => 'number',
            'desc'  => __( 'How many actions have to be completed before this is available? If it needs 2, make sure that 2 are available.', 'giveasap' ),
        );

		return apply_filters( 'sg_extra_action_admin_fields', $this->fields, $this );
	}

	/**
     * Get the admin form.
     *
	 * @param int $index
	 *
	 * @return string
	 */
	public function get_admin_form( $index = 0 ) {
	    ob_start();
	    $this->form_admin( $index );
	    return ob_get_clean();
    }

	public function get_icon() {
		return '<span class="sg-action-icon"><span class="' . $this->icon . '"></span></span>';
	}

	/**
	 * Return the Action Slug
	 *
	 * @return string
	 */
	public function get_slug() {
		return $this->slug;
	}

	/**
	 * Return the instance id.
	 * @return integer
	 */
	public function get_instance_id() {
		return $this->instance_id;
	}

	/**
	 * Return the giveaway id.
	 * @return integer
	 */
	public function get_giveaway_id() {
		return $this->giveaway_id;
	}

	/**
	 * Return the title.
	 *
	 * @return string
	 */
	public function get_title() {
		return $this->title;
	}

	/**
	 * Return the description.
	 *
	 * @return string
	 */
	public function get_description() {
		return $this->description;
	}

	/**
	 * Return the Category.
	 *
	 * @return string
	 */
	public function get_category() {
		return $this->category;
	}

	/**
	 * Get data
	 */
	public function get_data() {
	    if ( null === $this->data ) {
	        $data = $this->get_action_from_db();
	        if ( ! $data ) {
	            $data = array();
            } elseif ( is_array( $data ) ) {
	            $data = array_map( 'maybe_unserialize', $data );
            }
            $this->data = $data;
        }
        return $this->data;
    }

	/**
	 * Get admin data
	 */
	public function get_admin_data() {
	    return wp_parse_args(
	            $this->admin_data,
                array(
                    'title'       => '',
                    'instance_id' => '',
                    'button_text' => __( 'Do it', 'giveasap' ),
                )
        );
	}

	/**
	 * Get the action from DB.
     *
     * @return bool|array
	 */
	public function get_action_from_db() {
	    global $wpdb;

        if ( ! $this->get_subscriber_id() ) {
            return false;
        }

        if ( ! $this->get_instance_id() ) {
            return false;
        }

        $action = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . $wpdb->giveasap_actions . ' WHERE action=%s AND subscriber_id=%d AND instance=%d ORDER BY datetime DESC', $this->get_slug(), $this->get_subscriber_id(), $this->get_instance_id() ), ARRAY_A );

        if ( ! $action ) {
            return false;
        }

		return apply_filters( 'sg_extra_action_from_db', $action, $this );
	}

	/**
	 * Get the subscriber ID.
	 *
	 * @return int
	 */
	public function get_subscriber_id() {
		return $this->subscriber_id;
	}

	/**
	 * This is the value that we will show on the Entries table.
	 */
	public function get_value_for_entries_table( $data ) {
	    return '';
    }

	/**
     * Get Locked
     *
	 * @return bool
	 */
    public function get_locked() {
	    return $this->locked;
    }

	/**
     * Get Mandatory
     *
	 * @return int
	 */
    public function get_mandatory() {
        $data = $this->get_admin_data();
        return isset( $data['mandatory'] ) ? absint( $data['mandatory'] ) : 0;
    }

	/******************
	 * Setters
	 ******************/

	/**
	 * Set the entries.
	 *
	 * @param integer $entries
	 */
	public function set_entries( $entries ) {
		$this->entries = $entries;
	}

	/**
	 * Set the title.
	 *
	 * @param $title
	 */
	public function set_title( $title ) {
		$this->title = $title;
	}

	/**
	 * Set the instance ID.
	 *
	 * @param $id
	 */
	public function set_instance_id( $id ) {
		$this->instance_id = $id;
	}

	/**
	 * Set the Giveaway ID.
	 *
	 * @param $id
	 */
	public function set_giveaway_id( $id ) {
		$this->giveaway_id = $id;
	}

	/**
	 * Set admin data
	 */
	public function set_admin_data( $data ) {
	    $this->instance_id = isset( $data['instance_id'] ) ? absint( $data['instance_id'] ) : 0;
		$this->admin_data = $data;
	}

	/**
	 * @param $giveaway_id
	 */
	public function set_admin_data_from_giveaway( $giveaway_id ) {
		if ( $giveaway_id ) {
			$actions = sg_get_extra_actions( $giveaway_id );
			if ( $actions ) {
				foreach ( $actions as $action ) {
					if ( absint( $this->get_instance_id() ) === absint( $action['instance_id'] ) ) {
						$this->set_admin_data( $action );
						return true;
					}
				}
			}
		}
		return false;
    }

	/**
     * Set the subscriber ID.
     *
	 * @param $id
	 */
	public function set_subscriber_id( $id ) {
	    $this->subscriber_id = absint( $id );
    }

	/**
	 * @param bool $locked
	 */
    public function set_locked( $locked = true ) {
	    $this->locked = $locked;
    }
}