/* 
* Copyright 2016 Agencia Estatal de Administración Tibutaria
*
* Licencia con arreglo a la EUPL, Versión 1.1 o –en cuanto
* sean aprobadas por la Comisión Europea– versiones
* posteriores de la EUPL (la «Licencia»);
* Solo podrá usarse esta obra si se respeta la Licencia.
* Puede obtenerse una copia de la Licencia en:
*  
* https://joinup.ec.europa.eu/software/page/eupl
*  
* Salvo cuando lo exija la legislación aplicable o se acuerde
* por escrito, el programa distribuido con arreglo a la
* Licencia se distribuye «TAL CUAL», SIN GARANTÍAS NI CONDICIONES
* DE NINGÚN TIPO, ni expresasni implícitas.
*
* Véase la Licencia en el idioma concreto que rige los permisos y 
* limitaciones que establece la Licencia.
*/ 

package servidor.cargador;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;

import java.sql.*;
import java.text.*;
import java.util.*;

import javax.swing.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class ActualizadorATENEO implements ActionListener {

   String URLBase;
   ArrayList<Fichero> ListaFicheros;
   JTextArea ventana;
   boolean conError = false;
   JButton jsalir;
   JFrame jf;
   boolean modificadoServidor = false;
   String codigoCentro;

   public ActualizadorATENEO(String URL, String codigocen) {
      boolean avisoDeError = true;
      if(URL.toLowerCase().startsWith("(noaviso)")) {
         avisoDeError = false;
         URL = URL.substring(9);
      }
      URLBase = URL;
      prepara_interface();
      codigoCentro = codigocen;
      try {
         if (CreaListaFicheros()) {
            RecorreListaFicheros();
         }
      } catch (Exception e) {
         trata_excepcion_XML(e);
      }
      if (conError) {
         if(avisoDeError) {
            if (!jf.isVisible()) {
               jf.setVisible(true);
            }
            mensaje_ventana("");
            mensaje_ventana(" *******  ATENCIÓN  ********   ");
            mensaje_ventana("El proceso de descarga ha concluido con errores");
            mensaje_ventana("Se continuará con la ejecución de las versiones actuales");
            mensaje_ventana(" **** PULSE el botón SALIR  --->  ****");
            jsalir.setEnabled(true);
         } else {
            jf.dispose();
         }
      } else {
         //envia_datos_servidor();
         if (modificadoServidor) {
            Genera_script();
            System.exit(0);
         } else {
            jf.dispose();
         }
      }
   }

   private void Genera_script() {
      PrintWriter pwbat;
      try {
         pwbat = new PrintWriter(new FileOutputStream("reiniciaServidor.vbs"));
         pwbat.println("On Error Resume Next");
         pwbat.println("WScript.sleep 15000");
         pwbat.println("Set fs = CreateObject(\"Scripting.FileSystemObject\")");
         pwbat.println("If fs.fileExists(\"libs\\quickserver.jar.new\") Then");
         pwbat.println("    fs.GetFile(\"libs\\quickserver.jar\").delete");
         pwbat.println("    fs.GetFile(\"libs\\quickserver.jar.new\").name = \"quickserver.jar\"");
         pwbat.println("End if");
         pwbat.println("If fs.fileExists(\"libs\\commons-pool.jar.new\") Then");
         pwbat.println("    fs.GetFile(\"libs\\commons-pool\").delete");
         pwbat.println("    fs.GetFile(\"libs\\commons-pool.jar.new\").name = \"commons-pool.jar\"");
         pwbat.println("End if");
         pwbat.println("If fs.FileExists(\"libs\\transmisorateneo.jar.new\") Then");
         pwbat.println("    If fs.FileExists(\"libs\\transmisorateneo.jar.bak\") Then fs.GetFile(\"libs\\transmisorateneo.jar.bak\").Delete");
         pwbat.println("    If fs.FileExists(\"libs\\transmisorateneo.jar\") then fs.GetFile(\"libs\\transmisorateneo.jar\").Name = \"transmisorateneo.jar.bak\"");
         pwbat.println("    fs.GetFile(\"libs\\transmisorateneo.jar.new\").Name = \"transmisorateneo.jar\"");
         pwbat.println("End If");
         pwbat.println("If fs.FileExists(\"servidor.jar.new\") Then");
         pwbat.println("    If fs.FileExists(\"servidor.jar.bak\") Then fs.GetFile(\"servidor.jar.bak\").Delete");
         pwbat.println("    If fs.FileExists(\"servidor.jar\") then fs.GetFile(\"servidor.jar\").Name = \"servidor.jar.bak\"");
         pwbat.println("    fs.GetFile(\"servidor.jar.new\").Name = \"servidor.jar\"");
         pwbat.println("End If");
         pwbat.println("set shell = wscript.CreateObject(\"wscript.Shell\")");
         pwbat.println("shell.Exec \"javaw -jar servidor.jar ejecutarSinDescargar\"");
         pwbat.println("    If fs.FileExists(\"transmisorateneo.jar.bak\") Then fs.GetFile(\"transmisorateneo.jar.bak\").Delete");
         pwbat.println("    If fs.FileExists(\"transmisorateneo.jar\") Then fs.GetFile(\"transmisorateneo.jar\").Delete");
         pwbat.println("    If fs.FileExists(\"transmisorateneo.jar.new\") Then fs.GetFile(\"transmisorateneo.jar.new\").Delete");

         pwbat.println("fs.DeleteFile \"reiniciaServidor.vbs\"");
         pwbat.close();
         Runtime.getRuntime().exec("cscript reiniciaServidor.vbs");
       
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   private void prepara_interface() {
      jf = new JFrame("Descarga de módulos ATENEO");
      jf.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
      JScrollPane jsp = new JScrollPane();
      JPanel jp = new JPanel();
      ventana = new JTextArea(20, 50);
      ventana.setBounds(30, 30, 100, 50);
      jsp = new JScrollPane(ventana,
              JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
              JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      jp.add(jsp);
      jsalir = new JButton("Salir");
      jsalir.setEnabled(false);
      jsalir.addActionListener(this);
      jsalir.setBounds(50, 180, 30, 10);
      jp.add(jsalir);
      jf.setContentPane(jp);
      jf.pack();
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      if (e.getSource() == jsalir) {
         jf.dispose();
      }
   }

   private void mensaje_ventana(String mensaje) {
      ventana.append(mensaje + "\n");
   }

   private void trata_excepcion_XML(Exception e) {
      mensaje_ventana("Error ModulosATENEO.xml: " + e.getMessage());
      mensaje_ventana("Proceso ABORTADO");
      conError = true;
   }

   long descargaArchivo(String path, File file) {
      HttpURLConnection httpURL = null;
      try {
         OutputStream sout = new FileOutputStream(file);
         URL urlin = new URL(URLBase + path);
         httpURL = (HttpURLConnection) urlin.openConnection();
         httpURL.setUseCaches(false);
         InputStream sin = httpURL.getInputStream();
         long sizeFileHost = httpURL.getContentLength();
         byte[] buffer = new byte[1024];
         while (true) {
            int n = sin.read(buffer);
            if (n < 0) {
               break;
            }
            sout.write(buffer, 0, n);
         }
         sin.close();
         sout.close();
         httpURL.disconnect();
         return sizeFileHost;
      } catch (Exception exc) {
         this.mensaje_ventana("No se ha podido descargar " + path);
         return -1;
      } finally {
         if (httpURL != null) {
            httpURL.disconnect();
         }
      }
   }

   private void CopiaArchivo(Fichero fiHost) {
      long sizeFileHost;
      try {
         File fiLocal = new File(fiHost.getPath());
         File fiTemp = new File(fiHost.getPath() + ".new");
         if (fiTemp.exists()) {
            fiTemp.delete();
         }
         mensaje_ventana("Chequeando " + fiHost.getPath());
         if (fiLocal.lastModified() != fiHost.getFechaModificacion()) {
            if (!jf.isVisible()) {
               jf.setVisible(true);
            }
            mensaje_ventana("Iniciando transferencia: " + fiHost.getPath());
            sizeFileHost = descargaArchivo(fiHost.getPath(), fiTemp);
            if (sizeFileHost == -1 || fiTemp.length() != sizeFileHost) {
               fiTemp.delete();
               throw new IOException("Error en tamaño de archivo.");
            }
            renombraFicheros(fiHost);
            mensaje_ventana("Concluida transferencia: " + fiHost.getPath());
         }
      } catch (Exception e) {
         conError = true;
         mensaje_ventana("Error transferencia módulo " + fiHost.getPath() + ": " + e.getMessage());
         e.printStackTrace();
      }
   }

   private void renombraFicheros(Fichero fiHost) throws Exception {
      File fiNuevo = new File(fiHost.getPath() + ".new");
      if (!fiNuevo.exists()) {
         throw new Exception("Error durante el renombrado del archivo " + fiHost.getPath());
      } else {
         if (fiHost.getNombre().equalsIgnoreCase("servidor.jar") || fiHost.getNombre().equalsIgnoreCase("transmisorateneo.jar")) {
            modificadoServidor = true;
            fiNuevo.setLastModified(fiHost.getFechaModificacion());
         } else {
            File fiAntiguo = new File(fiHost.getPath());
            if (fiAntiguo.exists()) {
               File fixbak = new File(fiAntiguo.getAbsolutePath() + ".bak");
               if (fixbak.exists()) {
                  fixbak.delete();
               }
               fiAntiguo.renameTo(fixbak);
            }
            File fiFinal = new File(fiHost.getPath());
            fiNuevo.renameTo(fiFinal);
            fiFinal.setLastModified(fiHost.getFechaModificacion());
         }
      }
   }

   private boolean CreaListaFicheros() throws Exception {
      try {
         System.setProperty("sun.net.client.defaultConnetTimeout", "10000");
         System.setProperty("sun.net.client.defaultReadTimeout", "10000");
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         DocumentBuilder builder = factory.newDocumentBuilder();
         File fileXml = new File("temporal.xml");
         if (descargaArchivo("modulosateneo.xml", fileXml) == -1) {
            mensaje_ventana("de " + URLBase);
            conError = true;
            return false;
         }
         Document document = builder.parse(fileXml);
         NodeList list = document.getElementsByTagName("Fichero");
         ListaFicheros = new ArrayList<Fichero>(list.getLength());
         for (int i = 0; i < list.getLength(); i++) {
            Element fi = (Element) list.item(i);
            if (!fi.getParentNode().getNodeName().equalsIgnoreCase("completa")) {
               comprueba_datos_fhost(fi);
               ListaFicheros.add(new Fichero(fi.getAttribute("Nombre"), fi.getAttribute("Directorio"), fecha_aMilis(fi.getAttribute("FechaModificacion"))));
            }
         }
         fileXml.delete();
         return true;
      } catch (IOException ioe) {
         mensaje_ventana("Error en comunicación: " + ioe.getClass().toString() + ":" + ioe.getMessage());
         throw ioe;
      }
   }

   private void RecorreListaFicheros() {
      for (int i = 0; i < ListaFicheros.size(); i++) {
         CopiaArchivo(ListaFicheros.get(i));
      }
   }

   private void comprueba_datos_fhost(Element fi) throws SAXException {
      if (fi.getAttribute("Nombre").toString().equals("")) {
         throw new SAXException("El atributo 'Nombre' no existe o está vacío");
      }
      if (fi.getAttribute("Directorio").toString().equals("")) {
         throw new SAXException("El atributo 'Directorio' no existe o está vacío");
      }
      try {
         if (fecha_aMilis(fi.getAttribute("FechaModificacion")) == 0) {
            throw new SAXException("El atributo 'FechaModificacion' no es una fecha correcta");
         }
      } catch (NumberFormatException e) {
         throw new SAXException("El atributo 'FechaModificacion' no es una fecha correcta");
      }
   }

   private long fecha_aMilis(String fechastr) {
      SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy kk:mm:ss");
      try {
         java.util.Date fecha = sdf.parse(fechastr);
         return fecha.getTime();
      } catch (ParseException e) {
      }
      return 0;
   }

  
}
