/*
 * Fichero:     RespuestaCXML.java
 * Fecha:       20/10/06
 * Autor:       Alvaro Sarmiento losada 
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase RespuestaCXML, que representa a un documento
 *              de contenido cXML de respuesta.
 *
 * 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 respuesta basado en cXML. <br>
 * En el modelo de intercambio de mensajes de comercio eléctronico
 * propuesto por cXML, los concentradores o servidores de comercio
 * eléctronico envían respuestas cXML ante las peticiones de los clientes.
 * Esta clase puede implementar cualquier tipo de respuesta cXML, aunque
 * tiene implementado constantes de un subconjunto de tipos de peticiones:
 * OrderResponse, ProfileResponse, SubscriptionListResponse, 
 * SubscriptionContentResponse, SupplierListResponse, SupplierDataResponse.
 * 
 * @author  Alvaro Sarmiento Losada
 */
public class RespuestaCXML extends DocumentoCXML {
    
    /** 
     * Constante que representa el tipo de respuesta cXML "ProfileResponse"
     * (respuesta de perfil).
     */
    public final static String RESPUESTA_PERFIL = "ProfileResponse";
    
    /** 
     * Constante que representa el tipo de respuesta cXML "OrderResponse"
     * (respuesta de orden de compra).
     */
    public final static String RESPUESTA_COMPRA = "OrderResponse";
    
    /** 
     * Constante que representa el tipo de respuesta cXML 
     * "SubscriptionListResponse" (respuesta de lista de catálogos).
     */
    public final static String RESPUESTA_LISTA_CATALOGOS = "SubscriptionListResponse";
    
    /** 
     * Constante que representa el tipo de respuesta cXML 
     * "SubscriptionContentResponse" (respuesta de contenido de catálogo).
     */
    public final static String RESPUESTA_CATALOGO = "SubscriptionContentResponse";
    
    /** 
     * Constante que representa el tipo de respuesta cXML 
     * "SupplierListResponse" (respuesta de lista de proveedores).
     */
    public final static String RESPUESTA_LISTA_PROVEEDORES = "SupplierListResponse";
    
    /** 
     * Constante que representa el tipo de respuesta cXML 
     * "SupplierDataResponse" (respuesta de datos de proveedor).
     */
    public final static String RESPUESTA_PROVEEDOR = "SupplierDataResponse";
    
    /** 
     * Almacena si ya ha sido establecido un elemento de respuesta en el
     * elemento "Response".
     */
    private boolean establecido = false;
    
    /** 
     * Constructor básico de la clase. Crea una nueva instancia de esta
     * clase creando una nueva estructura XML de respuesta cXML.
     */
    public RespuestaCXML() {
        super(TIPO_CXML);
        establecerEstructura();
    }

    /**
     * Crea una nueva instancia de una <code>RespuestaCXML</code> e 
     * inicializa el elemento "Status" de la respuesta cXML al valor
     * especificado. Este método está especialmente implementado para
     * crear una nueva OrderResponse, puesto que éste tipo de documento
     * cXML sólo requiere como respuesta el elemento Status.
     *
     * @param codigo el valor del atributo "code" del elemento "Status" de la
     *               respuesta cXML.
     * @param texto  el valor del atributo "text" del elemento "Status" de la
     *               respuesta cXML.
     * @param descr  el valor del elemento "Status" como descripción específica
     *               del código.
     */
    public RespuestaCXML(String codigo, String texto, String descr) {
        this();
        setStatus(codigo, texto, descr);
    }

    /**
     * Devuelve un elemento JDOM con el tipo de respuesta cXML que representa
     * este objeto. El elemento JDOM devuelto incluye todos los nodos que 
     * cuelgan del nodo tipo de respuesta
     *
     * @return un objeto <code>Element</code> JDOm con el contenido de
     *         la respuesta cXML. Devuelve <code>null</code> si es una 
     *         OrderResponse.
     */    
    public Element getTipoRespuesta() {
        Element respuesta = getElemento("cXML/Response");
        //Se obtiene una lista con todos los nodos que cuelgan del nodo Response
        List lista = respuesta.getChildren();

        /*
         * Un elemento Response debe tener obligatoriamente un elemento
         * Status, y puede tener o no un elemento "Tipo"-Response. No lo tendrá
         * si es una OrderResponse. Se comprueba que la lista de elementos
         * colgantes de Response tenga al menos 2 elementos; si no, es una 
         * OrderResponse y se devuelve null.
         */
        return ( (lista.size() > 1) ? ((Element) lista.get(1)) 
                                    : null );
    }
    
    /**
     * Devuelve el tipo de respuesta cXML que representa este objeto.
     *
     * @return una cadena <code>String</code> con el tipo de respuesta cXML
     *         de este objeto.
     */    
    public String getTipoRespuestaEnString() {
        Element respuesta = getTipoRespuesta();
        /*
         * Si el elemento Response no contiene ningún tipo de respuesta,
         * la respuesta es de tipo OrderRequest. En el otro caso, se devuelve
         * el tipo de la respuesta cXML.
         */
        return ( (respuesta == null) ? RESPUESTA_COMPRA 
                                     : respuesta.getName() );
    }
    
    /**
     * Establece el tipo y contenido de la respuesta 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"-Response al elemento "Response".
     * 
     * @param tipo el elemento JDOM que se quiere añadir como contenido
     *             de la respuesta cXML, colgando del nodo con etiqueta
     *             "Response".
     */
    public void setTipoRespuesta(Element tipo) {
        if ( !establecido ) {
            Element respuesta = getElemento("cXML/Response");
            respuesta.addContent(tipo);
            establecido = true;
        } else {
            /* Ya ha sido añadido un elemento, este no se añade */
        }
    }
    
    /**
     * Devuelve el valor del atributo "code" del elemento "Status" de
     * esta <code>RespuestaCXML</code>.
     *
     * @return una cadena <code>String</code> con el valor del código
     *         de status de esta respuesta cXML.
     */
    public String getCodigoStatus() {
        Element status = getElemento("cXML/Response/Status");
        return status.getAttributeValue("code");
    }

    /**
     * Devuelve el valor del atributo "text" del elemento "Status" de
     * esta <code>RespuestaCXML</code>, que representa un valor canónico
     * de código HTTP.
     *
     * @return una cadena <code>String</code> con el valor del texto
     *         de status de esta respuesta cXML.
     */
    public String getTextoStatus() {
        Element status = getElemento("cXML/Response/Status");
        return status.getAttributeValue("text");
    }

    
    /**
     * Devuelve el valor del elemento "Status" de esta 
     * <code>RespuestaCXML</code>, que es una explicación específica
     * del error ocurrido.
     *
     * @return una cadena <code>String</code> con el valor del texto
     *         específico de status de esta respuesta cXML.
     */
    public String getDescripcionStatus() {
        return getElemento("cXML/Response/Status").getText();
    }
    
    
    /**
     * Establece el valor de los atributos "code" y "text" del elemento
     * "Status" de esta <code>RespuestaCXML</code>.
     *
     * @param una cadena <code>String</code> con el valor del código
     *        de status de esta respuesta cXML.
     * @param una cadena <code>String</code> con el valor del texto
     *        de status de esta respuesta cXML.
     * @param una cadena <code>String</code> con el valor del texto
     *        específico del elemento Status de la respuesta cXML.
     */
    public void setStatus(String codigo, String texto, String descr) {
        Element status = getElemento("cXML/Response/Status");        
        status.setAttribute("code", codigo);
        status.setAttribute("text", texto);
        status.setText(descr);
    }

    /**
     * Crea el esqueleto básico de una respuesta cXML e inicializa algunos
     * valores por defecto usando JDOM.
     */
    protected void establecerEstructura() {
        Element raiz = getElementoRaiz();
        
        /*
         * Se construye el árbol JDOM de respuesta en 2 partes:
         * 1) Se asignan los atributos del elemento raíz cXML
         * 2) Se crea el elemento Response 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 construye el elemento Response */
        Element respuesta = new Element("Response");
        //Se construye el elemento status y se añade al elemento Response
        Element status = new Element("Status");
        status.setAttribute("code","");
        status.setAttribute("text","");
        respuesta.addContent(status);

        /*Se añade el elemento Response al elemento CXML */
        raiz.addContent(respuesta);                       
    }
}