<?php
namespace Engine\GenDocument\TextProcessor;

class DefaultTextHandler
{
	private $variablesSpace = null;

	public $stats = [];
	protected $resets = 0;

	private $functionsClass = '\App\GenDocument\TextProcessor\DefaultFunctions';

	public $lastCall = [];
	public $thisCall = [];
	public $firstCall = [];
	public $calls = [];

	function __construct(){
	}

	/*
	 * Reset the internal state of the object. Called when the parent resets. Implemented as "magic function" detected by the parent textProcessor class
	 * */
	function __reset(){
		$this->firstCall = [];
		$this->lastCall = [];
		$this->thisCall = [];
		$this->calls = [];


		// this is called to initialize the main class
		if(!$this->resets){
			global $CFG;
			if($CFG['DTM']['textProcessor']['functionsClass']){
				$this->functionsClass = $CFG['DTM']['textProcessor']['functionsClass'];
			}
			$this->resets++;
		}
	}

	/*
	 * custom defined function, used so we won't have to rely on the __call() method.
	 * Ths function can be detected and used accordingly, the __call methis would override all other methods...
	 * */
	function __customCall($input, $method, $params, $functionIndex){
		if(!$this->resets){
			$this->__reset();
		}
// 		debug_mark();
// 		var_dump($input, $method, $params, $functionIndex);

		$processed = false;

		if(!$method){
			return $input;
		}

		$this->thisCall = [];

		$this->thisCall['name'] = $method;
		$this->thisCall['functionIndex'] = $functionIndex;

		// check if this is a function call
		if(!$processed ){

			// check if the input data is not set. If this is the case, then it means that this is the first call in the calling chain...
			if(!isset($input)){
				$input = new $this->functionsClass($input);

				$this->thisCall['firstInChain'] = true;
			}

			// do the actual call, if the method exists
			if(is_callable([&$input, $method])){
				// first parse the params and see if we can replace any special variables in it
				foreach($params as $k=>$value){
					if($this->variablesSpace->exists("{$value}")){
						$params[$k] = $this->variablesSpace->getValue($value);
					}
				}

				$fctResult = call_user_func_array([&$input, $method], $params);
				$processed = true;

				$this->thisCall['isFunction'] = true;
			}
		}

		// check if this is a variable name... replace it, use the appropiate type for this
		if(!$processed && $this->variablesSpace->exists($method)){
			$fctResult= new $this->functionsClass($this->variablesSpace->getValue($method));
			$processed = true;

			$this->thisCall['isVariable'] = true;
		}

		// if we checked both functions and variables, then throw an error indicating that the generate failed...
		if(!$processed){
			// throw an error... the re-loop handler will get it and force a reloop
			throw new Exception\InvalidFunction("Trying to call invalid function or variable : '{$method}'", $method, $params, $functionIndex);
		}

		$this->calls[] = $this->thisCall;
		$this->lastCall = $this->thisCall;
		if(!$this->firstCall){
			$this->firstCall = $this->thisCall;
		}

		return $fctResult;
	}

	/*
	 * Assign the variablesSpace internally, so we'd be able to replace variables ourselfes
	 * */
	function loadVariables($variablesSpace){
		$this->variablesSpace = $variablesSpace;
	}

	/**
	 * Returns the internally variablesSpace attribute.
	 * @return \App\GenDocument\Vars\ValuesAbstract
	 */
	public function getVariables()
	{
		return $this->variablesSpace;
	}

	/*
	 * Return internal object stats
	 * */
	function getStats(){
		return [
			'firstCall' => 	$this->firstCall,
			'lastCall' => 	$this->lastCall,
			'thisCall' => 	$this->thisCall,
			'calls' => 		$this->calls,
		];
	}

}

