/*
 * Fichero:     ServicioCXML.java
 * Fecha:       25/11/2006
 * Autor:       Alvaro Sarmiento Losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase ServicioCXML, que representa a un servidor
 *              que acepta peticiones cXML y genera respuestas cXML,
 *              basándose en datos contenidos en determinados directorios
 *              fijados de antemano. 
 *
 * 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.cxml;

import com.pfc.lib.utiles.FechaISO8601;
import com.pfc.lib.utiles.Log;
import com.pfc.lib.xml.DocumentoXML;
import com.pfc.lib.xml.ExcepcionMensajeXML;
import com.pfc.lib.xml.MensajeXML;
import com.pfc.lib.xml.cxml.PeticionCXML;
import com.pfc.lib.xml.cxml.RespuestaCXML;
import com.pfc.ventanas.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.ListIterator;
import org.jdom.Element;
import com.pfc.lib.utiles.*;

/**
 * Implementa un servidor (manejador) de peticiones cXML que genera repuestas también cXML. Este servidor cXML recibe y envía peticiones/respuestas encapsuladas en mensajes <code>MensajeXML</code>. 
 * @author   Alvaro Sarmiento Losada
 * @see  CodigosStatusServicioCXML
 */
public class ServicioCXML extends Object {
    
    /** 
     * El directorio donde se guardan las órdenes de compra recibidas para
     * un posible procesado posterior.
     */
    public static final String DIRECTORIO_ORDENES_COMPRA = "./ordenescompra/";
    
    /** 
     * El nombre del archivo que será usado como log por este servidor para
     * anotar eventos notables.
     */
    public static final String ARCHIVO_LOG = "servicioComercioP2P";

    
    /**
     * Constante que define el nombre de la operación "Petición de perfil" y
     * que está soportada por este servidor.
     */
    private static final String OPERACION_PERFIL = "ProfileRequest";

    /**
     * Constante que define el nombre de la operación "Orden de compra" y
     * que está soportada por este servidor.
     */
    private static final String OPERACION_COMPRA = "OrderRequest";

    
    /**
     * Define una array con todos los nombres de las operaciones de comercio
     * electrónico cXML soportadas por este servidor.
     */
    private static final String[] OPERACIONES = { OPERACION_PERFIL, 
                                                  OPERACION_COMPRA };
                                                 
     
    
    public final static String NUESTROSPRODUCTOS= "nuestrosproductos.txt";
    /** Almacena la fecha en la que este servidor se puso en marcha. */
    private static String fechaComienzoEjecucion;
    
    /** Almacena el nombre dado a este servidor. */
    private static String identidadServidor;
    
    /** Log o bitácora usada por este servidor para apuntar eventos notables */
    private Log log;
    
    /** Indica si se ha solicitado una parada de la ejecución del servicio */
    private boolean parar;
    
    
    public static final String CLAVES = "C:/Documents and Settings/Antonio/Mis documentos/cosas alvaro/proyecto_alvaro/claves.xml.txt";
    /**
     * Constructor básico de la clase. Crea una nueva instacia de un 
     * servidor de comercio electrónico basado en cXML.
     */
    private ServicioCXML() {
        // Se registra una fecha ISO8601 como de inicio.
        fechaComienzoEjecucion = FechaISO8601.fechaISO();
        // Se abre el archivo de log.
        log = new Log(ARCHIVO_LOG);
        log.iniciar();
    }
    
    /**
     * Crea una nueva instancia de un servidor de comercio electrónico
     * basado en cXML y le asigna el nombre especificado.
     *
     * @param identidad el nombre de este servidor cXML, por el que se 
     *                  reconocerá en el elemento "Identity" de la petición
     *                  cXML recibida.
     */
    public ServicioCXML(String identidad) {
        this();
        identidadServidor = identidad;
    }
    
    /**
     * Arranca la ejecución del servicio de comercio electrónico basado en
     * cXML. El servicio se ejecutará hasta que se llame expresamente al
     * método <code>pararServicio()</code>.
     */
    public void ejecutarServicio() {
        parar = false;
        gestorVentanas gestor=new gestorVentanas();
        Log log=new Log("log_aplicacion");
        
        /*
         * La estructura de este método de procesado de peticiones y respuestas
         * cXML es la siguiente:
         * 
         *  WHILE parar == FALSE 
         *      recibir una nueva petición
         *      procesar la petición y generar la respuesta
         *      enviar la respuesta
         *  END WHILE
         *
         *  Cada uno de los 3 pasos de cada iteración se detalla más adelante
         */ 
        
        while ( !parar ) {
            /*
             * Se crea los documentos XML de petición recibida y la
             * respuesta que se enviará.
             */
            PeticionCXML peticion = new PeticionCXML();
            RespuestaCXML respuesta = new RespuestaCXML();

            /* Se crea un objeto MensajeXML para recibir un nuevo mensaje */
            MensajeXML mensajePeticion = new MensajeXML();            

            try {
                //Se pone a la escucha para recibir mensajes XML
                mensajePeticion.recibirMensajeXML();
                //Si llega aquí, es que se ha recibido un mensaje nuevo
                System.out.println("Se ha recibido exitosamente un mensaje");
            } catch (ExcepcionMensajeXML emx) {
                //Se ha recibido algo, pero con algún tipo de error
                System.out.println("Se ha generado una excepcion al recibir un mensaje");
            }
            //Se obtiene el documento XML asociado al mensaje recibido
            DocumentoXML documentoPeticion = mensajePeticion.getDocumentoXML();

            /* 
             * Se inicia el procesado de la petición cXML recibida. El 
             * algoritmo seguido en líneas generales es el siguiente:
             * 
             * IF peticion != null THEN 
             *   IF peticion es valida THEN
             *     IF destinatario es este servidor THEN
             *        CASE peticion OF
             *          perfil            : procesar y generar respuesta 
             *          compra            : procesar y generar respuesta
             *          lista catálogos   : procesar y generar respuesta
             *          catálogo          : procesar y generar respuesta
             *          lista proveedores : procesar y generar respuesta
             *          datos proveedor   : procesar y generar respuesta
             *          OTHERWISE         : error operación no implementada
             *        END
             *     ELSE error petición incorrecta
             *   ELSE error petición no válida
             * ELSE error petición incorrecta
             * 
             *  
             */

            /* Se comprueba que la petición recibida existe */
            if( documentoPeticion != null ) {
                
                /* Se comprueba que la petición recibida es válida */
                if ( documentoPeticion.esValido() == true ) {
                    /*
                     * Ya es seguro que es una petición cXML. Se construye pues
                     * un objeto PeticionCXML apropiado para manejar la petición
                     */
                    peticion.setDocumento( documentoPeticion.getDocumento() );
                    System.out.println(peticion);
                    
                    /* 
                     * Se comprueba que ese servidor es el destinatario de
                     * la petición.
                     */
                    String destinatario = peticion.getIdentidadTo();
                    if( destinatario.equals(identidadServidor) == true ) {
                        
                        /* 
                         * Se procesa y genera la respuesta dependiendo del
                         * tipo de petición cXML. Esta parte es la
                         * correspondiente al "CASE" del pseudocódigo más 
                         * arriba comentado.
                         */
                        String tipoPeticion = peticion.getTipoPeticionEnString();
                        if ( tipoPeticion.equals(OPERACION_PERFIL) ) {
                            
                            //log.apuntar("Se ha recibido una peticion de Perfil");
                            Element perfil = procesarPeticionPerfil();
                            respuesta.setStatus(
                                     CodigosStatusServicioCXML.CORRECTO_OK[0],
                                     CodigosStatusServicioCXML.CORRECTO_OK[2], 
                                     CodigosStatusServicioCXML.CORRECTO_OK[1]);
                            respuesta.setTipoRespuesta(perfil);
                            
                        } else if ( tipoPeticion.equals(OPERACION_COMPRA) ) {
                            /*
                             * La operación de compra sigue el siguiente
                             * pseudocódigo:
                             * 
                             * IF clave es correcta THEN
                             *   IF aparece informacion pago THEN
                             *     IF procesado es correcto THEN
                             *       generar respuesta correcta
                             *     ELSE error peticion incorrecta
                             *   ELSE error pago
                             * ELSE error autorización credenciales
                             */
                            
                            System.out.println("Se ha recibido una peticion de Compra");

                            /* 
                             * Se comprueba que la clave SharedSecret
                             * proporcionada en el elemento Sender de la
                             * petición cXML coincida con la almacenada por 
                             * este servidor.
                             */
                            String remitente = peticion.getIdentidadSender();
                            System.out.println(remitente);
                            String clave = peticion.getClaveSender();
                            System.out.println(clave);
                            if ( comprobarClave(remitente, clave) == true ) {
                            	
                            	System.out.println("Se han validado las claves");
                                /*
                                 * Se comprueba que el elemento de pago esté 
                                 * incluido en la petición
                                 */
                                Element pago = peticion.getElemento("cXML/Request/OrderRequest/OrderRequestHeader/Payment");
                                if ( pago != null ) {
                                	
                                	Element item= peticion.getElemento("cXML/Request/OrderRequest/ItemOut");
                                	Element id=item.getChild("id");
                                	/*Buscamos el elemnto id y el elemento nombre*/
                                	String iden =id.getText();
                                	/*Comprobamos que el producto que requiere es nuestro*/
                                	boolean comprobacion=comprobarProducto(iden);
                                    /* Se procesa la petición de compra */
                                	if(comprobacion!=false){
                                		
                                		System.out.println("Se ha comprobado el producto");
                                		if ( procesarPeticionCompra(peticion) ) {
                                			//Se genera una respuesta OK sin más
                                			respuesta.setStatus(
                                					CodigosStatusServicioCXML.CORRECTO_OK[0],
                                					CodigosStatusServicioCXML.CORRECTO_OK[2],
                                					CodigosStatusServicioCXML.CORRECTO_OK[1]
                                			);
                                			System.out.println("Se ha procesado y se genera una respuesta");
                                			System.out.println(respuesta);
                                			log.apuntar("se ha realizado la venta de un producto");
                                			
                                		} else {
                                			//El procesado no ha dado buen resultado
                                			respuesta.setStatus( 
                                					CodigosStatusServicioCXML.ERROR_PETICION_INCORRECTA[0], 
                                					CodigosStatusServicioCXML.ERROR_PETICION_INCORRECTA[2], 
                                					CodigosStatusServicioCXML.ERROR_PETICION_INCORRECTA[1]);
                                		}
                                	}else {
                                		/*De momento pongo esto*/
                                		System.out.println("No era nuestro producto");
                                		respuesta.setStatus( 
                                    			CodigosStatusServicioCXML.ERROR_PRODUCTO[0],
                                    			CodigosStatusServicioCXML.ERROR_PRODUCTO[2], 
                                    			CodigosStatusServicioCXML.ERROR_PRODUCTO[1]);
                                	}
                                } else {
                                	respuesta.setStatus( 
                                			CodigosStatusServicioCXML.ERROR_PAGO[0],
                                			CodigosStatusServicioCXML.ERROR_PAGO[2], 
                                			CodigosStatusServicioCXML.ERROR_PAGO[1]);
                                }
                               } else {                
                            	   respuesta.setStatus( 
                                		CodigosStatusServicioCXML.ERROR_CREDENCIALES[0],
                                		CodigosStatusServicioCXML.ERROR_CREDENCIALES[2],
                                		CodigosStatusServicioCXML.ERROR_CREDENCIALES[1]
                                );
                           }
                            
                       } 
            
                    }      
                } 
            }
            //Se crea un objeto MensajeXML para encapsular la respuesta cXML.
            MensajeXML mensajeRespuesta = new MensajeXML();
            //Se establece como contenido del mensaje la respeusta del servidor
            mensajeRespuesta.setDocumentoXML(respuesta);
            //Se envía el mensaje
            try {
                mensajeRespuesta.enviarMensajeXML();
                System.out.println("Se ha enviado exitosamente la Respuesta");
                String decision=gestor.otraOperacion();
                if(decision.equals("si")){} /*No hacemos nada*/
                else{
                	pararServicio();
                }
            } catch (ExcepcionMensajeXML emx) {
                System.out.println("Se ha producido una excepcion al enviar la Respuesta");
            }
        }
       
    }
    
    /**
     * Detiene la ejecución del servidor cXML.
     */
    public void pararServicio() {
        parar = true;
    }
    
    public boolean comprobarProducto(String id){
    	boolean resultado=false;
    	String[] sigo=new String[100];
    	int i=0;
    	try{
    		BufferedReader br = new BufferedReader(new FileReader(NUESTROSPRODUCTOS));
    		String s;                  	    
    		 
    		
    		while ((s = br.readLine())!= null) {
    			sigo[i]=s;
    			i++;
    		}
    	}catch(Exception e){
    		e.printStackTrace(System.out);
    	}
    	boolean seguir=true;

    	
    	for(i=0;sigo[i]!=null && seguir!=false;i++){
    		int j=0;
        	int contador=0;
        	int indice=0;
        	boolean exit=false;
    		String apoyo=new String();
        	String []prueba=new String[50];
    		for(j=0;exit!=true;j++){
				indice=sigo[i].indexOf(":",contador);			
				apoyo=sigo[i].substring(contador,indice);
				System.out.println(apoyo);
				indice++;
				contador=indice;

				if(apoyo.equals("final2"))
					exit=true;
				else
					prueba[j]=apoyo;
			}
    		if(prueba[0].equals(id))
    			seguir=false;
    	}
    	if(seguir!=false){
    		System.out.println("el producto no era nuestro");
    	}else 
    		resultado=true;
    	
    	return resultado;
    }
    
    /**
     * Devuelve si la clave especificada es la correcta para un nombre de
     * remitente dado. Este método busca en el archivo de claves de este 
     * servidor dado por <code>ARCHIVO_CLAVES</code> la clave almacenada
     * para el <code>remitente</code>, y verifica que la clave almacenada
     * y la clave proporcionada por <code>clave</code> sean iguales.
     * 
     * @param  remitente el nombre de la identidad del que envía la petición.
     * @param  clave     la clave que se quiere comprobar.
     * @return           <code>true</code> si la clave almacenada para un 
     *                   remitente coincide con la proporcionada, o si no se 
     *                   tiene almacenada ninguna clave para ese remitente. <br>
     *                   <code>false</code> si no coinciden o si ocurre algún
     *                   error leyendo el archivo de claves.
     */
    private boolean comprobarClave(String remitente, String clave) {
        //Almacena el resultado de la comprobación
        boolean claveCorrecta = true;
        //Se abre el archivo de claves
        File archivo = new File(CLAVES);
              
        try {
            //Se obtiene el XML contenido en el archivo de claves
            DocumentoXML lista = new DocumentoXML(archivo);
            Element raiz = lista.getElementoRaiz();
            /*
             * Se obtiene una lista con todos los elementos "Credential"
             * almacenados en el documento XML del archivo de claves.
             */
            List listaCredenciales = raiz.getChildren("Credential");
            ListIterator iterador = listaCredenciales.listIterator();
            
            /*
             * Se recorre la lista hasta que se termine o se encuentre la 
             * clave buscada.
             */
            boolean seguir = true;
            while ( (seguir == true) && (iterador.hasNext() == true) ) {
                Element siguiente = (Element) iterador.next();
                //Se obtiene el remitente de esta entrada
                String remitenteAlmacenado = siguiente.getChildText("Identity");
                System.out.println("Remitente almacenado:"+remitenteAlmacenado);
                //Se obtiene la clave de esta entrada
                String claveAlmacenada = siguiente.getChildText("SharedSecret");
                System.out.println("Clave almacenada:"+claveAlmacenada);
                if ( remitenteAlmacenado.equals(remitente) == true ) {
                    /*
                     * Se ha encontrado una entrada para el remitente. Ya no
                     * se buscará más. Se comprueba que la clave almacenada
                     * coincida con la proporcionada.
                     */
                    seguir = false; //No se itera más
                    claveCorrecta = claveAlmacenada.equals(clave);                    
                } else {
                    /*
                     * Se sigue iterando, y se considera la clave
                     * como válida al no haber encontrado ninguna entrada
                     * hasta ahora.
                     */
                    claveCorrecta = true;
                }
            }
        } catch (IOException ioe) {
            /*
             * Si ocurre algún error leyendo el archivo de claves, por 
             * precacución se considera incorrecta la clave proporcionada.
             */
            claveCorrecta = false;
        }
        return claveCorrecta;
    }
    
    /**
     * Crea un elemento "ProfileResponse" JDOM que contiene la respuesta
     * de este servidor a una petición cXML de perfil. La respuesta incluye
     * todas las operaciones soportadas por este servidor.
     *
     * @return un <code>Element</code> de tipo cXML "ProfileResponse" con 
     *         las operaciones cXML soportadas por este servidor.
     */
    private Element procesarPeticionPerfil() {
        //Se crea un elemento "ProfileResponse"
        Element resultado = new Element(RespuestaCXML.RESPUESTA_PERFIL);
        /*
         * Se asigna la fecha de comienzo de disponibilidad de los servicios
         * prestados por este servidor con la fecha de creación de este objeto.
         */
        resultado.setAttribute("effectiveDate", fechaComienzoEjecucion);
        
        /*
         * Se crea un nuevo elemento "Transaction" por cada operación
         * soportada, indicado en el array OPERACIONES.
         */
        for (int i = 0; i < OPERACIONES.length ; i++) {
            /*
             * Se crea un elemento "Transaction" con una operación
             * soportada por este servidor.
             */
            Element transaccion = new Element("Transaction");
            transaccion.setAttribute("requestName", OPERACIONES[i]);
            /*
             * El elemento "URL" es obligatorio según el DTD de cXML, pero
             * como este servidor no soporta URLs, se pone sin contenido.
             */ 
            Element url = new Element("URL");
            transaccion.addContent(url);
            //Se añade el nuevo elemento "Transaction" a la respuesta
            resultado.addContent(transaccion);
        }
        return resultado;        
    }
    
    /**
     * Procesa la petición de compra cXML especificada. En esta implementación
     * de servidor cXML, sólo se muestra por pantalla la petición
     * recibida y se guarda en un fichero de nombre el identificador de la
     * petición cXML "payload" y en el directorio marcado por 
     * <code>DIRECTORIO_ORDENES_COMPRA</code>.
     *
     * @param  peticion la petición cXML recibida y que se quiere procesar
     * @return          si la petición cXML ha sido aceptada y procesada
     *                  correctamente.
     */
    private boolean procesarPeticionCompra(PeticionCXML peticion) {
        // Se imprime la petición en el flujo de salida
        System.out.println("Peticion recibida de:" + peticion.getIdentidadSender());
        System.out.println("Esta es la orden de compra:");
        System.out.println(peticion.toString());
        
        /*
         * Se guarda en un archivo de nombre el identificador "payload"
         * de la petición.
         */
        String nombreArchivo = 
            peticion.getElementoRaiz().getAttributeValue("payloadID") + ".xml";
        peticion.guardarEnArchivo( new File(DIRECTORIO_ORDENES_COMPRA, 
                                            nombreArchivo ) );
        
        return true; //Todo ha ido correctamente
    }
    
   
    
    
}