/*
 * Fichero:     GrupoDePeersGenerico.java
 * Fecha:       20/10/06
 * Autor:       Alvaro Sarmiento Losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase GrupoDePeersGenerico, que representa a un 
 *              grupo de peers JXTA de propósito general.
 *
 * 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.lib.p2p;


import java.io.IOException;
import java.util.Enumeration;
import net.jxta.discovery.DiscoveryListener;
import net.jxta.discovery.DiscoveryService;
import net.jxta.peer.PeerID;
import net.jxta.peergroup.PeerGroup;
import net.jxta.protocol.PeerAdvertisement;
import net.jxta.protocol.PeerGroupAdvertisement;

/**
 * Implementa a un grupo de peers JXTA de propósito general con métodos de búsqueda de anuncios, basados en el servicio de Descubrimiento JXTA del grupo. <br> Esta clase no puede ser instanciada, ya que sirve de marco de referencia para otras clases que heredarán de ésta y que deben refinar los servicios  prestados.
 * @author   Alvaro Sarmiento Losada
 * @see Pares
 * @see  GrupoDePeers
 */
public abstract class GrupoDePeersGenerico extends Object {
    
    /** 
     * Referencia al propio grupo de peers JXTA, y que proporciona los
      * servicios básicos usados por esta clase.
     */
    protected PeerGroup miGrupo;
    
    /** 
     * Referencia al grupo de peers por defecto
     */
    public PeerGroup netpg;
    
    /** 
     * Valor por defecto del número de intentos de búsqueda de cualquier tipo
     * de anuncios.
     */
    protected final int INTENTOS = 10;

    /** 
     * Valor por defecto del intervalo de tiempo entre intentos de búsqueda 
     * de anuncios en milisegundos.
     */
    protected final int TIEMPO = 6*1000;
    
    /** Almacena el número de intentos de búsqueda de anuncios. */
    private int intentos;
    
    /** 
     * Almacena el intervalo de tiempo entre intentos de búsqueda 
     * de anuncios.
     */
    private int tiempo;
    
    /**
     * Constructor básico de la clase. Crea una nueva instancia de esta clase.
     */
    protected GrupoDePeersGenerico() {
    	netpg=null;
        miGrupo  = null;
        intentos = INTENTOS;
        tiempo   = TIEMPO;
    }
    
    /**
     * Crea una nueva instancia de <code>GrupoDePeersGenerico</code> a partir
     * de un grupo de peers JXTA especificado.
     *
     * @param grupo el grupo de Peers JXTA al que se desea pertenecer.
     */
    protected GrupoDePeersGenerico(PeerGroup grupo) {
        this();
        miGrupo = grupo;
    }
    
    /**
	 * Devuelve el objeto <code>PeerGroup</code> de JXTA asociado a este  objeto.
	 * @return  el grupo de peers <code>PeerGroup</code> representado por este   objeto.
	 * @uml.property  name="miGrupo"
	 */
    public PeerGroup getMiGrupo() {
        return miGrupo;
    }
    
    public PeerID getMiPeer(){
    	return miGrupo.getPeerID();
    }
    
    /**
     * Devuelve un objeto <code>PeerGroupAdvertisement</code> del grupo de 
     * peers representado por este objeto.
     *
     * return el anuncio de grupo de peers de este objeto.
     */
    public PeerGroupAdvertisement getAnuncioMiGrupo() {
        return miGrupo.getPeerGroupAdvertisement();
    }

    /**
     * Devuelve el nombre del grupo de peers representado por este objeto.
     *
     * return el nombre del grupo de peers de este objeto.
     */
    public String getNombreMiGrupo() {
        return miGrupo.getPeerGroupName();
    }

    /**
     * Devuelve un objeto <code>PeerAdvertisement</code> del propio peer.
     *
     * return el anuncio de peer de este objeto.
     */
    public PeerAdvertisement getAnuncioMiPeer() {
        return miGrupo.getPeerAdvertisement();
    }

    /**
     * Devuelve el nombre del peer representado por este objeto.
     *
     * return el nombre del peer de este objeto.
     */
    public String getNombreMiPeer() {
        return miGrupo.getPeerName();    
    }
    
    /**
     * Establece el número de intentos e intervalo de tiempo entre ellos que
     * usará este objeto para realizar las búsquedas en la red JXTA de
     * anuncios de servicios y peers. Si se especifica algún valor a
     * negativo, se establece a su valor por defecto dado por las 
     * constantes <code>INTENTOS</code> y <code>TIEMPO</code>.
     *
     * @param intentos el número de intentos máximo
     * @param tiempo   el intervalo de tiempo entre intentos en milisegundos
     */
    public void setIntervaloBusqueda(int intentos, int tiempo) {
        this.intentos = ( (intentos < 0) ? INTENTOS : intentos );
        this.tiempo   = ( (tiempo   < 0) ? TIEMPO   : tiempo );
    }
    
    /**
     * Inicia una búsqueda de anuncios de peers por la red JXTA, limitando
     * la búsqueda a los anuncios con el <code>valor</code> del
     * <code>atributo</code> especificados. Si son <code>null</code>, la 
     * búsqueda es genérica. Los resultados de la búsqueda se almacenan
     * en el caché JXTA.
     *
     * @param atributo el nombre del atributo por el que se limitará la 
     *                 búsqueda de anuncios en la red JXTA.
     * @param atributo el valor del atributo por el que se limitará la 
     *                 búsqueda de anuncios en la red JXTA.
     * @see            #setIntervaloBusqueda(int, int)
     * @see            #descubrirPeersDelCache(String, String)
     */
    public void descubrirPeers(String atributo, String valor) {
        descubrir(null, DiscoveryService.PEER, atributo, valor, null);     
    }

    /**
     * Inicia una búsqueda de anuncios de servicio de un determinado peer 
     * por la red JXTA, limitando la búsqueda a los anuncios con el <code>valor</code> del
     * <code>atributo</code> especificados. Si son <code>null</code>, la 
     * búsqueda es genérica.Los resultados de la búsqueda se almacenan
     * en el caché JXTA.
     *
     * @param peerID   cadena <code>String</code> con el identificador JXTA
     *                 del peer del cual se quiere descubrir sus servicios.
     * @param atributo el nombre del atributo por el que se limitará la 
     *                 búsqueda de anuncios en la red JXTA.
     * @param atributo el valor del atributo por el que se limitará la 
     *                 búsqueda de anuncios en la red JXTA.
     * @see            #setIntervaloBusqueda(int, int)
     * @see            #descubrirAnunciosServicioDelCache(String, String)
     */    
    public void descubrirAnunciosServicio(String peerID, 
                                          String atributo, 
                                          String valor) {
        descubrir(peerID, DiscoveryService.ADV, atributo, valor, null);
    }

    /**
     * Inicia una búsqueda de anuncios de peers en el caché JXTA, limitando
     * la búsqueda a los anuncios con el <code>valor</code> del
     * <code>atributo</code> especificados. Si son <code>null</code>, la 
     * búsqueda es genérica. 
     *
     * @param atributo el nombre del atributo por el que se limitará la 
     *                 búsqueda de anuncios en el caché JXTA.
     * @param atributo el valor del atributo por el que se limitará la 
     *                 búsqueda de anuncios en el caché JXTA.
     * @return         un objeto <code>Enumeration</code> con la lista de
     *                 <code>PeerAdvertisement</code> encontrados.
     * @see            #descubrirPeers(String, String)
     */
    public Enumeration descubrirPeersDelCache(String atributo, String valor) {
        return descubrirDelCache(DiscoveryService.PEER, atributo, valor);
    }

    /**
     * Inicia una búsqueda de anuncios de servicio por el caché JXTA,
     * limitando la búsqueda a los anuncios con el <code>valor</code> del
     * <code>atributo</code> especificados. Si son <code>null</code>, la 
     * búsqueda es genérica.
     *
     * @param atributo el nombre del atributo por el que se limitará la 
     *                 búsqueda de anuncios en la red JXTA.
     * @param atributo el valor del atributo por el que se limitará la 
     *                 búsqueda de anuncios en la red JXTA.
     * @return         un objeto <code>Enumeration</code> con la lista de
     *                 <code>ModuleSpecAdvertisement</code> encontrados.
     * @see            #descubrirAnunciosServicio(String, String)
     */    
    public Enumeration descubrirAnunciosServicioDelCache(String atributo, 
                                                         String valor) {
        return descubrirDelCache(DiscoveryService.ADV, atributo, valor);
    }
    
    /**
     * Realiza una búsqueda de anuncios de un tipo especificado en la red
     * JXTA, limitándola a anuncios con el valor especificado por 
     * <code>valor</code> de un atributo especificado <code>atributo</code>.
     * Se puede también limitar la búsqueda a un sólo peer.
     * El parámetro <code>tipo</code> está referenciado en constantes de la
     * clase JXTA <code>DiscoveryService</code>.
     * 
     * @param  peerID        el identificador del peer si se quiere limitar la 
     *                       búsqueda a ese peer sólo. Para hacer una búsqueda
     *                       genérica, este parámetro debe ser <code>null</code>
     * @param  tipo          el tipo de anuncio que se desea buscar.
     * @param  atributo      el nombre del atributo del anuncio para limitar 
     *                       la búsqueda.
     * @param  valor         el valor del atributo para limitar la búsqueda.
     * @param  discoListener un objeto <code>DiscoveryListener</code> si se 
     *                       quiere capturar cada respuesta ante una petición
     *                       de búsqueda de anuncios.
     * @return               un objeto <code>Enumeration</code> con todos los
     *                       anuncios encontrados.
     */
    protected void descubrir(String peerID, 
                             int tipo, 
                             String atributo, 
                             String valor, 
                             DiscoveryListener discoListener) {
        //Se crea un objeto de servicio de descubrimiento
        DiscoveryService discoSvc = miGrupo.getDiscoveryService();
        /*
         * Se realizan varias búsquedas de anuncios, para asegurarse de que 
         * se da tiempo a los otros peers de responder.
         */
        for (int i=0; i < intentos ; i++) {
            //Se inicia la búsqueda
            discoSvc.getRemoteAdvertisements(peerID, 
                                             tipo, 
                                             atributo, 
                                             valor, 
                                             10, 
                                             discoListener);
            //Esperamos el intervalo de tiempo entre intentos
            try {
                Thread.sleep(tiempo);
            } catch(InterruptedException ie) {  }
        }
    }
    
    /**
     * Realiza una búsqueda de anuncios de un tipo especificado en el caché
     * JXTA, limitándola a anuncios con el valor especificado por 
     * <code>valor</code> de un atributo especificado <code>atributo</code>.
     * El parámetro <code>tipo</code> está referenciado en constantes de la
     * clase JXTA <code>DiscoveryService</code>.
     *
     * @param  tipo     el tipo de anuncio que se desea buscar.
     * @param  atributo el nombre del atributo del anuncio para limitar 
     *                  la búsqueda.
     * @param  valor    el valor del atributo para limitar la búsqueda.
     * @return          un objeto <code>Enumeration</code> con todos los
     *                  anuncios encontrados.
     */
    protected Enumeration descubrirDelCache(int tipo, 
                                            String atributo, 
                                            String valor) {
        Enumeration enumerador = null;
        //Se crea un objeto de servicio de descubrimiento        
        DiscoveryService disco = miGrupo.getDiscoveryService();

        try {
            //Realizamos un búsqueda en el caché
            enumerador = disco.getLocalAdvertisements(tipo, atributo, valor);
        } catch (IOException ioe) {
            //Ha ocurrido un error al mirar el caché.
            enumerador = null;
        }
        return enumerador;
    }
    
}