<?php

/**
 * $valid = new validate($arr);
 * $valid
 *  ->field('name', 'Full Name')->is_empty()->match('Sami')
 *  ->field('dob', 'Date of Birth')->is_less_than('2016-10-12')
 *  ->field('password', 'Date of Birth')->min_length(5)->is_numberchar();
 *  $error = $valid->evaluate(); //array of errors
 */
class validate {

    /**
     * array used as POST / GET / etc...
     * @var type 
     */
    private $arr = array();

    /**
     * set the message
     * @var type 
     */
    private $messages = array(
        'empty' => "You need to fill %s (%s) !",
        'numeric' => "%s (%s) should be a number. Example:1234 or 1.2",
        'int' => "%s (%s) should be integer. Example:1",
        'float' => "%s (%s) should be real. Example:1.2",
        'maxlength' => "%s (%s) length should not exceed (%s)",
        'minlength' => "%s (%s) length should be at least (%s)",
        'match' => "%s (%s) should match (%s)",
        'greater' => "%s (%s) should be greater than (%s)",
        'less' => "%s (%s) should be less than (%s)",
        'email' => "%s is not a correct email format. Check Example:you@site.me",
        'numberchar' => "%s should contains at least one number and one character",
        'positive_float' => "%s should be a positive number",
    );

    /**
     * fill array error to return when finish
     * @var type 
     */
    private $error = array();

    /**
     * field variable that will be used to enable multi check on same field
     * @var type 
     */
    private static $field = null;

    /**
     * set the value of the ruled field
     * @var type 
     */
    private static $value = null;

    /**
     * set the label of the ruled field
     * @var type 
     */
    private static $label = null;

    /**
     * 
     * @param type $arr
     */
    public function __construct($arr) {
        $this->arr = $arr;
    }

    /**
     * set the field and value used to check with
     * @param type $field
     * @return \validate
     */
    public function field($field, $label = null) {
        self::$field = $field;
        self::$value = isset($this->arr[$field]) ? $this->arr[$field] : null;
        self::$label = isset($label) ? $label : $field;
        return $this;
    }

    /**
     * check if data is empty
     * @return \validate
     */
    public function is_empty(&$err = null) {
        if (!self::$value) {
            $this->err_handle('empty', $err);
        }
        return $this;
    }

    /**
     * check if number
     * @return \validate
     */
    public function is_numeric(&$err = null) {
        if (!is_numeric(self::$value)) {
            $this->err_handle('numeric', $err);
        }
        return $this;
    }

    /**
     * check if int
     * @return \validate
     */
    public function is_int(&$err = null) {
        if (!is_int(self::$value)) {
            $this->err_handle('int', $err);
        }
        return $this;
    }

    /**
     * check if float
     * @return \validate
     */
    public function is_float(&$err = null) {
        if (!is_int(self::$value)) {
            $this->err_handle('float', $err);
        }
        return $this;
    }
     /**
     * check if only contain numbers
     * @return \validate
     */
    public function is_numericChar(&$err = null) {
        if (!ctype_digit(self::$value)) {
            $this->err_handle('int', $err);
        }
        return $this;
    }
     /**
     * check if only contain numbers
     * @return \validate
     */
    
    public function is_floatChar(&$err = null) {
        $pattern = "/^(?:\d+|\d*\.\d+)$/";
        if (!preg_match($pattern, self::$value)) {
            $this->err_handle('positive_float', $err);
        }
        return $this;
    }

    /**
     * handle non numeric values
     * @param type $var1
     * @param type $var2
     */
    private static function than_handler(&$var1, &$var2) {
        if (!is_numeric($var1) || is_numeric($var2)) {
            $var1 = strtotime($var1);
            $var2 = strtotime($var2);
        }
    }

    /**
     * check greater date or number
     * @param type $val
     * @param type $msg
     * @return \validate
     */
    public function is_less_than($val, &$err = null) {

        $var1 = self::$value;
        $var2 = $val;
        self::than_handler($var1, $var2);
        if ($var2 < $var1) {
            $this->err_handle('less', $err, $val);
        }
        return $this;
    }

    /**
     * check greater date or number
     * @param type $val
     * @param type $msg
     * @return \validate
     */
    public function is_greater_than($val, &$err = null) {

        $var1 = self::$value;
        $var2 = $val;
        self::than_handler($var1, $var2);

        if ($var2 > $var1) {
            $this->err_handle('greater', $err, $val);
        }
        return $this;
    }

    /**
     * check if email
     * @param type $msg
     * @return \validate
     */
    public function is_email(&$err = null) {
        $pattern = "/^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,3})$/";
        if (!preg_match($pattern, self::$value)) {
            $this->err_handle('email', $err);
        }
        return $this;
    }

    
    /**
     * check if email
     * @param type $msg
     * @return \validate
     */
    public function is_numberchar(&$err = null) {
        $pattern = "/^(?=.*?[A-Za-z])(?=.*?[0-9])/";
        if (!preg_match($pattern, self::$value)) {
            $this->err_handle("numberchar", $err);
        }
        return $this;
    }

    /**
     * check maximum length
     * @param type $length

     * @param type $encode
     * @return \validate
     */
    public function max_length($length, &$err = null, $encode = 'utf-8') {
        if (mb_strlen(self::$value, $encode) > $length) {
            $this->err_handle('maxlength', $err, $length);
        }
        return $this;
    }

    /**
     * check minimum length
     * @param type $length
     * @param type $encode
     * @return \validate
     */
    public function min_length($length, &$err = null, $encode = 'utf-8') {
        if (mb_strlen(self::$value, $encode) < $length) {
            $this->err_handle('minlength', $err, $length);
        }
        return $this;
    }

    /**
     * check if equal to another value
     * @param type $val
     * @return \validate
     */
    public function match($val, &$err = null) {
        if (self::$value != $val) {
            $this->err_handle('match', $err, $val);
        }
        return $this;
    }

    /**
     * error handle
     * @param type $type
     * @param type $err
     */
    private function err_handle($type, &$err = null, $compare = null) {

        // get the message from the array default we have
        $msg = $this->messages[$type];
        // validate
        $err = sprintf($msg, self::$label, self::$value, $compare);
        $this->error[] = $err;
    }

    /**
     *  check whether there are errors or no
     * @return type
     */
    public function evaluate() {
        return $this->error;
    }

}

?>