<?php

/**
 * Validation class
 *
 * this class contain the methods that deals with data validation
 *
 *
 * LICENSE: Open source
 *
 * @category   general
 * @package    core system
 * @subpackage parent
 * @copyright  coderg
 * @license    http://coderg.com
 * @version    .01
 * @link       http://coderg.com
 * @since      2018
 */

class Validation{
    // Validation Array
    private $data;
    // The Form Data Like $_POST['']
    private $dataValue;
    // The Field Name  -> The Key Of $data Array Like ("username"=>array(),"pass"=>array())
    private $fieldName;
    // The Name That Will Be Using In Case Of Error
    private $errorName;
    // Error
    private $error = array();
    // If The Data Validation Is True Return Array To Be Send To The Model
    private $dataSuccess = array();
   // result
    private $result = array();
	
	// error language
	private $validationLang;
	// validation vars
	private $validationVars;
	// this var for get user rules as string 
	private $rules;
	// this var for get rules as array
	private $rules_Array = array();
	// this var for check if user want return all errors or firest error only
	private $continue_on_error;
    /**
     * __construct
     *
     * Set Data
     *
     * @param     (array) Data To Validate
     * @return    (non)
     *
     */
    public function __construct($data,$continue_on_error = FALSE) {
        $this->data = $data;
        $this->continue_on_error = $continue_on_error;
		$this->set_validation_error_lang();
		$this->validationVars = $this->get_validation_lang_vars();
    }
	
    /**
     * checkStatus
     *
     * Check The Data Rules
     * like required | string | number
     *
     * @param     $errorName (string)  The Name That Will Be Using In Case Of Error
     * @param     $val (unknown)  The User Data That Will Be Cheked
     * @param     $property (string)  The Key That Will Be Used For Check Like "required" "min-lenght"
     * @return    (Boolean) TRUE if The Data Is Ok , Error Otherwise
     *
     */
    private function checkStatus($errorName,$val,$property)
    {
		if($this->validationVars != FALSE)
		{
			extract($this->validationVars);
		}else{
			die("Please Check Language Config");
			exit;
		}
		
        switch(strtolower($property)):
           case "required":
             return ($this->checkNotNull($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_required);
           break;
           case (preg_match('/(lang)\[(.*)\]/', $property, $match) == TRUE):
             if($match[2] == "ar")
                return ($this->checkArString($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_only_arabic);
             else if($match[2] == "en")
                return ($this->checkEnString($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_only_english);
              else if($match[2] == "aren")
                return ($this->checkArEnString($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_only_arabic_english);
               else if($match[2] == "stringAndNumbers")
                return ($this->checkStringAndNumber($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_letters_numbers);
           break;
           case "number":
             return ($this->checkNumber($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_numbers);
           break;
           case (preg_match('/(max-length)\[(.*)\]/', $property, $match) == TRUE):
             return ($this->checkMaxLength($val,$match[2]))?TRUE:$this->result['error'][] = str_replace(array("{field}","{value}"),array($errorName,$match[2]),$field_max_length);
           break;
           case (preg_match('/(min-length)\[(.*)\]/', $property, $match) == TRUE):
             return ($this->checkMinLength($val,$match[2]))?TRUE:$this->result['error'][] = str_replace(array("{field}","{value}"),array($errorName,$match[2]),$field_min_length);
           break;
           case "email":
             return ($this->checkEmail($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_email);
           break;
           case "url":
             return ($this->checkUrl($val))?TRUE:$this->result['error'][] = str_replace("{field}",$errorName,$field_url);
           break;
           case (preg_match('/(match)\[(.*)\]/', $property, $match) == TRUE):
             return ($this->checkMatch($val,$match[2]))?TRUE:$this->result['error'][] = str_replace(array("{field1}","{field2}"),array($errorName,$match[2]),$field_match);
           break;
          case (preg_match('/(between)\[(.*)\]/', $property, $match) == TRUE):
             return ($this->checkBetween($val,$match[2]))?TRUE:$this->result['error'][] = str_replace(array("{field}","{value}"),array($errorName,$match[2]),$field_between);
           break;
          case "sha1_md5":
             return ($this->sha1_md5($val))?TRUE:$this->result['error'][] = $field_encrypt;
           break;
		default:
		  return NULL;
        endswitch;
    }
	/**
     * formValidate
     *
     *  Validate User Data
     * like required | string | number
     * @return    (Boolean) The Error Occurred During Validation
     *
     */
	public function formValidate()
    {
        foreach($this->data as $key=>$value)
		{
			// Check If The User Added The Value Key And errorName To His Array
			if(array_key_exists("value",$value) && array_key_exists("errorName",$value))
			{
				// set The Data Like Tha Value Of $_POST['username']
				  $this->dataValue = $value['value'];
				 // desired field Name in Case Of Success
				  $this->fieldName = $key;
				  // desired Error Name in Case Of Error
				  $this->errorName = $value['errorName'];
				 // check if develper set rules
				 if(array_key_exists("rules",$value))
				 {
					 $this->rules = $value['rules'];
					 // set rules as array
					 $this->set_rules_array();
					 foreach($this->rules_Array as $property)
					 {
						 $dataStatus = $this->checkStatus($this->errorName,$this->dataValue,$property);
							// if Error Happend When Check User Data Retrun FALSE
						  if($dataStatus !== TRUE && $dataStatus !== NULL)
							{
							  // if user want stop and return firest happend error
							    if($this->continue_on_error == FALSE)
							    {
								    return $this->get_result();
								    break 2; 
							     }
							 // if user add invalid validation attribute 
							}elseif($dataStatus == NULL){
							  
									die("Error : The Attribute ".$property." Not Found Please Check Validation Class");
									exit;
							// if data is ok  
							}else{
									if($property != "match")
									{
										if($property == "sha1_md5")
										{
										  $this->result["success"][$this->fieldName] = sha1(md5($this->dataValue));  
										}else{
										   // Set The Data If No Error Happend
										   $this->result["success"][$this->fieldName] = $this->dataValue; 
										}
									 }
							 }
				 		}
					// if user not add any rules add data to success array    
				   }else{
				       $this->result["success"][$this->fieldName] = $this->dataValue;
					   continue;
				   }
			 }
			 // If User Did Not Add The Value and errorName To His Array
			 else
			 {
				 $this->result['error'] = "Please Add The value Key And errorName Key To Your ".$key." Array";
				 return $this->get_result();
			 }
		}
        if(array_key_exists("error",$this->result))
		{
			// if there is success data remove it to return error
			if(array_key_exists("success",$this->result))
			{
				unset($this->result['success']);
			}
			return $this->get_result();
		}else{
			return $this->get_result();
		}
    }
	private function set_rules_array()
	{
		if(isset($this->rules) && !empty($this->rules))
		{
			// explode roule
			 $this->rules_Array = explode("|",$this->rules);
			return;
		}
		return NULL;
	}
    
	public function set_validation_error_lang()
	{
		// global validation lang from validation config
		global $templeteLang;
		$this->validationLang = strtolower($templeteLang);
	}
	
	public function get_validation_lang_vars()
	{
		if($this->validationLang == "session")
		{
			if(isset($_SESSION['lang']))
			{
				$errorLang = strtolower($_SESSION['lang']);
			}else{
				$errorLang = "en";
			}
			
		}else{
			$errorLang = $this->validationLang;
		}
		if(file_exists("app/langauge/validation/validation_".$errorLang.".php"))
		{
			require("app/langauge/validation/validation_".$errorLang.".php");
			return $error;
		}
		return FALSE;
	 }
	/*public function set_validation_error_vars()
	{
		$this->validationVars = $this->check_validation_lang();
	}*/
    /**
     *  get_result
     *
     *  get validation result
     * @param     (none)
     * @return (array) the result from validation
     *
     */
    public function get_result()
    {
		if(array_key_exists('error',$this->result) && $this->continue_on_error == FALSE)
		{
			return $this->result['error'][0];
		}else if(array_key_exists('error',$this->result) && $this->continue_on_error == TRUE)
		{
			return $this->result;
		}
        return $this->result;
    }

    /**
     *  checkEnString
     *
     *  check if variable contain only English letters And Spaces
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Only contain English letters And Spaces , false otherwise
     *
     */
 private function checkEnString($var)
  {
      $pattern = "/^([\sa-zA-Z])+$/";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkEnString
     *
     *  check if variable contain only English letters And Spaces
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Only contain Arabic letters And Spaces , false otherwise
     *
     */
 private function checkArString($var)
  {
      $pattern = "/^([\s\p{Arabic}])+$/u";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkArEnString
     *
     *  check if variable contain only English letters Or Arabic letters And Spaces
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Only contain English letters Or Arabic letters And Spaces , false otherwise
     *
     */
 private function checkArEnString($var)
  {
      $pattern = "/^([\s\p{Arabic}a-zA-Z])+$/u";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkNumber
     *
     *  check if variable contain only Numbers
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Only contain Numbers , false otherwise
     */
  private function checkNumber($var)
  {
      $pattern = "/^([\d])+$/";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkStringAndNumber
     *  check if The variable contain only Numbers oR English Letters Or Arabic Letters
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Only contain Numbers oR English Letters Or Arabic Letters  , false otherwise
     */
  private function checkStringAndNumber($var)
  {
     $pattern = "/^([\d\sa-zA-Z\p{Arabic}])+$/u";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkEmail
     *  check if The variable is a true email
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Is a True Email  , false otherwise
     */
  private function checkEmail($var)
  {
      $pattern = "/^([\w\.-]+)@([\w\.-]+)\.([\w.-]+)$/";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkUrl
     *  check if The variable is a true Url
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Is a True Url  , false otherwise
     */
  private function checkUrl($var)
  {
      $pattern = "/((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z0-9\&\.\/\?\:@\-_=#])*/";
      return (preg_match($pattern,$var))?TRUE:FALSE;
  }
    /**
     *  checkNotNull
     *  check if The variable Is Not Null
     * @param    $var (Unknown) The Data That Will Be Checked
     * @return true if The Data Is Not Null  , false otherwise
     */
  private function checkNotNull($var)
  {
     return(!empty($var))?TRUE:FALSE;
  }
    /**
     *  checkMaxLength
     *  check if The variable <= Max length
     *  @param    $name (Unknown_Type) The Data That Will Be Checked
     *  @param    $maxNumber (Int) The Max Length
     *  @return true if THE $name <= Max length , false otherwise
     */
  private function checkMaxLength($name,$maxNumber)
  {
	  if($this->checkNumber($maxNumber) == TRUE)
	  {
		  return (mb_strlen($name, 'UTF-8') <= $maxNumber)?TRUE:FALSE;
	  }
      return FALSE;
  }
    /**
     *  checkMinLength
     *  check if The variable >= Min length
     *  @param    $name (Unknown_Type) The Data That Will Be Checked
     *  @param    $minNumber (Int) The Min Length
     *  @return true if THE $name >= Min length , false otherwise
     */
  private function checkMinLength($name,$minNumber)
  {
	  if($this->checkNumber($minNumber) == TRUE)
	  {
		 return (mb_strlen($name, 'UTF-8') >= $minNumber)?TRUE:FALSE; 
	  }
      return FALSE;
  }
   /**
     *  checkMatch
     *  check if Two Fields Values Are Matches
     *  @param    $fieldVal (Unknown_Type) The Firse Field Value
     *  @param    $matchedFieldName (string) The Field That Will Be Match With Firest Field
     *  @return true if THE $fieldVal === $matchedFieldName Value , false otherwise
     */
  private function checkMatch($fieldVal,$matchedFieldName)
  {
    if(array_key_exists($matchedFieldName,$this->result['success']))
    {
       $matchedFieldVal = $this->result['success'][$matchedFieldName] ;
       return ($fieldVal === $matchedFieldVal)? TRUE : FALSE;
    }
  }
    
    /**
     *  checkBetween
     *  check if The Number Is Between Two Numbers
     *  @param    $val (number) The value that will be checked
     *  @param    $numbers (string) The Two Numbers For Check If The Number Between Them Like (1-9)
     *  @return true if THE $number Between Two Numbers , false otherwise
     */
 private function checkBetween($val,$numbers)
  {
    if(isset($numbers))
    {
      $between = explode(':',$numbers);
      if(is_array($between) && count($between) == 2)
      {
           return ($val >= ceil(min($between)) && $val <= ceil(max($between)))?TRUE:FALSE;
      }else{
        return FALSE;
      }
    }
  }
    
 private function sha1_md5($val)
 {
    return sha1(md5($val)); 
 }

}



?>
