/*
 * Fichero:     ClienteServicioComercioP2P.java
 * Fecha:       26/11/2006
 * Autor:       Alvaro Sarmiento Losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase ClienteServicioComercioP2P, que representa un
 *              cliente del servicio JXTA de comercio electrónico ComercioP2P.
 *
 * Este fichero pertenece al proyecto fin de carrera del autor,
 * consistente en el estudio de JXTA y su aplicación al comercio 
 * electrónico b2b.
 */
package com.pfc.comercio.p2p;

import com.pfc.lib.p2p.ExcepcionP2P;
import com.pfc.lib.p2p.GrupoDePeers;
import com.pfc.lib.xml.MensajeXML;
import com.pfc.lib.xml.SoporteMensajesXML;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import net.jxta.endpoint.InputStreamMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.pipe.PipeMsgEvent;
import net.jxta.pipe.PipeMsgListener;
import net.jxta.protocol.PeerAdvertisement;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.util.JxtaBiDiPipe;


/**
 * Esta clase representa a un  cliente de un servicio JXTA  {@link ComercioP2P}  de intercambio de mensajes de comercio  electrónico basado en cXML. Actúa como plataforma de JXTA para los niveles superiores de aplicación: sólo se encarga de la transmisión y recepción de los mensajes a través de la red JXTA, dejando a  los niveles superiores la tarea de la generación y tratamiento de los mensajes. De esta forma se consigue la separación entre los niveles de Servicio JXTA y  Aplicación JXTA, tal y como está descrito en la guía de usuario de JXTA v2.0 . <br> Un objeto de esta clase se conecta a través de una tubería a un servidor <code>ComercioP2P</code> y le envía o recibe mensajes JXTA de  contenido XML, determinados por  {@link MensajeXML} .
 * @author   Alvaro Sarmiento Losada
 * @see  ComercioP2P
 */
public class ClienteComercioP2P extends Object
								implements 	PipeMsgListener, 
											SoporteMensajesXML, 
											ParametrosComercioP2P{
	/** Almacena una referencia al grupo JXTA donde se ejecuta este servicio */
    private GrupoDePeers grupo;
    
    /**
     * Almacena el anuncio de peer del destinatario de un mensaje enviado
     * por este cliente.
     */
    private PeerAdvertisement destinatario;
    
    /**
     * Almacena el anuncio de la tubería JXTA bidireccional por la que se 
     * enviarán y recibirán los mensajes JXTA.
     */    
    private PipeAdvertisement tuberiaServicio;

    /**
     * Almacena la tubería JXTA bidireccional por la que se enviarán y 
     * recibirán los mensajes JXTA.
     */    
    private JxtaBiDiPipe miBiDiPipe;
    
    /** Almacena un flujo al recibir un mensaje JXTA. */
    private InputStream flujoRecibido;
    
    /**
     * Constructor básico de la clase.
     */
    protected ClienteComercioP2P() {
        destinatario = null;
        tuberiaServicio = null;
        //Registra este objeto como soporte de mensajes XML.
        MensajeXML.registrarSoporteMensajes(this);
    }
        
    /**
     * Crea una nueva instancia de este cliente a partir de una referencia
     * a un grupo de peers donde implantan el servicio ComercioP2P.
     *
     * @param grupo el grupo de peers {@link GrupoDePeers} en el que se
     *              instancia el servicio.
     */
    public ClienteComercioP2P(GrupoDePeers grupo) {
        this();
        this.grupo = grupo;        
    }
    
    /**
	 * Devuelve el anuncio de peer del destinatario actual de los mensajes.
	 * @return  el anuncio del peer destinatario de los mensajes de este cliente.
	 * @uml.property  name="destinatario"
	 */
    public PeerAdvertisement getDestinatario() {
        return destinatario;
    }
    
    /**
	 * Establece el destinatario de los mensajes enviados por este cliente. Puede usarse este método un número ilimitado de veces, oncluso con distintos destinatarios. No es necesario usar este método si se envía <b>consecutivamente</b> a un mismo destinatario.
	 * @param destinatario  el anuncio del peer destinatario de los mensajes de   este cliente
	 * @uml.property  name="destinatario"
	 */
    public void setDestinatario(PeerAdvertisement destinatario) {
        this.destinatario = destinatario;
        //Se obtiene la tubería de servicio del destinatario
        tuberiaServicio = grupo.encontrarServicioDeUnPeer(SERVICIO, 
                                                          destinatario);
        System.out.println("tuberia:"+tuberiaServicio);
    }
    
    public void enviar(InputStream mensaje) throws ExcepcionP2P {
        
        if( tuberiaServicio == null)
   		 System.out.println("Hay que solucionarlo");
   	 else
   		 System.out.println("Esto marcha");
   	 
       try {
           //Se crea una nueva tubería bidireccional
           miBiDiPipe = new JxtaBiDiPipe();
           
           if(miBiDiPipe!=null)
           	System.out.println("Crea la tuberia Bidireccional");
           	
           //Se intenta conectar con el destinatario establecido
           miBiDiPipe.connect(grupo.getMiGrupo(), 
                              null, 
                              tuberiaServicio, 
                              60000, 
                              this);
           
           System.out.println("Ha conectado");
       
           /* Se crea el mensaje JXTA */
           Message msg = new Message();
           //Se añade los datos a enviar
           InputStreamMessageElement elemento
                    = new InputStreamMessageElement(TAG, null, mensaje, null);
           msg.addMessageElement(ESPACIO_NOMBRE, elemento);
           
           System.out.println("Vamos a mandar el mensaje por la tuberia");
           
           /* 
            * Se envía el mensaje JXTA. Se usa una copia del mensaje para
            * evitar errores en la transmisión.
            */
           miBiDiPipe.sendMessage( (Message) msg.clone());
       } catch (Exception e) {
           throw new ExcepcionP2P("Error enviando en el cliente de B2B", e);
       }
    }
    
    public InputStream recibir() throws ExcepcionP2P {
        flujoRecibido = null;
        /*
         * Se espera como máximo 10 intervalos de 6 segundos para recibir un 
         * mensaje. El método pipeMsgEvent será el que reciba el mensaje y le
         * de valor a la variable flujoRecibido.
         */
        for ( int i=0; (i<10) && (flujoRecibido == null) ; i++ ) {
            try {
                Thread.sleep(6*1000);
            } catch (InterruptedException ie) {   }
        }
        
        if ( flujoRecibido == null ) {
            /*
             * Si no se ha recibido nada tras un minuto de espera, se lanza
             * la excepción.
             */
            throw new ExcepcionP2P("No se ha recibido ninguna respuesta en el plazo establecido");
        }
        //Si llega aquí, es que se ha recibido algo.
        miBiDiPipe = null;
        return flujoRecibido;
    }
    
    public void pipeMsgEvent(PipeMsgEvent evento) {
        //Se obtiene el mensaje JXTA
        Message mensaje = evento.getMessage();
        //Se obtienen los datos encapsulados en el mensaje JXTA
        MessageElement elemento = mensaje.getMessageElement(ESPACIO_NOMBRE, 
                                                            TAG);
        flujoRecibido = new ByteArrayInputStream( elemento.getBytes(false) );
    }
    

}
