<?php

namespace WpieFw\Settings;

use WpieFw\Helpers\WpieSettingsHelper;
use WpieFw\Helpers\WpieMiscHelper;

if( ! defined( 'ABSPATH' ) ) exit;

final class WpieSettingsValidator
{
	const SETT_WARN_IS_NOT_NUM = 'is_not_numeric';
	const SETT_WARN_IS_NOT_COLOR = 'is_not_color';
	const SETT_WARN_IS_ZERO = 'is_zero';
	const SETT_WARN_IS_FLOAT = 'is_float';
	const SETT_WARN_IS_NOT_FLOAT = 'is_not_float';
	const SETT_WARN_NO_OPTION = 'no_option';

	/**
	 * Flag if warnings are present
	 *
	 * @var bool
	 */
	public $hasWarnings = false;

	/**
	 * All warning messages for form validation
	 *
	 * @var array
	 */
	private $warnings = [];

	/**
	 * Constructor
	 */
	public function __construct()
	{
		$this->setWarnings();
	}

	/**
	 * Validate given settings data
	 *
	 * @param array $data   the data submitted (passed by reference)
	 * @param array $fields the settings fields
	 *
	 * @return array with warnings
	 */
	public function validate( array &$data, array $fields )
	{
		$warnings = [];

		foreach ( $fields as $name => $field ) {
			$attributes = WpieSettingsHelper::getFieldAttr( $field );
			$type = ( isset( $attributes['type'] ) ) ? $attributes['type'] : '';
			$title = $field['title'];
			$isset = ( isset( $data[$name] ) );
			$value = ( $isset ) ? $data[$name] : null;

			if( is_string( $value ) ) {
				$value = trim( $value );
			}

			switch ( $type ) {
				case 'numeric':
					if( $isset && !is_numeric( $value ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_NOT_NUM ), $title );
					}
					break;
				case 'numeric_abs':
					if( $isset && !is_numeric( $value ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_NOT_NUM ), $title );
					}
					if( $isset && ( false !== strpos( $value, '.' ) && false !== strpos( $value, ',' ) ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_FLOAT ), $title );
					} elseif( $isset && ( '0' === $value || 0 > (int) $value ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_ZERO ), $title );
					}
					break;
				case 'factor':
					if( $isset && !is_numeric( $value ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_NOT_NUM ), $title );
					}
					if( $isset && 1 !== (int) $value && ( false === strpos( $value, '.' ) && false === strpos( $value, ',' ) ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_NOT_FLOAT ), $title . ' => ' . $value );
					} elseif( $isset && ( '0' === $value || 0 > (int) $value ) ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_ZERO ), $title );
					}
					break;
				case 'color':
					if( $isset ) {
						if ( WpieMiscHelper::isValidHexColor( "#$value") && false === strpos( $value , '#') ) {
							$data[$name] = "#$value";
							continue 2;
						}
						if( false === WpieMiscHelper::isValidHexColor( $value ) ) {
							$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_IS_NOT_COLOR ), $title );
						}
					}
					break;
				case 'force_option':
					if( $isset && '-1' === $value ) {
						$warnings[$name] = sprintf( $this->getWarning( self::SETT_WARN_NO_OPTION ), $title );
					}
					break;
				case 'allowed_tags':
					if( isset( $data[$name] ) && function_exists( 'wp_kses_allowed_html' ) ) {
						$data[$name] = wp_kses( $value, wp_kses_allowed_html( 'post' ), [ 'http', 'https', 'mailto', 'tel' ] );
					}
					break;
			}
		}

		return $warnings;
	}

	/**
	 * Set Warning messages
	 *
	 * @access private
	 */
	private function setWarnings()
	{
		$this->warnings[self::SETT_WARN_IS_NOT_NUM] 	= __( 'Please enter a numeric value for "%s"', 'weepie' );
		$this->warnings[self::SETT_WARN_IS_NOT_COLOR] 	= __( 'Please enter a valid color for "%s" in the format #XXX or #XXXXXX', 'weepie' );
		$this->warnings[self::SETT_WARN_IS_ZERO] 		= __( 'Please enter a number greater then zero for "%s"', 'weepie' );
		$this->warnings[self::SETT_WARN_IS_FLOAT] 		= __( 'Please enter an integer number like 5,  20 or 100 for "%s"', 'weepie' );
		$this->warnings[self::SETT_WARN_IS_NOT_FLOAT] 	= __( 'Please enter a numeric value between zero and 1 like 0.2,  0.65 or 0.99 for "%s"', 'weepie' );
		$this->warnings[self::SETT_WARN_NO_OPTION] 		= __( 'Please select an option for "%s"', 'weepie' );
	}

	/**
	 * Get Warning messages
	 *
	 * @access private
	 *
	 * @return array
	 */
	private function getWarnings()
	{
		return $this->warnings;
	}

	/**
	 * Get Warning message
	 *
	 * @access private
	 *
	 * @param string $key
	 *
	 * @return string
	 */
	private function getWarning( $key = '' )
	{
		if( isset( $this->warnings[$key] ) ) {
			return $this->warnings[$key];
		} else {
			return '';
		}
	}

}