<?php

if ( ! defined( 'ABSPATH' ) ) {
	return;
}

/**
 * A wrapper for all metaboxes.
 */
class GiveASAP_Metaboxes {

	/**
     * Array of all metaboxes to render.
     *
	 * @var array
	 */
	private $metaboxes = array();

	/**
	 * Get all metaboxes through hook if any and then register our metabox method.
	 */
	public function register() {
	    do_action( 'sg_metaboxes_before_register', $this );
		add_action( 'add_meta_boxes', array( $this, 'register_metabox' ) );
	}

	/**
	 * Register our main metabox.
	 */
	public function register_metabox() {
		add_meta_box( 'sg-metaboxes', __( 'Giveaway', 'giveasap' ), array(
			$this,
			'render'
		), 'giveasap', 'advanced', 'high' );
	}

	/**
	 * @param GiveASAP_Metabox $metabox
	 */
	public function add( GiveASAP_Metabox $metabox ) {
		$metabox->register = false;
		$this->metaboxes[ $metabox->settings_id ] = $metabox;
	}

	/**
	 * Prepare the metaboxes by filtering them.
	 */
	private function prepare() {
		$this->metaboxes = apply_filters( 'sg_metaboxes', $this->metaboxes );
	}

	/**
     * Render our metabox.
     *
	 * @param $post
	 */
	public function render( $post ) {
		$this->prepare();
		if ( $this->metaboxes ) {
			?>
			<div class="sg-metaboxes">
				<ul>
					<?php
					$active = true;
					foreach ( $this->metaboxes as $slug => $metabox ) {
						$icon = '';
						if ( $metabox->icon ) {
							$icon = '<span class="sg-metabox-icon">' . $metabox->icon . '</span>';
						}
						?>
						<li class="sg-metabox sg-<?php echo $slug; echo $active ? ' active' : ''; ?>"><a href="#sg-metabox-fields-<?php echo $slug; ?>"><?php echo $icon . $metabox->get_title(); ?></a></li>
						<?php
						$active = false;
					}
					?>
				</ul>
				<div class="sg-metaboxes-fields">
					<?php
					$hidden = false;
					foreach ( $this->metaboxes as $slug => $metabox ) {
						?>
						<div id="sg-metabox-fields-<?php echo $slug; ?>" class="sg-metabox-fields sg-<?php echo $slug; echo $hidden ? ' hidden' : ''; ?> "><?php $metabox->render( $post ); ?></div>
						<?php
						$hidden = true;
					}
					?>
				</div>
			</div>
			<?php
		}
	}
}

/**
 * Class for making Metaboxes
 */
class GiveASAP_Metabox extends GiveASAP_WordPressSettings {

	/**
	 * Icon
	 * @var string
	 */
	public $icon = '';

	/**
	 * Metabox Title
	 */
	protected $title = '';

	/**
	 * Metabox ID
	 */
	protected $slug = '';

	/**
	 * Array of post types for which we allow the metabox
	 */
	protected $post_types = array();

	/**
	 * Post ID used to save or retrieve the settings
	 */
	protected $post_id = 0;

	/**
	 * Metabox context
	 */
	protected $context = '';

	/**
	 * Should Register?
	 *
	 * @var bool
	 */
	public $register = true;

	/**
	 * Metabox priority
	 */
	protected $priority = '';

	/**
     * Collecting errors and displaying them.
     *
	 * @var array
	 */
	protected $errors = array();

	public function __construct( $title, $slug, $post_types = array( 'post' ), $context = 'advanced', $priority = 'default', $icon = '<i class="fal fa-cog"></i>' ) {

		if ( $slug == '' || $context == '' || $priority == '' ) {
			return;
		}

		if ( $title == '' ) {
			$this->title = ucfirst( $slug );
		}

		if ( empty( $post_types ) ) {
			return;
		}

		$this->title       = $title;
		$this->slug        = $slug;
		$this->post_types  = $post_types;
		$this->settings_id = $this->slug;
		$this->context     = $context;
		$this->priority    = $priority;
		$this->icon        = $icon;

		do_action( 'giveasap_metabox_object_' . $this->settings_id, $this );

		add_action( 'add_meta_boxes', array( $this, 'register' ) );
		add_action( 'save_post', array( $this, 'save_meta_settings' ) );
	}

	/**
     * Get post ID.
     *
	 * @return int
	 */
	public function get_post_id() {
		return $this->post_id;
	}

	/**
     * Set the Post ID.
     *
	 * @param $id
	 */
	public function set_post_id( $id ) {
	    $this->post_id = $id;
    }

	public function register( $post_type ) {
		if ( $this->register && in_array( $post_type, $this->post_types ) ) {
			add_meta_box( $this->slug, $this->title, array(
				$this,
				'render'
			), $post_type, $this->context, $this->priority );
		}
	}

	public function get_title() {
		return $this->title;
	}

	public function render( $post ) {
		$this->post_id = $post->ID;

		wp_nonce_field( 'metabox_' . $this->slug, 'metabox_' . $this->slug . '_nonce' );

		$this->get_all_fields();

		$this->init_settings();

		if ( $this->errors ) {
		    for( $i = 0; $i < count( $this->errors ); $i++ ) {
		        $error = $this->errors[ $i ];
		        echo '<div class="error"><p>' . $error . '</p></div>';
            }
        }
		do_action( 'gasap_metabox_' . $this->slug . '_before_fields' );
		echo '<table class="form-table">';
		$this->render_fields( 'general' );
		echo '</table>';


	}

	/**
	 * Get the settings from the database
	 *
	 * @return void
	 */
	public function init_settings() {

		$post_id        = $this->post_id;
		$this->settings = get_post_meta( $post_id, $this->settings_id, true );

		if ( ! $this->settings ) {
			$this->settings = array();
		}

		if ( ! is_array( $this->settings ) ) {
		    $this->settings = maybe_unserialize( $this->settings );
        }

		foreach ( $this->fields as $tab_key => $tab ) {

			foreach ( $tab as $name => $field ) {
                if ( isset( $field['single'] ) && true === $field['single'] ) {
	                $this->fields[ $tab_key ][ $name ]['default'] = get_post_meta( $post_id, $name, true );
                } elseif ( isset( $this->settings[ $name ] ) ) {
					$this->fields[ $tab_key ][ $name ]['default'] = $this->settings[ $name ];
				}

			}
		}
	}

	public function save_meta_settings( $post_id ) {
		if ( ! in_array( get_post_type( $post_id ), $this->post_types ) ) {
			return $post_id;
		}
		// Check if our nonce is set.
		if ( ! isset( $_POST[ 'metabox_' . $this->slug . '_nonce' ] ) ) {
			return $post_id;
		}

		$nonce = $_POST[ 'metabox_' . $this->slug . '_nonce' ];

		// Verify that the nonce is valid.
		if ( ! wp_verify_nonce( $nonce, 'metabox_' . $this->slug ) ) {
			return $post_id;
		}

		/*
		* If this is an autosave, our form has not been submitted,
		* so we don't want to do anything.
		*/
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return $post_id;
		}

		// Check the user's permissions.
		if ( 'page' == $_POST['post_type'] ) {
			if ( ! current_user_can( 'edit_page', $post_id ) ) {
				return $post_id;
			}
		} else {
			if ( ! current_user_can( 'edit_post', $post_id ) ) {
				return $post_id;
			}
		}

		$this->post_id = $post_id;

		$this->get_all_fields();
		$this->save_settings();

		do_action( 'giveasap_metabox_' . $this->settings_id . '_saved' );
	}

	/**
	 * Save settings from POST
	 *
	 * @return void
	 */
	public function save_settings() {
		$this->posted_data = $_POST;

		if ( empty( $this->settings ) ) {
			$this->init_settings();
		}

		if ( ! is_array( $this->settings ) ) {
			$this->settings = array();
		}

		$no_single = false;

		foreach ( $this->fields as $tab => $tab_data ) {
			foreach ( $tab_data as $name => $field ) {

				if ( 'custom' === $field['type'] ) {
					if ( isset( $field['validate'] ) && '' !== $field['validate'] ) {
						$func = $field['validate'];
						if ( is_callable( $func ) ) {
							// Passes the value to the function
							$this->settings[ $name ] = call_user_func_array( $func, array( $this->posted_data[ $name ], $this ) );
						} else {
							$this->settings[ $name ] = $this->posted_data[ $name ];
						}
					} else {
						$this->settings[ $name ] = $this->posted_data[ $name ];
					}
				} else {
					$this->settings[ $name ] = $this->{'validate_' . $field['type']}( $name );
				}

				if ( isset( $field['single'] ) && true === $field['single'] ) {
				    update_post_meta( $this->post_id, $name, $this->settings[ $name ] );
                    unset( $this->settings[ $name ] );
                } else {
				    $no_single = true;
                }

			}
		}

		// If we have no single fields, let's save them. Otherwise, don't.
		if ( $no_single ) {
			update_post_meta( $this->post_id, $this->settings_id, $this->settings );
		}
	}

	/**
     * Adding the error message;
	 * @param string $error Error message.
	 */
	public function add_error( $error ) {
	    $this->errors[] = $error;
    }

}