/*
 * Fichero:     PeticionCXML.java
 * Fecha:       20/10/06
 * Autor:       Alvaro Sarmiento losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase PeticionCXML, que representa a un documento
 *              de contenido cXML de petición.
 *
 * 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.xml.cxml;

import java.util.List;
import org.jdom.*;

import com.pfc.lib.utiles.FactoriaAleatoria;
import com.pfc.lib.utiles.FechaISO8601;

/**
 * Clase que representa un documento de petición basado en cXML. <br>
 * En el modelo de intercambio de mensajes de comercio eléctronico
 * propuesto por cXML, los clientes envían peticiones a los concentradores
 * de comercio, como por ejemplo peticiones de compra, de perfil, etc. 
 * Esta clase puede implementar cualquier tipo de petición cXML, aunque
 * tiene implementado constantes de un subconjunto de tipos de peticiones:
 * OrderRequest, ProfileRequest, SubscriptionListRequest, 
 * SubscriptionContentRequest, SupplierListRequest, SupplierDataRequest.
 * 
 * @author  Alvaro Sarmiento Losada
 */
public class PeticionCXML extends DocumentoCXML {
    
    /** 
     * Constante que representa el tipo de petición cXML "ProfileRequest"
     * (petición de perfil).
     */
    public final static String PETICION_PERFIL = "ProfileRequest";
    
    /** 
     * Constante que representa el tipo de petición cXML "OrderRequest"
     * (petición de orden de compra).
     */
    public final static String PETICION_COMPRA = "OrderRequest";
    
    /** 
     * Constante que representa el tipo de petición cXML 
     * "SubscriptionListRequest" (petición de lista de catálogos).
     */
    public final static String PETICION_LISTA_CATALOGOS = "SubscriptionListRequest";

    /** 
     * Constante que representa el tipo de petición cXML 
     * "SubscriptionContentRequest" (petición de contenido de catálogo).
     */
    public final static String PETICION_CATALOGO = "SubscriptionContentRequest";
    
    /** 
     * Constante que representa el tipo de petición cXML 
     * "SupplierListRequest" (petición de lista de proveedores).
     */
    public final static String PETICION_LISTA_PROVEEDORES = "SupplierListRequest";
    
    /** 
     * Constante que representa el tipo de petición cXML 
     * "SupplierDataRequest" (petición de datos de proveedor).
     */
    public final static String PETICION_PROVEEDOR = "SupplierDataRequest";
    
    /**
     * Constante que representa un dominio de identidad de los credenciales
     * cXML por defecto.
     */
    public final static String DOMINIO_DE_IDENTIDAD = "UsuarioID";

    /**
     * Constante que representa el agente software usado para enviar esta
     * petición cXML por defecto.
     */
    protected final static String AGENTE = "Agente desconocido";
    
    /** 
     * Almacena si ya ha sido establecido un elemento de petición en el
     * elemento "Request".
     */
    private boolean establecido = false;
    
    /** 
     * Constructor básico de la clase. Crea una nueva instancia de esta
     * clase creando una nueva estructura XML de petición cXML.
     */
    public PeticionCXML() {
        super(TIPO_CXML);
        establecerEstructura();
    }
    
    /**
     * Crea una nueva instancia de una <code>PeticionCXML</code> del tipo
     * especificado.
     *
     * @param tipo el tipo de petición cXML que se desea construir.
     */
    public PeticionCXML(String tipo) {
        this();
        setTipoPeticion(tipo);
    }
    
    /**
     * Crea una nueva instancia de una <code>PeticionCXML</code> de tipo
     * y contenido el especificado por un <code>Element</code> JDOM.
     *
     * @param tipo el <code>Element</code> JDOM que se desea poner como
     *             cuerpo y tipo de la petición.
     */
    public PeticionCXML(Element tipo) {
        this();
        setTipoPeticion(tipo);
    }
    
    /**
     * Devuelve un elemento JDOM con el tipo de petición cXML que representa
     * este objeto. El elemento JDOM devuelto incluye todos los nodos que 
     * cuelgan del nodo tipo de petición.
     *
     * @return un objeto <code>Element</code> JDOm con el contenido de
     *         la petición cXML.
     */
    public Element getTipoPeticion() {
        Element request = getElemento("cXML/Request");
        //Se obtiene una lista con todos los nodos que cuelgan del nodo Request
        List lista = request.getChildren();
        //Se escoge el primer nodo (aunque sólo debe de haber uno en la lista)
        return (Element) lista.get(0);
    }

    /**
     * Devuelve el tipo de petición cXML que representa este objeto.
     *
     * @return una cadena <code>String</code> con el tipo de petición cXML
     *         de este objeto.
     */
    public String getTipoPeticionEnString() {
        return getTipoPeticion().getName();
    }
    
    /**
     * Establece el tipo de petición cXML de este objeto. Este método sólo
     * añade una etiqueta XML con el nombre especificado por 
     * <code>tipo</code>.
     *
     * @param tipo el tipo de petición cXML que se desea establecer.
     */
    public void setTipoPeticion(String tipo) {
        Element peticion = getElemento("cXML/Request");
        Element tipoPeticion = new Element(tipo);
        
        peticion.addContent(tipoPeticion);
    }
    
    /**
     * Establece el tipo y contenido de la petición cXML que representa
     * este objeto mediante el <code>Element</code> especificado. Si  
     * este método es llamado dos o más veces, sólo tendrá efecto la primera
     * vez que fue invocado, para evitar la adición de múltiples elementos
     * "Tipo"-Request al elemento "Request".
     * 
     * @param tipo el elemento JDOM que se quiere añadir como contenido
     *             de la petición cXML, colgando del nodo con etiqueta
     *             "Request".
     */
    public void setTipoPeticion(Element tipo) {
       if ( !establecido ) { 
            Element peticion = getElemento("cXML/Request");
            peticion.addContent(tipo);
            establecido = true;
        } else {
            /* Ya ha sido añadido un elemento, este no se añade */
        }
    }
    
    /**
     * Devuelve la identidad del elemento "From" de esta petición cXML.
     *
     * @return una cadena <code>String</code> con el valor del elemento 
     *         "Identity" contenido en el elemento "From".
     */
    public String getIdentidadFrom() {
        Element identidad = getElemento("cXML/Header/From/Credential/Identity");
        return identidad.getText();
    }

    /**
     * Establece la identidad del elemento "From" de esta petición cXML.
     *
     * @param id una cadena <code>String</code> con el valor del elemento 
     *           "Identity" contenido en el elemento "From" para esta 
     *           petición cXML.
     */
    public void setIdentidadFrom(String id) {
        Element identidad = getElemento("cXML/Header/From/Credential/Identity");
        identidad.setText(id);        
    }

    /**
     * Devuelve el valor del atributo "Domain" del elemento "Credential" 
     * en el elemento "From" de esta petición cXML.
     *
     * @return una cadena <code>String</code> con el valor del atributo 
     *         dominio de credencial contenido en el elemento "From".
     */
    public String getDominioCredencialFrom() {
        Element credencial = getElemento("cXML/Header/From/Credential");
        return credencial.getAttributeValue("domain", (String) null);
    }

    /**
     * Establece el valor del atributo "Domain" del elemento "Credential" 
     * en el elemento "From" de esta petición cXML.
     *
     * @param  una cadena <code>String</code> con el valor del atributo 
     *         dominio de credencial del elemento "From", o <code>null</code>
     *         para establecer el valor por defecto dado por 
     *         <code>DOMINIO_DE_IDENTIDAD</code>.
     */
    public void setDominioCredencialFrom(String valor) {
        Element credencial = getElemento("cXML/Header/From/Credential");
        if (valor != null) {
            credencial.setAttribute("domain", valor);
        } else {
            //Se establece un valor por defecto
            credencial.setAttribute("domain", DOMINIO_DE_IDENTIDAD);
        }
    }

    /**
     * Devuelve la identidad del elemento "To" de esta petición cXML.
     *
     * @return una cadena <code>String</code> con el valor del elemento 
     *         "Identity" contenido en el elemento "To".
     */
    public String getIdentidadTo() {
        Element identidad = getElemento("cXML/Header/To/Credential/Identity");
        return identidad.getText();
    }

    /**
     * Establece la identidad del elemento "To" de esta petición cXML.
     *
     * @param id una cadena <code>String</code> con el valor del elemento 
     *           "Identity" contenido en el elemento "To" para esta 
     *           petición cXML.
     */
    public void setIdentidadTo(String id) {
        Element identidad = getElemento("cXML/Header/To/Credential/Identity");
        identidad.setText(id);                
    }

    /**
     * Devuelve el valor del atributo "Domain" del elemento "Credential" 
     * en el elemento "To" de esta petición cXML.
     *
     * @return una cadena <code>String</code> con el valor del atributo 
     *         dominio de credencial contenido en el elemento "To".
     */    
    public String getDominioCredencialTo() {
        Element credencial = getElemento("cXML/Header/To/Credential");
        return credencial.getAttributeValue("domain", (String) null);
    }

    /**
     * Establece el valor del atributo "Domain" del elemento "Credential" 
     * en el elemento "To" de esta petición cXML.
     *
     * @param  una cadena <code>String</code> con el valor del atributo 
     *         dominio de credencial del elemento "To", o <code>null</code>
     *         para establecer el valor por defecto dado por 
     *         <code>DOMINIO_DE_IDENTIDAD</code>.
     */
    public void setDominioCredencialTo(String valor) {
        Element credencial = getElemento("cXML/Header/To/Credential");
        if (valor != null) {
            credencial.setAttribute("domain", valor);
        } else {
            //Se establece un valor por defecto
            credencial.setAttribute("domain", DOMINIO_DE_IDENTIDAD);
        }
    }

    /**
     * Devuelve la identidad del elemento "Sender" de esta petición cXML.
     *
     * @return una cadena <code>String</code> con el valor del elemento 
     *         "Identity" contenido en el elemento "Sender".
     */
    public String getIdentidadSender() {
        Element identidad = getElemento("cXML/Header/Sender/Credential/Identity");
        return identidad.getText();        
    }

    /**
     * Establece la identidad del elemento "Sender" de esta petición cXML.
     *
     * @param id una cadena <code>String</code> con el valor del elemento 
     *           "Identity" contenido en el elemento "Sender" para esta 
     *           petición cXML.
     */
    public void setIdentidadSender(String id) {
        Element identidad = getElemento("cXML/Header/Sender/Credential/Identity");
        identidad.setText(id);
    }

    /**
     * Devuelve el valor del atributo "Domain" del elemento "Credential" 
     * en el elemento "Sender" de esta petición cXML.
     *
     * @return una cadena <code>String</code> con el valor del atributo 
     *         dominio de credencial contenido en el elemento "Sender".
     */
    public String getDominioCredencialSender() {
        Element credencial = getElemento("cXML/Header/Sender/Credential");
        return credencial.getAttributeValue("domain", (String) null);
    }

    /**
     * Establece el valor del atributo "Domain" del elemento "Credential" 
     * en el elemento "Sender" de esta petición cXML.
     *
     * @param  una cadena <code>String</code> con el valor del atributo 
     *         dominio de credencial del elemento "Sender", o <code>null</code>
     *         para establecer el valor por defecto dado por 
     *         <code>DOMINIO_DE_IDENTIDAD</code>.
     */
    public void setDominioCredencialSender(String valor) {
        Element credencial = getElemento("cXML/Header/Sender/Credential");
        if (valor != null) {
            credencial.setAttribute("domain", valor);
        } else {
            //Se establece un valor por defecto
            credencial.setAttribute("domain", DOMINIO_DE_IDENTIDAD);
        }
    }

    /**
     * Devuelve el valor del atributo "SharedSecret" del elemento "Credential"
     * en el elemento "Sender" de esta petición cXML.
     *
     * @return  una cadena <code>String</code> con el valor del atributo
     *          clave del elemento "Sender".
     */
    public String getClaveSender() {
        Element secreto = getElemento("cXML/Header/Sender/Credential/SharedSecret");
        return secreto.getText();                
    }

    /**
     * Establece el valor del atributo "SharedSecret" del elemento "Credential"
     * en el elemento "Sender" de esta petición cXML.
     *
     * @param  una cadena <code>String</code> con el valor del atributo 
     *         clave del elemento "Sender".
     */
    public void setClaveSender(String clave) {
        Element secreto = getElemento("cXML/Header/Sender/Credential/SharedSecret");
        secreto.setText(clave);        
    }

    /**
     * Devuelve el valor del atributo "UserAgent" del elemento "Sender"
     * de esta petición cXML.
     *
     * @return  una cadena <code>String</code> con el valor del atributo
     *          clave del elemento "Sender".
     */
    public String getAgente() {
        Element agenteUsuario = getElemento("cXML/Header/Sender/UserAgent");
        return agenteUsuario.getText();                
    }

    /**
     * Establece el valor del atributo "UserAgent" del elemento "Sender"
     * de esta petición cXML.
     *
     * @param   una cadena <code>String</code> con el valor del atributo
     *          "UserAgente" del elemento "Sender".
     */
    public void setAgente(String agente) {
        Element agenteUsuario = getElemento("cXML/Header/Sender/UserAgent");
        agenteUsuario.setText(agente);        
    }
    
    /**
     * Crea el esqueleto básico de una petición cXML e inicializa algunos
     * valores por defecto usando JDOM.
     */
    private void establecerEstructura() {
        Element raiz = getElementoRaiz();
        
        /*
         * Se construye el árbol JDOM de petición en 3 partes:
         * 1) Se asignan los atributos del elemento raíz cXML
         * 2) Se crea el elemento cabecera (header) del documento
         * 3) Se crea el elemento Request del documento
         */
        
        /*Los documentos de tipo cXML deben llevar los siguientes atributos:*/
        //Se genera un número aleatorio como identificación
        raiz.setAttribute("payloadID", FactoriaAleatoria.cadenaNumericaAleatoria());
        //Se establece el idioma del documento
        raiz.setAttribute("lang","es", Namespace.XML_NAMESPACE);
        //Se genera una fecha ISO8601
        raiz.setAttribute("timestamp", FechaISO8601.fechaISO() );
        
        /* Se crea la cabecera (Header) con los elementos From, To y Sender */
        Element cabecera = new Element("Header");
        Element from = new Element("From");
        Element to = new Element("To");
        Element sender = new Element("Sender");

        //Se construye el elemento From
        Element credencialFrom = new Element("Credential");
        Element identidadFrom = new Element("Identity");        
        credencialFrom.setAttribute("domain", DOMINIO_DE_IDENTIDAD);
        credencialFrom.addContent(identidadFrom);
        from.addContent(credencialFrom);
        
        //Se construye el elemento To
        Element credencialTo = new Element("Credential");
        Element identidadTo = new Element("Identity");
        credencialTo.setAttribute("domain", DOMINIO_DE_IDENTIDAD);
        credencialTo.addContent(identidadTo);
        to.addContent(credencialTo);
        
        //Se construye el elemento Sender
        Element credencialSender = new Element("Credential");
        Element agente = new Element("UserAgent");
        Element identidadSender = new Element("Identity");
        Element secretoSender = new Element("SharedSecret");
        credencialSender.setAttribute("domain", DOMINIO_DE_IDENTIDAD);
        credencialSender.addContent(identidadSender);
        credencialSender.addContent(secretoSender);
        agente.setText(AGENTE);
        sender.addContent(credencialSender);
        sender.addContent(agente);
        
        //Se añaden al elemento Header (cabecera)
        cabecera.addContent(from);
        cabecera.addContent(to);
        cabecera.addContent(sender);
        
        /* Se construye el elemento petición (Request) */
        Element peticion = new Element("Request");
        
        /* Se añaden los elementos cabecera y petición al elemento raiz CXML */
        raiz.addContent(cabecera);        
        raiz.addContent(peticion);               
    }
    
}