<?php
/**
 * Html Schema Class
 *
 * @package errigal
 * @since 1.2.0
 */

namespace Errigal\Shared;

defined( 'ABSPATH' ) || exit;

use Errigal\Constant\{
	Errigal_Html_Attr as Html_Attr,
	Errigal_Html_Schema_Hook as Html_Schema_Hook,
	Errigal_Html_Tag as Html_Tag,
};
use Errigal\Shared\{
	Errigal_Utility as Utility,
	Errigal_Validator as Validator,
};

/**
 * This class is in charge of providing HTML schema functions.
 *
 * @since 1.2.0
 */
class Errigal_Html_Schema {
	/**
	 * Allowed HTML tags and attributes for body.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_BODY = array(
		Html_Tag::BODY => array(
			Html_Attr::CLASS_NAME => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for form.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_FORM = array(
		Html_Tag::FORM => array(
			Html_Attr::CLASS_NAME => true,
			Html_Attr::ACTION     => true,
			Html_Attr::METHOD     => true,
			Html_Attr::ROLE       => true,
			Html_Attr::ARIA_LABEL => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for head.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_HEAD = array(
		Html_Tag::HEAD => true,
	);

	/**
	 * Allowed HTML tags and attributes for html.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_HTML = array(
		Html_Tag::HTML => array(
			Html_Attr::LANG       => true,
			Html_Attr::DIR        => true,
			Html_Attr::CLASS_NAME => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for input.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_INPUT = array(
		Html_Tag::INPUT => array(
			Html_Attr::TYPE        => true,
			Html_Attr::ID          => true,
			Html_Attr::NAME        => true,
			Html_Attr::CLASS_NAME  => true,
			Html_Attr::REQUIRED    => true,
			Html_Attr::SPELLCHECK  => true,
			Html_Attr::SIZE        => true,
			Html_Attr::VALUE       => true,
			Html_Attr::PLACEHOLDER => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for link.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_LINK = array(
		Html_Tag::LINK => array(
			Html_Attr::REL         => true,
			Html_Attr::HREF        => true,
			Html_Attr::CROSSORIGIN => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for main.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_MAIN = array(
		Html_Tag::MAIN => array(
			Html_Attr::ID         => true,
			Html_Attr::CLASS_NAME => true,
			Html_Attr::ROLE       => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for meta.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_META = array(
		Html_Tag::META => array(
			Html_Attr::CHARSET => true,
			Html_Attr::NAME    => true,
			Html_Attr::CONTENT => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for svg.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_SVG = array(
		Html_Tag::PATH => array(
			Html_Attr::CLIP_RULE       => true,
			Html_Attr::D               => true,
			Html_Attr::FILL            => true,
			Html_Attr::FILL_RULE       => true,
			Html_Attr::STROKE          => true,
			Html_Attr::STROKE_LINECAP  => true,
			Html_Attr::STROKE_LINEJOIN => true,
			Html_Attr::STROKE_WIDTH    => true,
		),
		Html_Tag::RECT => array(
			Html_Attr::FILL         => true,
			Html_Attr::HEIGHT       => true,
			Html_Attr::RX           => true,
			Html_Attr::STROKE       => true,
			Html_Attr::STROKE_WIDTH => true,
			Html_Attr::WIDTH        => true,
			Html_Attr::X            => true,
			Html_Attr::Y            => true,
		),
		Html_Tag::SVG  => array(
			Html_Attr::ARIA_HIDDEN => true,
			Html_Attr::CLASS_NAME  => true,
			Html_Attr::FILL        => true,
			Html_Attr::HEIGHT      => true,
			Html_Attr::ROLE        => true,
			Html_Attr::VIEWBOX     => true,
			Html_Attr::WIDTH       => true,
			Html_Attr::XMLNS       => true,
		),
	);

	/**
	 * Allowed HTML tags and attributes for time.
	 *
	 * @since 1.2.0
	 *
	 * @var array
	 */
	private const ALLOWED_HTML_TIME = array(
		Html_Tag::TIME => array(
			Html_Attr::CLASS_NAME => true,
			Html_Attr::DATETIME   => true,
		),
	);

	/**
	 * Gets allowed HTML tags and attributes for body.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_body() {
		/**
		 * Filters allowed HTML body.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_body Associative array of allowed HTML tags and attributes for body.
		 */
		$allowed_html_body = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_BODY,
			self::ALLOWED_HTML_BODY
		);

		return Validator::has_array_key( $allowed_html_body, Html_Tag::BODY )
			? $allowed_html_body
			: self::ALLOWED_HTML_BODY;
	}

	/**
	 * Gets allowed HTML tags and attributes for form.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_form() {
		/**
		 * Filters allowed HTML form.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_form Associative array of allowed HTML tags and attributes for form.
		 */
		$allowed_html_form = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_FORM,
			self::ALLOWED_HTML_FORM
		);

		return Validator::has_array_key( $allowed_html_form, Html_Tag::FORM )
			? $allowed_html_form
			: self::ALLOWED_HTML_FORM;
	}

	/**
	 * Gets allowed HTML tags and attributes for head.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_head() {
		/**
		 * Filters allowed HTML head.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_head Associative array of allowed HTML tags and attributes for head.
		 */
		$allowed_html_head = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_HEAD,
			self::ALLOWED_HTML_HEAD
		);

		return Validator::has_array_key( $allowed_html_head, Html_Tag::HEAD )
			? $allowed_html_head
			: self::ALLOWED_HTML_HEAD;
	}

	/**
	 * Gets allowed HTML tags and attributes for html.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_html() {
		/**
		 * Filters allowed HTML html.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_html Associative array of allowed HTML tags and attributes for html.
		 */
		$allowed_html_html = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_HTML,
			self::ALLOWED_HTML_HTML
		);

		return Validator::has_array_key( $allowed_html_html, Html_Tag::HTML )
			? $allowed_html_html
			: self::ALLOWED_HTML_HTML;
	}

	/**
	 * Gets allowed HTML tags and attributes for input.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_input() {
		/**
		 * Filters allowed HTML input.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_input Associative array of allowed HTML tags and attributes for input.
		 */
		$allowed_html_input = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_INPUT,
			self::ALLOWED_HTML_INPUT
		);

		return Validator::has_array_key( $allowed_html_input, Html_Tag::INPUT )
			? $allowed_html_input
			: self::ALLOWED_HTML_INPUT;
	}

	/**
	 * Gets allowed HTML tags and attributes for link.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_link() {
		/**
		 * Filters allowed HTML link.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_link Associative array of allowed HTML tags and attributes for link.
		 */
		$allowed_html_link = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_LINK,
			self::ALLOWED_HTML_LINK
		);

		return Validator::has_array_key( $allowed_html_link, Html_Tag::LINK )
			? $allowed_html_link
			: self::ALLOWED_HTML_LINK;
	}

	/**
	 * Gets allowed HTML tags and attributes for main.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_main() {
		/**
		 * Filters allowed HTML main.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_main Associative array of allowed HTML tags and attributes for main.
		 */
		$allowed_html_main = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_MAIN,
			self::ALLOWED_HTML_MAIN
		);

		return Validator::has_array_key( $allowed_html_main, Html_Tag::MAIN )
			? $allowed_html_main
			: self::ALLOWED_HTML_MAIN;
	}

	/**
	 * Gets allowed HTML tags and attributes for meta.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_meta() {
		/**
		 * Filters allowed HTML meta.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_meta Associative array of allowed HTML tags and attributes for meta.
		 */
		$allowed_html_meta = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_META,
			self::ALLOWED_HTML_META
		);

		return Validator::has_array_key( $allowed_html_meta, Html_Tag::META )
			? $allowed_html_meta
			: self::ALLOWED_HTML_META;
	}

	/**
	 * Gets allowed HTML tags and attributes for post.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_post() {
		return wp_kses_allowed_html( 'post' );
	}

	/**
	 * Gets allowed HTML tags and attributes for post and SVG.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_post_svg() {
		return Utility::array_merge_deep(
			self::get_allowed_html_post(),
			self::get_allowed_html_svg(),
		);
	}

	/**
	 * Gets allowed HTML tags and attributes for svg.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_svg() {
		/**
		 * Filters allowed HTML svg.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_svg Associative array of allowed HTML tags and attributes for svg.
		 */
		$allowed_html_svg = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_SVG,
			self::ALLOWED_HTML_SVG
		);

		return Validator::has_array_key( $allowed_html_svg, Html_Tag::SVG )
			? $allowed_html_svg
			: self::ALLOWED_HTML_SVG;
	}

	/**
	 * Gets allowed HTML tags and attributes for time.
	 *
	 * @since 1.2.0
	 *
	 * @return array
	 */
	public static function get_allowed_html_time() {
		/**
		 * Filters allowed HTML time.
		 *
		 * @since 1.2.0
		 *
		 * @param array $allowed_html_time Associative array of allowed HTML tags and attributes for time.
		 */
		$allowed_html_time = apply_filters(
			Html_Schema_Hook::ALLOWED_HTML_TIME,
			self::ALLOWED_HTML_TIME
		);

		return Validator::has_array_key( $allowed_html_time, Html_Tag::TIME )
			? $allowed_html_time
			: self::ALLOWED_HTML_TIME;
	}
}
