<?php defined('BASEPATH') OR exit('No direct script access allowed');

class Base_processor
{
	public $params;

	// protected $flags;

	private $_validators = array();

	protected $CI;

	protected $db;

	protected $cId = 0;

	protected $bId = 0;

	protected $userId = 0;

	/**
	 * Constructor
	 *
	 * @param array $params Reference to the processing parameters
	 */
	public function __construct(&$params)
	{
		$this->CI =& get_instance();

		$this->db =& $this->CI->db;

		$this->cId = get_company("id");

		$this->userId = get_user_data('id');

		$this->bId = get_user_data("defaultbId");

		$this->params =& $params;

		$this->_validators = array();

		// $this->flags = new stdClass();
	}

	/**
	 * Validates input data using all registered validators.
	 *
	 * @param array $data Input data to validate
	 * @return void
	 */
	public final function validate($data)
	{
		$this->setupValidators($data);
		$this->is_valid($data);
	}

	/**
	 * Hook to set up validators.
	 * Can be overridden in child classes to register custom validators.
	 *
	 * @param array $data Input data
	 */
	protected function setupValidators($data)
	{
		// All page common validation goes here.		
	}

	/**
	 * Executes all registered validators on the input data.
	 *
	 * @param array $data Input data (by reference)
	 * @return bool True if all validators pass, false otherwise
	 */
	public function is_valid(&$data)
	{
		if (empty($this->_validators))
		{
			return true;
		}

		$is_valid = true;

		foreach($this->_validators as $validator)
		{
			if (!$validator->is_valid($data))
			{
				$is_valid = false;
				break;
			}
		}

		return $is_valid;
	}

	/**
	 * Adds a new validator to the validator list.
	 *
	 * @param Validator_interface $ctxValidator An instance of a validator
	 */
	public function addValidator(Validator_interface $ctxValidator)
	{
		$this->_validators[] = $ctxValidator;
	}

	/**
	 * Triggers the "before save" hook.
	 *
	 * @param array $postData Data to be saved (by reference)
	 */
	public function init_save(&$postData)
	{
		
	}

	/**
	 * Customizable "before save" hook.
	 * Intended to be overridden in child classes for preprocessing.
	 *
	 * @param array $postData Data to be saved (by reference)
	 */
	protected function pre_save(&$postData)
	{
		
	}

	protected function execute_save(&$postData, &$result)
	{
		
	}

	/**
	 * Hook executed right after transaction starts.
	 * Can be overridden for setting locks or preparing the environment.
	 */
/*
	public function pre_save(&$postData)
	{
	}
*/
	/**
	 * Hook executed after data is saved but before transaction commit.
	 * Can be overridden for cleanup, verification, or additional steps.
	 */
	public function post_save(&$postData, &$result)
	{
		
	}

	/**
	 * Triggers the "after save" hook.
	 *
	 * @param array $postData Data that was saved (by reference)
	 * @param mixed $result Result of the save operation (by reference)
	 */
	public function post_commit(&$postData, &$result)
	{
		
	}

	public function save(&$postData, &$result)
	{
		$this->validate($data);

		$this->init_save($data);

		$this->CI->db->trans_start();

		try {

			$this->pre_save($data);

			$this->execute_save($data, $result);

			$this->post_save($data, $result);

		} catch(Exception $ex) {

			$this->CI->db->trans_rollback();

			throw $ex;
		}

		$this->CI->db->trans_complete();

		$this->post_commit($data, $result);
	}

	/**
	 * Dynamically runs a method on the class if it exists.
	 *
	 * @param string $functionName The method name to call
	 * @param mixed ...$args Arguments to pass to the method
	 * @return mixed|null The return value of the method or null if not found
	 */
	public function run()
	{
		$args = func_get_args();

		$functionName = array_shift($args);

		if (method_exists($this, $functionName))
		{
			return call_user_func_array([$this, $functionName], $args);
		}
		else
		{
			// throw new Exception("Function '$functionName' not found in " . __CLASS__);
			return null;
		}
	}

	public function strip_fields($data, $fields=array())
	{
		if (empty($fields)) {
			return $data;
		}

		if (in_array('cId', $fields)) {
			$data['cId']	= $this->params->cId;
		}

		// check posted data is in fields
		foreach ($data as $field => $value)
		{
			if (@!in_array($field, $fields) || is_null($data[$field]))
			{
				unset($data[$field]);
			}
		}

		return $data;
	}
}
