<?php

/*
  Clase SuperConfigFiles
  24/01/2019 ==> Se ejecuta el widget o módulo directamente desde aquí, justo después de lanzar la función remota. El resultado de la función remota se añade en un campo de "data" llamado response
  @version 1.1
 */

class SuperRemoteRequest {
	private static $last_error = '';
    //Constructor y destructor
    public function __construct() {
    }

    public function __destruct() {
        
    }
	
	//----------------------------------------------------
	// Por ahora los parámetros que vamos a recibir son:
	//	controller ==> Conrolador a lanzar (clase, controlador u módulo
	//	method ==> Método que se va a lanzar ==> Esta función le añadirá siempre la palabra "Remote" delante convirtiendo el método el camel case
	//	data ==> datos que le vamos a pasar al método
	//----------------------------------------------------
	public static function call($struct){
		//----------------------------------------------------
		//Vamos a capturar la salida para no devolverla:
		ob_start();
		$retorno = new BasicObject();
		$retorno->response = false;
		//$struct contiene una estructura de datos en formato Json pero en base64, hay que decodificar:

		$struct = base64_decode($struct);
		//Resulta que javascript nos envía json en utf8, pero necesitamos los caracteres especiales pasados a unicode (\uXXX), para solucionarlos codificamos con json y decodificamos
		/*$struct = json_encode($struct);
		$struct = json_decode($struct);*/
		//echo("$struct\n");

		if ($struct = static::json_validate($struct)){
			if (isset($struct->controller)){
				$controller = $struct->controller;
				if (class_exists($controller)){
					//Nos pueden haber mandado un método diferente:
					$method = 'remoteRequest';
					if (isset($struct->method)){
						$method = $struct->method;
						//Por seguridad convertimos el nombre del méotdo:
						$method = 'Remote' . ucfirst($method);
					}
					//Vamos a ver si la clase especificada tiene un método así:
					if (method_exists($controller, $method)){
						//Ahora sólo vamos a ver si existe data o es nulo:
						$data = NULL;
						if (isset($struct->data)){
							$data = $struct->data;
						}
						//ya sólo queda llamar a la función pasándole el objeto:
						//$retorno->data = $controller::$method($data);
						//Modificado por Pedro el 24/Enero/2018 ==> Esta clase se va a encargar de ejecutar los widgets o módulos a actualizar
						$retorno->response = $controller::$method($data);
						//Ahora vamos a crearnos el objeto que va a ser devuelto:
						$retorno->data = array();
						if (isset($data->components)){
							$components = $data->components;
							//si los componentes son un array, vamos a recorrerlo
							if (is_array($components)){
								foreach($components as $clave => $componente){
									if (isset($componente->component)){
										$componente = $componente->component;
										//En componente tengo una cadena de texto con la que podemos lanzar un widget:
										$retorno->data[] = Module::loadEncryptedComponent($componente);
									}
								}
							}
						}
						//var_dump($retorno->data);
					}else{
						echo('El controlador definido no contiene el método especificado');
					}
				}else{
					echo('El controlador definido no existe');
				}
			}else{
				echo('Controlador no definido');
			}
		}else{
			echo(static::getLastError());
		}
		//Capturamos cualquier salida que hubiese
		$salida = ob_get_contents();
		//Si tenemos algo en salida, lo guardamos en el objeto:
		$retorno->msgs = $salida;
		//Creamos un objeto Json
		$retorno = json_encode($retorno);
		//Limpiamos la salida de pantalla
		ob_clean();
		//Vamos a indicar que el retorno es json:
		header('Content-Type: application/json');
		echo($retorno);
	}
	
	public static function json_validate($string)
{
		// decode the JSON data
		$result = json_decode($string);

		// switch and check possible JSON errors
		switch (json_last_error()) {
			case JSON_ERROR_NONE:
				$error = ''; // JSON is valid // No error has occurred
				break;
			case JSON_ERROR_DEPTH:
				$error = 'The maximum stack depth has been exceeded.';
				break;
			case JSON_ERROR_STATE_MISMATCH:
				$error = 'Invalid or malformed JSON.';
				break;
			case JSON_ERROR_CTRL_CHAR:
				$error = 'Control character error, possibly incorrectly encoded.';
				break;
			case JSON_ERROR_SYNTAX:
				$error = 'Syntax error, malformed JSON.';
				break;
			// PHP >= 5.3.3
			case JSON_ERROR_UTF8:
				$error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
				break;
			// PHP >= 5.5.0
			case JSON_ERROR_RECURSION:
				$error = 'One or more recursive references in the value to be encoded.';
				break;
			// PHP >= 5.5.0
			case JSON_ERROR_INF_OR_NAN:
				$error = 'One or more NAN or INF values in the value to be encoded.';
				break;
			case JSON_ERROR_UNSUPPORTED_TYPE:
				$error = 'A value of a type that cannot be encoded was given.';
				break;
			default:
				$error = 'Unknown JSON error occured.';
				break;
		}

		if ($error !== '') {
			// throw the Exception or exit // or whatever :)
			exit($error);
			self::$last_error = $error;
		}else{
			self::$last_error = '';
		}

		// everything is OK
		return $result;
	}
	public static function getLastError(){
		return(self::$last_error);
	}
}
