<?php
/**
 * Template Variable Model
 *
 * @package SEOvaultSEO
 */

namespace SEOvaultSEO\ReplaceVariables;

defined( 'ABSPATH' ) || exit;

/**
 * Represents a single replaceable variable.
 */
class Variable {

	/**
	 * Required properties for a valid variable.
	 *
	 * @var array
	 */
	private static $required = array( 'name', 'description', 'variable' );

	/**
	 * Unique id.
	 *
	 * @var string
	 */
	protected $id;

	/**
	 * Display name.
	 *
	 * @var string
	 */
	protected $name;

	/**
	 * Description shown in the admin picker.
	 *
	 * @var string
	 */
	protected $description;

	/**
	 * The variable token without percent signs, e.g. "post_title".
	 *
	 * @var string
	 */
	protected $variable;

	/**
	 * Example value for admin preview.
	 *
	 * @var string
	 */
	protected $example;

	/**
	 * Callback that returns the replacement value.
	 *
	 * @var callable|null
	 */
	protected $callback;

	/**
	 * Whether the variable can be cached.
	 *
	 * @var bool
	 */
	protected $cacheable = true;

	/**
	 * Create a Variable instance from an array definition.
	 *
	 * @param string $id   Unique id.
	 * @param array  $args Definition array (name, description, variable, example, nocache).
	 * @return Variable
	 */
	public static function from( $id, $args ) {
		if ( empty( $id ) ) {
			return new self();
		}

		$variable          = new self();
		$variable->id      = $id;
		$variable->example = isset( $args['example'] ) ? $args['example'] : '';

		foreach ( self::$required as $key ) {
			if ( ! isset( $args[ $key ] ) ) {
				return new self();
			}
			$variable->$key = $args[ $key ];
		}

		if ( isset( $args['nocache'] ) && $args['nocache'] ) {
			$variable->cacheable = false;
		}

		return $variable;
	}

	/**
	 * Get the id.
	 *
	 * @return string
	 */
	public function get_id() {
		return $this->id;
	}

	/**
	 * Get the name.
	 *
	 * @return string
	 */
	public function get_name() {
		return $this->name;
	}

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

	/**
	 * Get the variable token.
	 *
	 * @return string
	 */
	public function get_variable() {
		return $this->variable;
	}

	/**
	 * Get the example value.
	 *
	 * @return string
	 */
	public function get_example() {
		return $this->example;
	}

	/**
	 * Set the callback.
	 *
	 * @param callable $callback Callback that returns the replacement value.
	 * @return void
	 */
	public function set_callback( $callback ) {
		$this->callback = $callback;
	}

	/**
	 * Run the callback to get the replacement value.
	 *
	 * @param mixed  $var_args Arguments passed inside the variable, e.g. date(F jS, Y).
	 * @param object $args    Context object (post, term, etc.).
	 * @return mixed
	 */
	public function run_callback( $var_args, $args = null ) {
		if ( ! empty( $this->callback ) ) {
			return call_user_func( $this->callback, $var_args, $args );
		}

		return apply_filters( 'seovaultseo/vars/' . $this->get_id(), '', $var_args, $args );
	}

	/**
	 * Convert to array for JSON output.
	 *
	 * @return array
	 */
	public function to_array() {
		$arr = array();
		foreach ( array( 'name', 'description', 'variable', 'example' ) as $key ) {
			$arr[ $key ] = isset( $this->$key ) ? $this->$key : '';
		}

		return $arr;
	}

	/**
	 * Whether the variable is cacheable.
	 *
	 * @return bool
	 */
	public function is_cacheable() {
		return $this->cacheable;
	}
}
