/* 
* 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;

import java.awt.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import servidor.utiles.*;

public class PseudoConsola extends javax.swing.JFrame {

    PrintStream psOut = new PrintStream(new FilteredStream(new ByteArrayOutputStream(), 0));
    PrintStream psErr = new PrintStream(new FilteredStream(new ByteArrayOutputStream(), 1));
    int numeroLineas;
    public final java.util.List<Linea> lista = Collections.synchronizedList(new LinkedList<Linea>());
    ListaComandos ordenesCursadas = new ListaComandos();
    ServidorMain main;
    int lineHeight = 1;
    int lineaDesde;
    private boolean activada = true;
    int ultimaLineaGuardada = 0;

    public PseudoConsola() {
        try {
            setIconImage(new javax.swing.ImageIcon(getClass().getResource("/recursos/ateneo32x32.gif")).getImage());
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        initComponents();
        lineHeight = memo.getFontMetrics(memo.getFont()).getHeight();
        System.setOut(psOut);
        System.setErr(psErr);
        edComando.requestFocus();
        main = Global.main;
        this.setTitle(main.nombreServidor + leerVersion());
    }

    final String leerVersion() {
        try {
            String url = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
            String nombreJar = java.net.URLDecoder.decode(url.substring(1), "UTF-8");
            File jar = new File(nombreJar);
            Date d = new Date(jar.lastModified());
            SimpleDateFormat timeFormat = new java.text.SimpleDateFormat("dd/MM HH:mm");
            return "- " + timeFormat.format(d);
        } catch (Exception exc) {
            return "";
        }
    }

    public void activar() {
        activada = true;
    }

    public void desactivar() {
        activada = false;
    }

    public void textoExterno(String txt) {
        String[] lineas = Global.split(txt, '#');
        for (String linea : lineas) {
            nuevaLinea(linea, 2);
        }
    }

    void nuevaLinea(String txt, int tipo) {
        if (activada) {
            String ahora = Fecha.formatoHoraHMS(new Date());
            lista.add(new Linea(ahora + " " + txt, tipo));
            refrescaVisor();
        }
    }

    void hazScroll(int v) {
        lineaDesde = v;
        memo.repaint();
    }

    void refrescaVisor() {
        final int numeroElementos = lista.size();
        int indice = numeroElementos - numeroLineas;
        if (indice < 0) {
            indice = 0;
        }
        lineaDesde = indice;
        final int indiceFinal = indice;
        memo.paintImmediately(memo.getBounds());
        if (javax.swing.SwingUtilities.isEventDispatchThread()) {
            scroll.setValues(indice, numeroLineas, 0, numeroElementos);
        } else {
            try {
                javax.swing.SwingUtilities.invokeLater(() -> {
                    scroll.setValues(indiceFinal, numeroLineas, 0, numeroElementos);
                });
            } catch (Exception exc) {
                StringWriter sw = new StringWriter();
                exc.printStackTrace(new PrintWriter(sw));
                ServidorMain.log.log(Level.WARNING, "Error en consola: \n{0}", sw.toString());
            }
        }
    }

    void calculaNumeroLineas() {
        numeroLineas = memo.getHeight() / lineHeight;
        scroll.setVisibleAmount(numeroLineas);
    }

    void comandoTeclaPulsada(java.awt.event.KeyEvent evt) {
        if (evt.getKeyChar() == '\n') {
            String comando = edComando.getText().trim().toUpperCase();
            if (comando.length() > 0 && main.procesaComando(comando)) {
                ordenesCursadas.add(comando);
                edComando.setText("");
            }
            evt.consume();
        }
    }

    void comandoTeclaPresionada(java.awt.event.KeyEvent evt) {
        String s = null;
        switch (evt.getKeyCode()) {
            case java.awt.event.KeyEvent.VK_UP:
                s = ordenesCursadas.anterior();
                if (s != null) {
                    edComando.setText(s);
                }
                break;
            case java.awt.event.KeyEvent.VK_DOWN:
                s = ordenesCursadas.posterior();
                if (s != null) {
                    edComando.setText(s);
                }
                break;
        }
    }

    public void guardarPendiente(String fichero) {
        try {
            PrintStream salida = new PrintStream(new FileOutputStream(fichero, true));
            synchronized (lista) {
                for (ListIterator it = lista.listIterator(ultimaLineaGuardada); it.hasNext();) {
                    Linea l = (Linea) it.next();
                    salida.println(l.linea.trim());
                    ultimaLineaGuardada++;
                }
            }
            salida.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
    }

    public void test() {
        System.out.println("Prueba de linea con gran longitud: ..............:1234567890abcdefghijklmnñopqrstuvwxyzABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
    }

   // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
   private void initComponents() {
      java.awt.GridBagConstraints gridBagConstraints;

      panelSalida = new javax.swing.JPanel();
      scroll = new javax.swing.JScrollBar();
      memo = new MiPanel();
      panelEntrada = new javax.swing.JPanel();
      rotulo = new javax.swing.JLabel();
      edComando = new javax.swing.JTextField();

      setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
      setTitle("SERVIDOR Gesti\u00f3n Colas V. 0.3");
      panelSalida.setLayout(new java.awt.BorderLayout());

      scroll.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
         public void adjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {
            scrollAdjustmentValueChanged(evt);
         }
      });

      panelSalida.add(scroll, java.awt.BorderLayout.EAST);

      memo.setLayout(null);

      memo.setFont(new java.awt.Font("Courier New", 0, 12));
      memo.addComponentListener(new java.awt.event.ComponentAdapter() {
         public void componentResized(java.awt.event.ComponentEvent evt) {
            memoComponentResized(evt);
         }
      });

      panelSalida.add(memo, java.awt.BorderLayout.CENTER);

      getContentPane().add(panelSalida, java.awt.BorderLayout.CENTER);

      panelEntrada.setLayout(new java.awt.GridBagLayout());

      panelEntrada.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
      panelEntrada.setMinimumSize(new java.awt.Dimension(404, 30));
      panelEntrada.setPreferredSize(new java.awt.Dimension(0, 30));
      rotulo.setText("Comando: ");
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
      gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 10);
      panelEntrada.add(rotulo, gridBagConstraints);

      edComando.addKeyListener(new java.awt.event.KeyAdapter() {
         public void keyPressed(java.awt.event.KeyEvent evt) {
            edComandoKeyPressed(evt);
         }
         public void keyTyped(java.awt.event.KeyEvent evt) {
            edComandoKeyTyped(evt);
         }
      });

      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
      gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
      gridBagConstraints.weightx = 1.0;
      gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 10);
      panelEntrada.add(edComando, gridBagConstraints);

      getContentPane().add(panelEntrada, java.awt.BorderLayout.SOUTH);

      pack();
   }// </editor-fold>//GEN-END:initComponents

   private void edComandoKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_edComandoKeyPressed
       comandoTeclaPresionada(evt);
   }//GEN-LAST:event_edComandoKeyPressed

   private void memoComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_memoComponentResized
       calculaNumeroLineas();
   }//GEN-LAST:event_memoComponentResized

	private void edComandoKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_edComandoKeyTyped
            comandoTeclaPulsada(evt);
	}//GEN-LAST:event_edComandoKeyTyped

	private void scrollAdjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {//GEN-FIRST:event_scrollAdjustmentValueChanged
            hazScroll(evt.getValue());
	}//GEN-LAST:event_scrollAdjustmentValueChanged


   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JTextField edComando;
   private javax.swing.JPanel memo;
   private javax.swing.JPanel panelEntrada;
   private javax.swing.JPanel panelSalida;
   private javax.swing.JLabel rotulo;
   private javax.swing.JScrollBar scroll;
   // End of variables declaration//GEN-END:variables

    public class Linea {

        public String linea;
        public int tipo;

        Linea(String txt, int tipo) {
            this.linea = txt;
            this.tipo = tipo;
        }
    }

    class FilteredStream extends FilterOutputStream {

        int tipo;
        StringBuffer sb = new StringBuffer(500);

        public FilteredStream(OutputStream aStream, int tipo) {
            super(aStream);
            this.tipo = tipo;
        }

        @Override
        public void write(byte b[]) throws IOException {
            guardaTexto(new String(b));
        }

        @Override
        public void write(byte b[], int off, int len) throws IOException {
            String aString = new String(b, off, len);
            guardaTexto(aString);
        }

        void guardaTexto(String txt) {
            try {
                sb.append(txt);
                int p = 0;
                while ((p = sb.indexOf("\n")) >= 0) {
                    nuevaLinea(sb.substring(0, p), tipo);
                    sb.delete(0, p + 1);
                }
            } catch (Exception exc) {
                ServidorMain.log.log(Level.SEVERE, "Excepcion al imprimir en la consola.\n+{0}", exc.toString());
                for (int i = 0; i < 3; i++) {
                    java.awt.Toolkit.getDefaultToolkit().beep();
                }
            }
        }
    }

    class MiPanel extends javax.swing.JPanel {

        @Override
        protected void paintComponent(java.awt.Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setBackground(Color.WHITE);
            g2.clearRect(0, 0, this.getWidth(), this.getHeight());

            try {
                ListIterator it = lista.listIterator(lineaDesde);
                float ypos = lineHeight;
                while (it.hasNext()) {
                    Linea l = (Linea) it.next();
                    switch (l.tipo) {
                        case 0:
                            g2.setColor(Color.BLACK);
                            break;
                        case 1:
                            g2.setColor(Color.RED);
                            break;
                        case 2:
                            g2.setColor(Color.BLUE);
                            break;
                    }
                    g2.drawString(l.linea, 0.0f, ypos);
                    ypos += lineHeight;
                }
            } catch (ConcurrentModificationException exc) {
            } catch (Exception exc) {
            }
        }
    }
}
