<?php
/**
 * Doctrine_Validator
 */
class Doctrine_Validator {
    /**
     * ERROR CONSTANTS
     */

    /**
     * constant for length validation error
     */
    const ERR_LENGTH = 0;
    /**
     * constant for type validation error
     */
    const ERR_TYPE   = 1;
    /**
     * constant for general validation error
     */
    const ERR_VALID  = 2;
    /**
     * constant for unique validation error
     */
    const ERR_UNIQUE = 3;
    
    /**
     * @var array $stack        error stack
     */
    private $stack      = array();
    /**
     * @var array $validators   an array of validator objects
     */
    private static $validators = array();
    /**
     * returns a validator object
     *
     * @param string $name
     * @return Doctrine_Validator_Interface
     */
    public static function getValidator($name) {
        if( ! isset(self::$validators[$name])) {
            $class = "Doctrine_Validator_".ucwords(strtolower($name));
            if(class_exists($class)) {
                self::$validators[$name] = new $class;
            } elseif(class_exists($name."Validator")) {
                self::$validators[$name] = new $name."Validator";
            } else 
                throw new Doctrine_Exception("Validator named '$name' not availible.");
        }
        return self::$validators[$name];
    }
    /**
     * validates a given record and saves possible errors
     * in Doctrine_Validator::$stack
     *
     * @param Doctrine_Record $record
     * @return void
     */
    public function validateRecord(Doctrine_Record $record) {
        $modified = $record->getModified();
        $columns  = $record->getTable()->getColumns();
        $name     = $record->getTable()->getComponentName();

        $err      = array();
        foreach($modified as $key => $value) {
            $column = $columns[$key];

            if(strlen($value) > $column[1]) {
                $err[$key] = Doctrine_Validator::ERR_LENGTH;
                continue;
            } 

            if(self::gettype($value) !== $column[0]) {
                $err[$key] = Doctrine_Validator::ERR_TYPE;
                continue;
            }

            $e = explode("|",$column[2]);

            foreach($e as $k => $arg) {
                if(empty($arg) || $arg == "primary")
                    continue;

                $validator = self::getValidator($arg);
                if( ! $validator->validate($record,$key,$value)) {
                    switch(strtolower($arg)):
                        case "unique":
                            $err[$key] = Doctrine_Validator::ERR_UNIQUE;
                        break;
                        default:
                            $err[$key] = Doctrine_Validator::ERR_VALID;
                        break;
                    endswitch;
                }
                if(isset($err[$key]))
                    break;
            }
        }

        if( ! empty($err)) {
            $this->stack[$name][] = $err;
            return false;
        }
        
        return true;
    }
    /**
     * whether or not this validator has errors
     *
     * @return boolean
     */
    public function hasErrors() {
        return (count($this->stack) > 0);
    }
    /**
     * returns the error stack
     *
     * @return array
     */
    public function getErrorStack() {
        return $this->stack;
    }
    /**
     * returns the type of loosely typed variable
     *
     * @param mixed $var
     * @return string
     */
    public static function gettype($var) {
        $type = gettype($var);
        switch($type):
            case "string":
                if(preg_match("/^[0-9]+$/",$var)) return "integer";
                elseif(is_numeric($var)) return "float";
                else return $type;
            break;
            default:
            return $type;
        endswitch;
    }
}
?>