<?php
/**
 * @package Helpers
 * @subpackage Validation
 * @author Andrew Embler <andrew@concrete5.org>
 * @copyright  Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
 * @license    http://www.concrete5.org/license/     MIT License
 */

/**
 * Helper functions to use with validating submitting forms.
 * @package Helpers
 * @subpackage Validation
 * @author Andrew Embler <andrew@concrete5.org>
 * @copyright  Copyright (c) 2003-2008 Concrete5. (http://www.concrete5.org)
 * @license    http://www.concrete5.org/license/     MIT License
 */
 
 
	defined('C5_EXECUTE') or die("Access Denied.");
	class Concrete5_Helper_Validation_Form {	
		
		protected $fields = array();
		protected $fieldsInvalid = array();
		protected $data = array();
		protected $files = array();
		protected $error;
		
		/**
		 * @access private
		 */
		const VALID_NOT_EMPTY = 1;
		const VALID_EMAIL = 2;
		const VALID_INTEGER = 3;
		const VALID_INTEGER_REQUIRED = 4;
		const VALID_UPLOADED_IMAGE = 10;
		const VALID_UPLOADED_IMAGE_REQUIRED = 11;
		const VALID_UPLOADED_FILE = 20;
		const VALID_UPLOADED_FILE_REQUIRED = 25;
		const VALID_TOKEN = 30;
		const VALID_FIELD_INVALID = 99;

		public function __construct() {
			$this->error = Loader::helper('validation/error');
		}
		
		
		/** 
		 * Adds a test to a field to ensure that, if set, it is a valid uploaded image.
		 * @param string $field
		 * @param string $errorMsg
		 * @param bool $emptyIsOk Tells whether this can be submitted as empty (e.g. the validation tests only run if someone is actually submitted in the post.)
		 * @return void
		 */
		public function addUploadedImage($field, $errorMsg = null, $emptyIsOk = true) {
			$const = ($emptyIsOk) ? ValidationFormHelper::VALID_UPLOADED_IMAGE : ValidationFormHelper::VALID_UPLOADED_IMAGE_REQUIRED;
			$this->addRequired($field, $errorMsg, $const);
		}
		
		/** 
		 * Adds a test to a field to ensure that, if set, it is a valid uploaded file.
		 * @param string $field
		 * @param string $errorMsg
		 * @param bool $emptyIsOk Tells whether this can be submitted as empty (e.g. the validation tests only run if someone is actually submitted in the post.)
		 * @return void
		 */
		public function addUploadedFile($field, $errorMsg = null, $emptyIsOk = true) {
			$const = ($emptyIsOk) ? ValidationFormHelper::VALID_UPLOADED_FILE : ValidationFormHelper::VALID_UPLOADED_FILE_REQUIRED;
			$this->addRequired($field, $errorMsg, $const);
		}
		
		/** 
		 * Adds a required field and tests that it is integer only
		 * @param string $field
		 * @param string $errorMsg
		 * @param bool $emptyIsOk Tells whether this can be submitted as empty (e.g. the validation tests only run if someone is actually submitted in the post.)
		 * @return void
		 */
		public function addInteger($field, $errorMsg = null, $emptyIsOk = true) {
			$const = ($emptyIsOk) ? ValidationFormHelper::VALID_INTEGER : ValidationFormHelper::VALID_INTEGER_REQUIRED;
			$this->addRequired($field, $errorMsg, $const);
		}

		/** 
		 * Adds a required field to the form helper object. This will then be typically used in conjunction with the test() method to see
		 * if the test is passed
		 * @param string $field
		 * @param string $errorMsg
		 * @param string $validate test to validate against
		 * @return void
		 */
		public function addRequired($field, $errorMsg = null, $validate = ValidationFormHelper::VALID_NOT_EMPTY) {
			$obj = new stdClass;
			$obj->message = ($errorMsg == null) ? 'Field "' . $field . '" is invalid' : $errorMsg;
			$obj->field = $field;
			$obj->validate = $validate;
			$this->fields[] = $obj;
		}
		
		public function addRequiredToken($value, $errorMsg = null) {
			$obj = new stdClass;
		 	$vt = Loader::helper('validation/token');
			$obj->message = ($errorMsg == null) ? $vt->getErrorMessage() : $errorMsg;
			$obj->value = $value;
			$obj->validate = ValidationFormHelper::VALID_TOKEN;
			$this->fields[] = $obj;
		}
		
		/** 
		 * Adds a required email address to the suite of tests to be run.
		 * @param string $field
		 * @param string $errorMsg
		 * @return void
		 */
		public function addRequiredEmail($field, $errorMsg = null) {
			$this->addRequired($field, $errorMsg, ValidationFormHelper::VALID_EMAIL);
		}
		
		/**
		 * Sets the data files array 
		 */
		public function setFiles() {
			$this->files = $_FILES;
		}
		
		/** 
		 * An associative array that we setup to validate against. Typical usage is $val->setData($_POST);
		 * @param array $data
		 * @return void
		 */
		public function setData($data) {
			$this->data = $data;
		}
		
		/** 
		 * @access private
		 */
		protected function setErrorsFromInvalidFields() {
			foreach($this->fieldsInvalid as $f) {
				$this->error->add($f->message);	
			}
		}
		
		
		public function invalidate($message) {
			$f = new stdClass;
			$f->message = $message;
			$this->fieldsInvalid[] = $f;
		}
		
		/** 
		 * After the validation error helper has been setup, the test() method ensures that all fields that require validation
		 * pass. Returns the number of invalid fields (0 = success)
		 * @return int
		 */
		public function test() {
			$val = Loader::helper('validation/strings');
			$num = Loader::helper('validation/numbers');
			$fil = Loader::helper('validation/file');
			
			// loop through all the fields in the array, and run whatever validation
			// the validate parameter says is required
			foreach($this->fields as $f) {
				$validate = $f->validate;
				$field = $f->field;				
				switch($validate) {
					case ValidationFormHelper::VALID_NOT_EMPTY:
						if (!$val->notempty($this->data[$field])) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_TOKEN:
						$vt = Loader::helper('validation/token');
						if (!$vt->validate($f->value)) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_INTEGER:
						if ((!$num->integer($this->data[$field])) && ($val->notempty($this->data[$field]))) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_INTEGER_REQUIRED:
						if (!$num->integer($this->data[$field])) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_UPLOADED_IMAGE:
						if ((!$fil->image($this->files[$field]['tmp_name'])) && ($this->files[$field]['tmp_name'] != '')) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_UPLOADED_IMAGE_REQUIRED:
						if (!$fil->image($this->files[$field]['tmp_name'])) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_UPLOADED_FILE:
						if ((!$fil->file($this->files[$field]['tmp_name'])) && ($this->files[$field]['tmp_name'] != '')) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_UPLOADED_FILE_REQUIRED:
						if (!$fil->file($this->files[$field]['tmp_name'])) {
							$this->fieldsInvalid[] = $f;
						}
						break;
					case ValidationFormHelper::VALID_EMAIL:
						if (!$val->email($this->data[$field])) {
							$this->fieldsInvalid[] = $f;
						}
						break;
				}
			}
			
			$this->setErrorsFromInvalidFields();
			return count($this->fieldsInvalid) == 0;
		}
		
		/** 
		 * Gets the error object. 
		 * <code>
		 *     if ($val->test() > 0) { 
		 *         $e = $val->getError();
		 *     }
		 * </code>
		 * @return ValidationErrorHelper
		 */
		public function getError() {
			return $this->error;
		}
	
	}
	
?>