<?php
/*
  Clase SuperLineaPedidoCliente
 */

class SuperCabeceraCesta extends Objeto{
	//Variables estáticas que pertenecen a la cesta
	public static $cart = NULL;

	public $codigo = 0;
	public $cliente = 0;
	public $objeto_cliente = NULL;
	public $hash = '';
	public $lineas = array();
	//Campos que no vienen de la tabla, los calculamos sobre la marcha:
	public $cantidad = 0;
    public $base = 0;
	public $importe = 0;
	public $descuento = 0;
	public $importe_sin_descuento = 0;
	public $puntos = 0;
	public $puntos_gastados = 0;
	
	public static function getCampos($soloPrincipal = NULL){
		self::$nombreTabla = strtolower(get_called_class());
		self::getTablaRelacionada();
		//self::$campos_tabla = BaseDatos::$dictionary->{self::$nombreTabla . 'Campos'}; //==> Comento esta línea porque creo que no sirve pa na
		//Una vez que tenemos el nombre de la tabla, vamos a obtener los campos de la misma y los nombres para la selec
		if (self::$nombreTabla != ''){
			$campos = ' ';
			if ($soloPrincipal || $soloPrincipal === NULL){
				//$campos .= BaseDatos::dameCamposAlias(BaseDatos::$dictionary->{self::$nombreTabla . 'Campos'}, self::getAlias());
				$campos .= BaseDatos::dameCamposAlias(self::$nombreTabla);
			}
			if ($soloPrincipal === false || $soloPrincipal === NULL){
				$campos .= ( (trim($campos) != ' ') ? ', ' : '' ) . 
				LineaCesta::getCampos() . ', ' .
				Usuario::getCampos();
				
			}
			if ($soloPrincipal == NULL){
				self::$camposSelect = $campos;
			}
		}
		return($campos);
	}
	
	public static function getNombreTabla($soloPrincipal = NULL){
		//Incluimos los globals para coger el valor del idioma:
		//include('comunes/globals.php');
		self::$nombreTabla = strtolower(get_called_class());
		self::getTablaRelacionada();
		//Ahora vamos a componer el nombre de la tabla teniendo en cuenta si es sólo principal, si no o si es todo (NULL)
		$consulta = ' ';
		if ($soloPrincipal || $soloPrincipal === NULL){
			$consulta .= self::$nombreTabla . ' as `' .  self::getAlias() . '` ';
		}
		if ($soloPrincipal === false || $soloPrincipal === NULL){
			$consulta .= self::getJoin('CabeceraCesta', 'cliente', 'Usuario', 'codigo'); //Cogemos el cliente
			$consulta .= self::getJoin('CabeceraCesta', 'codigo', 'LineaCesta', 'cabecera'); //Queremos esta tabla con la de artículo
			$consulta .= LineaCesta::getNombreTabla(false);									//Cogemos los left join de artículo
		}
		$consulta .= ' ';
		//Sólo asignamos el nombre de la tabla si no nos piden más parámetros
		if ($soloPrincipal == NULL){
			self::$nombreTabla = $consulta;
		}
		return($consulta);
	}
	
	public static function getWhereTabla(){
		$argumentos = func_get_args();
		$cliente = isset($argumentos[0]) ? $argumentos[0] : 0;
		$codigo = isset($argumentos[1]) ? $argumentos[1] : 0;
		$hash = isset($argumentos[2]) ? $argumentos[2] : '';
		$limitar = isset($argumentos[3]) ? $argumentos[3] : true;
		
		//include('comunes/globals.php');
		self::$whereSelect = '';
		if ($cliente > 0) {
			self::$whereSelect = ' `' . self::getAlias() . '`.`cliente` = "' . $cliente . '" ';
		}
		if ($codigo > 0) {
			self::$whereSelect .= (self::$whereSelect != '') ? ' AND ' : '';
			self::$whereSelect .= ' `' .  self::getAlias() . '`.`codigo` = "' . $codigo . '" ';
		}
		if ($hash != '') {
			//Si ya tengo un cliente, entonces hago un OR, si no un AND:
			if (self::$whereSelect != ''){
				if ($cliente > 0) {
					self::$whereSelect .= (self::$whereSelect != '') ? ' OR ' : '';
				}else{
					self::$whereSelect .= (self::$whereSelect != '') ? ' AND ' : '';
				}
			}
			self::$whereSelect .= ' `' .  self::getAlias() . '`.`hash` = "' . $hash . '" ';
		}
		if ($limitar){
			self::$whereSelect .= ' LIMIT 0,1 ';
		}
		return(self::$whereSelect);
	}
	
    function __construct($opciones = NULL) {
		$filaCabecera = NULL;
		$codigoPedido = NULL;
		$objeto_cliente = Usuario::logueado();
		$setStaticCart = false;
		$cargarLineas = true;
        if ($opciones != NULL){
			if (is_a($opciones, 'OpcionesWidget')){
				$filaCabecera = ($opciones->configuracion->filaCabecera != NULL) ? $opciones->configuracion->filaCabecera : $filaCabecera;
				$codigoPedido = ($opciones->configuracion->codigoPedido != NULL) ? $opciones->configuracion->codigoPedido : $codigoPedido;
				$objeto_cliente = ($opciones->configuracion->objeto_cliente != NULL) ? $opciones->configuracion->objeto_cliente : NULL;
				$cargarLineas = ($opciones->configuracion->cargarLineas !== NULL) ? $opciones->configuracion->cargarLineas : $cargarLineas;
			}
		}
		$fila = NULL;
		if ($filaCabecera != NULL){
			$fila = $filaCabecera;
		}else{
			$sentencia_sql = 'SELECT ' . self::getCampos() . ' 
									FROM ' . self::getNombreTabla() . ' ' ;
			$sentencia_where = '';
			if (intval($codigoPedido) > 0) {	// ==> Si tengo un código de pedido lo cargo (no suele ser lo normal)
				//Preparamos el FROM con las uniones correspondientes
				$sentencia_where = ' WHERE ' . self::getWhereTabla($codigoPedido, NULL, '', false); //Cargamos todas las líneas del pedido
			}else if ($objeto_cliente != NULL){	// ==> Si el usuario está logueado lo cargo por su código
				$sentencia_where = ' WHERE ' . self::getWhereTabla($objeto_cliente->codigo, NULL, '', false); //Cargamos todas las líneas del pedido
					$setStaticCart = true;
			}else{	// ==> En caso contrario lo cargo por el hash de la sesión
				//No tenemos nada con qué cargar el pedido, vamos a por el hash de la sesión:
				$hash = Sesion::getHashSesion();
				if ($hash != NULL){
					$sentencia_where = ' WHERE ' . self::getWhereTabla(NULL, NULL, $hash, false); //Cargamos todas las líneas del pedido
					$setStaticCart = true;
				}
			}
			if ($sentencia_where != ''){
				$sentencia_sql = $sentencia_sql . $sentencia_where . '; ';
				//echo("$sentencia_sql <br />\n");
				$bd = new BaseDatos();
				if ($bd->isConectado()){
					$bd->setConsultaSQL($sentencia_sql);
					$fila = $bd->getFila();
				}
			}
		}

		$this->codigo = (int) $this->getProp($fila, 'codigo');
		$this->cliente = (int) $this->getProp($fila, 'cliente');
		//Si hemos recibido un objeto usuario, vamos a asignarlo
		if (is_a($objeto_cliente, 'Usuario')){
			$this->objeto_cliente = $objeto_cliente;
		}else{
			//Lo primero es mirar en la select si viene:
			$codigoCliente = $this->getProp($fila, 'codigo', Usuario::getAlias());
			if ($codigoCliente >= 0){
				$this->objeto_cliente = new Usuario(new OpcionesWidget(array('filaUsuario' => $fila)));
			}else{
				//Si llegados a este punto, no tenemos objeto cliente tenemos que ver si tenemos el código en la fila:
				$codigoCliente = (int) $this->getProp($fila, 'cliente');
				$this->objeto_cliente = new Usuario(new OpcionesWidget(array('codigo' => $codigoCliente)));
			}
			//Por último, si seguimos sin objeto cliente, vamos a cargar el de la sesión:
			if ($codigoCliente == 0){
				$this->objeto_cliente = Usuario::logueado();
			}
		}
		//Nos vamos a asegurar de que tenemos el código bien asignado:
		if ( ($this->cliente == 0) && ($this->objeto_cliente != NULL)){
			$this->cliente = $this->objeto_cliente->codigo;
			//Cuando esto ocurra, debemos grabar porque tenemos un cliente en la sesión pero no en la tabla:
			$this->grabar();
		}

		$this->hash = $this->getProp($fila, 'hash');
		//Vamos a ver si las líneas hay que cargarlas o vienen en la lista:
		$codigoLineaPedido = $this->getProp($fila, 'codigo', LineaCesta::getAlias());
		//Si el código es nulo, no nos lo han pasado y hay que cargarlo:
		
		if ($cargarLineas){
			if ($codigoLineaPedido == NULL){
				//hay que cargar las líneas:
				//$this->lineas = LineaCesta::getList($this->codigo); //Paso el código, pero podría haber pasado el objeto pedido
				$this->lineas = LineaCesta::getList($this); //Paso el objeto, pero podría haber pasado el código
			}else{
				//tenemos las líneas cargadas en esta misma select:
				do{
					$this->lineas[$this->getProp($fila, 'codigo', LineaCesta::getAlias())] = new LineaCesta(new OpcionesWidget(array(
						'filaLineaPedido' => $fila
						)));
				}while ($fila = $bd->getFila());
			}
		}		
		//Cuando está todo cargado vamos a inicializar los valores de totales de la cesta:
		$this->recalculate();
		//Llegados a este punto si la cesta hay que insertinsertarla en la estática, lo hacemos:
		if ($setStaticCart){
			static::$cart = $this;
		}
    }

    function __destruct() {
        
    }

	public static function getCart(){
		if (static::$cart == NULL){
			static::$cart = new CabeceraCesta();	//Cargando así la cesta se mete sóla en el objeto estático
		}
		return(static::$cart);
	}
	
	public function recalculate(){
		$this->cantidad = 0;
		$this->base = 0;
		$this->importe = 0;
		$this->importe_sin_descuento = 0;
		$this->puntos = 0;
		$this->puntos_gastados = 0;
		foreach($this->lineas as $clave => $valor){
			$this->cantidad += $valor->cantidad;
			$this->base += $valor->base;
			$this->importe += $valor->importe;
			$this->puntos += $valor->puntos;
			$this->puntos_gastados += $valor->puntos_gastados;
		}
		//echo("Despues de recalcular tenemos: " . $this->cantidad . " elementos\n ");
		//Ahora vamos a calcular el importe sin el descuento:
		//OJO esto está mal, Este campo es sin restar el descuento
		$this->importe_sin_descuento += Price::setDiscount($this->importe, $this->descuento);
	}
	
	public static function remoteAddProduct($data){
		//En data tenemos los datos a añadir a la línea (producto, cantidad, lote, etc.)
		//Vamos a ver si en "data" tenemos un EAN:
		//Si data es un string, hay que des-serializarlo (viene en json):
		if (is_string($data)){
			$data = json_decode($data);
		}
		//var_dump($data);
		$objeto_articulo = NULL;
		$ean = '';
		$codigoArticulo = 0;
		$cantidad = 0;
		$accion = '';
		$lote = 0;
		$oferta = 0;
		$retorno = new stdClass();
		if (isset($data->codigo_articulo)){
			$ean = $data->codigo_articulo;
		}else if (isset($data->ean)){
			$ean = $data->ean;
		}
		if ($ean != ''){
			$objeto_articulo = new Articulo($ean);
		}
		//Si hemos podido cargar el artículo vamos a seguir:
		//var_dump($objeto_articulo);
		if (is_a($objeto_articulo, "Articulo")){
			//Vamos a cargar la sesión:
			Sesion::init();
			//Vamos a cargar la cesta:
			$cart = static::getCart();
			//Es importante comprobar que exista una cabecera:
			if ($cart->codigo == 0){
				//Hay que guardar esta cabecera para tener un código:
				$cart->grabar();
			}
			//Vamos a coger el resto de datos:
			$cantidad = (isset($data->cantidad))? $data->cantidad : NULL;
			$accion = (isset($data->accion))? $data->accion : NULL;
			$lote = (isset($data->lote))? $data->lote : NULL;
			$oferta = (isset($data->oferta))? $data->oferta : NULL;
			$puntos_gastados = (isset($data->puntos_gastados))? $data->puntos_gastados : NULL;
			$linea = static::findInCart($objeto_articulo, array('lote' => $lote, 'oferta' => $oferta, 'puntos_gastados' => $puntos_gastados));
			//Si la acción es restar, nos vamos a asegurar que siempre sea "sumar"
			if ($accion == 'restar'){
				$accion = 'sumar';
				$cantidad *= -1;
			}
			//Si no hay línea hay que crearla siempre que vayamos a insertar algo:
			if ( ($linea == NULL) && ($cantidad > 0) ){
				//Ahora hay que crear una línea:
				$linea = new LineaCesta(new opcionesWidget(array('objetoPedido' => $cart, 'objetoArticulo' => $objeto_articulo)));			
			}
			//var_dump($linea);
			//Vamos a corregir la acción, en primer siempre se suma, nunca se resta:
			if ($linea != NULL){
				//Vamos a guardar la línea en la última borrada:
				Sesion::set('lastDeleted', clone $linea);
				
				//Ahora vamos a tener en cuenta si lo que nos pasan es absoluto o no:
				if ($accion == 'absoluto'){
					$nuevaCantidad = $cantidad;
				}else{
					//Cuando sumamos, tenemos que tener en cuenta la cantidad del lote y/o de la oferta:
					if ($linea->codigo_oferta > 0){
						//La cantidad de la línea está multiplicada por la cantida de la oferta:
						$nuevaCantidad = ($linea->cantidad/$linea->oferta->cantidad) + $cantidad;
					}else if ($linea->codigo_oferta > 0){
						$nuevaCantidad = $linea->cantidad + $cantidad;
					}else{					
						$nuevaCantidad = $linea->cantidad + $cantidad;
					}
				}
				//Vamos a controlar la acción y la nueva cantidad:
				//Ya tenemos la nueva cantidad a asignar, vamos a añadirla a la línea y a guardarla, pero ojo, que si es 0 o menor tenemos que borrar la línea:
				if ($nuevaCantidad <= 0){
					$nuevaCantidad = 0;
				}
				//echo("La nueva cantidad es: $nuevaCantidad\n");
				
				//Vamos a insertar la cantidad:
				$linea->setCantidad(new OpcionesWidget(array(
					'cantidad' => $nuevaCantidad,
					'oferta' => $oferta,
					'lote' => $lote,
					'puntos_gastados' => $puntos_gastados
				)));
				//echo($linea->cantidad);
				//Recalculamos otros datos de la línea (importes, etc...)
				$linea->grabar();
				//Si la cantidad de la línea se ha quedado a 0, se borra:
				if ($linea->cantidad == 0){
					unset($cart->lineas[$linea->codigo]);
				}else{
					//Si no se ha borrado nada, quitamos la línea de la sesión:
					Sesion::remove('lastDeleted');
					//echo("codigo insertado: " . $linea->codigo . "\n");
					$cart->lineas[$linea->codigo] = $linea;
				}
			
				//Recalculamos los importes y las cantidades del carrito:
				$cart->recalculate();
				//Asignamos la línea a la cesta y grabamos:
				$cart->grabar();
				
				//24/Enero/2019 ==> PEDRO ==> Esto ya no es necesario que lo hagan estas funciones, delegamos esto en la clase RemoteRequest
				/*
				//Vamos a actualizar los componentes que nos han pasado:
				$retorno->componentes = array();
				//Si hay componentes:
				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->componentes[] = Module::loadEncryptedComponent($componente);
							}
						}
					}
				}
				*/
				//Por último hacemos un commit de la sesión:
				Sesion::commit();
			}
		}
		//Aquí tenemos que dar un retorno:
		$retorno = json_encode($retorno);
		return($retorno);
	}
	
	public static function findInCart($product, $options = NULL){
		//echo("Vamos a buscar el producto en la cesta---");
		//El producto se busca siempre por EAN
		$lote = (isset($options['lote'])) ? $options['lote'] : NULL;
		$oferta = (isset($options['oferta'])) ? $options['oferta'] : NULL;
		$puntos_gastados = (isset($options['puntos_gastados'])) ? $options['puntos_gastados'] : NULL;
		$linea = NULL;
		//Cargamos la cesta:
		$cart = static::getCart();
		//Tenemos la cesta siempre en un objeto
		$lineas = $cart->lineas;
		
		if (is_array($lineas)){
			//echo("es un array---");
			foreach($lineas as $clave => $valor){
				//echo("Línea $clave---");
				//Vamos a buscar por ean o por código:
				if ( ($valor->ean == $product->ean) || ($valor->articulo == $product->codigo) ){
					//El producto está en la cesta, tenemos que ver si el lote o la oferta coinciden:
					if ( ($lote == NULL && $oferta == NULL && $puntos_gastados == NULL)
							&&
						($valor->lote == NULL && $valor->oferta == NULL && $valor->puntos_gastados == NULL) ){
						$linea = $valor;
						break;
					}else if ( ($lote != NULL) && ($lote == $valor->lote) ){
						$linea = $valor;
						break;
					}else if ( ($oferta != NULL) && ($oferta == $valor->codigo_oferta) ){
						$linea = $valor;
						break;
					}else if ( ($puntos_gastados != NULL) && ($puntos_gastados == $valor->puntos_gastados) ){
						$linea = $valor;
						break;
					}
					
				}
			}
		}
		return($linea);
	}
	
	public function grabar($setStaticCart = true){
		//Necesitamos al cliente:
		$cliente = Sesion::get('cod_cliente_web', 0);
		//comprobamos si es un alta o una modificación
		if ($this->codigo == 0){
			//Insert:
			$bd = new BaseDatos();
			if ($bd->isConectado()){
				$sentencia_sql = 'INSERT INTO tmp_cabecera_pedidos (cliente, hash) VALUES ("' . $cliente . '", "' . Sesion::getHashSesion() . '");';
				$bd->setConsultaSQL($sentencia_sql);
				$this->codigo = $bd->getAutonumerico();
			}
		}else{
			//Update:
			$bd = new BaseDatos();
			if ($bd->isConectado()){
				$sentencia_sql = 'UPDATE tmp_cabecera_pedidos SET cliente = ' . $cliente . ', hash = "' . Sesion::getHashSesion() . '"
					WHERE codigo = ' . $this->codigo . ' ; ';
				$bd->setConsultaSQL($sentencia_sql);
			}
		}
		//Si hay que guardar en la variable estática, vamos a ello:
		//echo($this->cantidad);
		if ($setStaticCart){
			static::$cart = $this;
		}
	}
	
	//Esta función indica si podemos finalizar el pedido o no
	public function readyToFinish(){
		$retorno = true;
		$tipo_envio = Sesion::get('tipo_envio');
		$forma_pago = Sesion::get('forma_pago');
		$obTipoEnvio = new TipoEnvioCliente($tipo_envio);
		$obFormaPago = new FormasPago($forma_pago);
		//Si no hay líneas, no seguimos mirando nada:
		if ($this->cantidad == 0){
			$retorno = false;
		}
		//El usuario tiene que ser distinto de NULL (usuario logueado o con datos de envío)
		if (Usuario::logueado() == NULL){
			$retorno = false;
		}
		//Si no hay tipo de envío no seguimos:
		if ($obTipoEnvio->codigo == 0){
			$retorno = false;
		}else{
			//Aquí falta ver si la dirección de envío está completa (Si el envío requiere envío)
			
			//Si el tipo de envío requiere pago y el pago no es correcto, entonces no podemos seguir
				//Al igual que antes, niego la condición
			if (!( (!$obTipoEnvio->requiere_pago) || ($obFormaPago->codigo > 0) )){
				$retorno = false;
			}
		}
		return($retorno);
	}
	
	//Finalizamos el pedido grabándolo en la BD en la tabla de pedidos y enviando los emails que sean correspondientes:
		//Devuelve el código del pedido creado
	public function finish(){
		return(PedidoCliente::newOrderFromCart($this));
	}
	
	public function shippingCosts(){
		//Aquí vamos a meter más adelante el cálculo de los gastos de envío, por ahora son 0
		$retorno = 0;
			//La función original de gastos de envío va a estar en el cliente, desde aquí obtendremos los parametros que sean necesarios para pasárselos
		$usuario = Usuario::logueado();
		if ($usuario != NULL){
			$retorno = $usuario->shippingCosts();
		}
		
		return($retorno);
	}
	public static function emtpyCart(){
		Sesion::remove("lastDeleted");
		//Vamos a actualizar los componentes que nos han pasado:
		$cart = static::getCart();
		foreach($cart->lineas as $clave => $linea){
			$linea->setCantidad(new OpcionesWidget(array(
					'cantidad' => 0,
					'oferta' => $linea->oferta,
					'lote' => $linea->lote,
					'puntos_gastados' => $linea->puntos_gastados
				)));
			$linea->grabar();
			unset($cart->lineas[$clave]);
		}
		$cart->recalculate();
		$cart->grabar();
	}
	//------------------------------------------------------------------------------------------
	//Funciones remotas
	//------------------------------------------------------------------------------------------
	public static function remoteDiscardRestoreProduct($data){
		Sesion::remove("lastDeleted");
		//Vamos a actualizar los componentes que nos han pasado:
		$retorno = new stdClass();
		//24/Enero/2019 ==> PEDRO ==> Esto ya no es necesario que lo hagan estas funciones, delegamos esto en la clase RemoteRequest
		/*
		$retorno->componentes = array();
		//Si hay componentes:
		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->componentes[] = Module::loadEncryptedComponent($componente);
					}
				}
			}
		}
		*/
		//Por último hacemos un commit de la sesión:
		Sesion::commit();
		$retorno = json_encode($retorno);
		return($retorno);
	}
	
	public static function remoteEmtpyCart($data){
		static::emtpyCart();
		$retorno = new stdClass();
		//Si hay componentes:
		//24/Enero/2019 ==> PEDRO ==> Esto ya no es necesario que lo hagan estas funciones, delegamos esto en la clase RemoteRequest
		/*
		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->componentes[] = Module::loadEncryptedComponent($componente);
					}
				}
			}
		}
		*/
		//Por último hacemos un commit de la sesión:
		Sesion::commit();
		$retorno = json_encode($retorno);
		return($retorno);
	}

}

?>