package com.FitBank.twain;

import java.io.FileInputStream;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

import java.util.ArrayList;

import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import com.FitBank.common.Debug;

/**
 * Implementacion del Servidor de Escaner via RMI.
 * 
 * @author FITBANK
 * @version 1.1 Junio del 2005
 */
public class ServidorEscanerImpl extends UnicastRemoteObject implements ServidorEscaner {

    private static final long serialVersionUID = 1L;

    private LectorTwain twain;
    private boolean     isStateFour;
    private int         res;
    private String      fuente,
    					selFnt;

    /**
     * Inicializa el servidor de escaner.
     * 
     * @throws RemoteException
     */
    public ServidorEscanerImpl() throws RemoteException {
        twain = LectorTwain.getInstance();
        if (twain == null) {
            JOptionPane.showMessageDialog(null, "No se pudo inicializar el Lector Twain",
            							  "Error de TWAIN", JOptionPane.ERROR_MESSAGE);
            System.exit(1);
        }
        fuente = "";
        selFnt = "";
        isStateFour = false;
        System.out.println("Inicializando servidor...");
    }

    /**
     * Establece resolucion de escaneo.
     * 
     * @param res Resolucion en DPIs (puntos por pulgada).
     * 
     * @throws RemoteException
     */
    public void setResolucion(double res) throws RemoteException {
        if (isStateFour) {
            int rs = twain.setResolucion(res);
            if (rs != 0) {
                System.out.println("Resolucion: " + res);
            } else {
                System.out.println("No se pudo negociar resolución.");
            }
        } else {
            System.out.println("No se pudo negociar resolución. No se ha abierto una fuente");
        }
    }

    /**
     * Establece tamanio del area de escaneo (en centimetros).
     * 
     * @param topx Coordenada X de la esquina superior izquierda.
     * @param topy Coordenada Y de la esquina superior izquierda.
     * @param wid  Ancho del area de escaneo (de izquierda a derecha).
     * @param hei  Alto del area de escaneo (de arriba a abajo).
     * 
     * @throws RemoteException
     */
    public void setTamano(double topx, double topy, double wid, double hei) throws RemoteException {
        if (isStateFour) {
            int tam = twain.setTamano(topx, topy, topx + wid, topy + hei);
            if (tam != 0) {
                System.out.println("Tamaño de imagen: x=" + topx + " y=" + topy + " w=" + wid + " h=" + hei);
            } else {
                System.out.println("No se pudo negociar tamaño de imagen.");
            }
        } else {
            System.out.println("No se pudo negociar tamaño. No se ha abierto una fuente");
        }
    }

    /**
     * Abre una fuente TWAIN para recibir pedidos.
     * 
     * @param fnt Nombre de la fuente TWAIN.
     */
    public void setFuente(String fnt) throws RemoteException {
        res = twain.setAbrirFuente(fnt);
        fuente = fnt;
        isStateFour = true;

        if (res != 0) {
            System.out.println("Abierta fuente " + fuente + ", pasando a estado 4");
        } else {
            System.out.println("No se pudo abrir la fuente " + fuente);
            isStateFour = false;
        }
    }

    /**
     * Devuelve la fuente escogida al iniciar el servidor.
     * 
     * @return un String con el nombre de la fuente escogida al iniciar el servidor.
     * 
     * @throws RemoteException
     */
    public String getFuente() throws RemoteException {

    	return selFnt;
    }

    /**
     * Permite ocultar la ventana de vista previa propia del driver del dispositivo TWAIN.
     * 
     * @param ocultar 0 si se desea mostrar, 1 para ocultar.
     */
    public void setOcultarUI(int ocultar) throws RemoteException {
        if (isStateFour) {
            twain.setOcultarUI(ocultar);
            if (getOcultarUI() != 0) {
                System.out.println("La ventana de preview del driver se ocultara.");
            } else {
                System.out.println("La ventana de preview del driver se mostrara.");
            }
        } else {
            System.out.println("No se puede ocultar/mostrar la ventana de preview. No se ha abierto una fuente.");
        }
    }

    /**
     * Permite ocultar la ventana de vista previa propia del driver del dispositivo TWAIN.
     * 
     * @param ocultar 0 si se desea mostrar, 1 para ocultar.
     */
    public int getOcultarUI() throws RemoteException {
        if (isStateFour) {
            return twain.getOcultarUI();
        } else {
            System.out.println("No se puede mostrar el estado de la ventana de preview. No se ha abierto una fuente.");

            return 0;
        }
    }

    /**
     * Permite escoger una fuente TWAIN de una lista.
     * 
     * @return Las fuentes disponibles en un String[].
     * 
     * @throws RemoteException
     */
    private String[] getFuentesDisp() {
        String fuentes[];

        System.out.println("Pedido de fuentes disponibles:");
        if (twain.isTwainDisp()) {
            fuentes = twain.getFuentesDisp();

            if (fuentes != null) {
                if (fuentes.length > 0) {
                    for (String fuente2 : fuentes) {
                        System.out.println("\t" + fuente2);
                    }
                } else {
                    fuentes = null;
                }
            } else {
                fuentes = null;
            }
        } else {
            fuentes = null;
        }

        return fuentes;
    }

    /**
     * Inicia un pedido de escaneo de imagen.
     * 
     * @return Un ArrayList con Bytes de la informacion de la imagen JPEG.
     * 
     * @throws RemoteException
     */
    public ArrayList adquirir() throws RemoteException {
        ArrayList rd = null;
        if (isStateFour) {
            System.out.println("Adquiriendo imagen desde " + fuente + "...");
            String filNam = twain.adquirir(fuente, res);

            System.out.println("Leyendo imagen...");
            try {
                FileInputStream fin = new FileInputStream(filNam);
                rd = new ArrayList();
                int readByt = 0;

                while (readByt != -1) {
                    readByt = fin.read();
                    Byte rdbyt = new Byte((byte) readByt);
                    rd.add(rdbyt);
                }

                fin.close();

                System.out.println("Imagen devuelta como ArrayList");
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                twain = null;
                twain = LectorTwain.getInstance();
                isStateFour = false;
            }
        } else {
            System.out.println("No se puede adquirir, no se ha abierto una fuente.");
        }

        return rd;
    }

    /**
     * Realiza un pedido de cambio de brillo de imagen.
     * 
     * @param brillo un double entre -1000 y +1000 especificando brillo, siendo 0 (cero) el brillo original.
     * 
     * @throws RemoteException
     */
    public void setBrillo(double brillo) throws RemoteException {
        if (isStateFour) {
            int exito = twain.setBrillo(brillo);
            if (exito != 0) {
                System.out.println("Brillo fijado en " + brillo);
            } else {
                System.out.println("No se pudo negociar brillo de imagen.");
            }
        } else {
            System.out.println("No se pudo negociar brillo. No se ha abierto una fuente");
        }
    }

    public void setContraste(double contr) throws RemoteException {
        if (isStateFour) {
            int exito = twain.setContraste(contr);

            if (exito != 0) {
                System.out.println("Contraste fijado en " + contr);
            } else {
                System.out.println("No se pudo negociar contraste de imagen.");
            }
        } else {
            System.out.println("No se pudo negociar contraste. No se ha abierto una fuente");
        }
    }

    public void setUnidades(int unitCode) throws RemoteException {
        if (isStateFour) {
            if (unitCode >= 0 && unitCode <= 5) {
                int exito = twain.setUnidades(unitCode);
                if (exito != 0) {
                    String nm[] = { "PULGADAS", "CENTIMETROS", "PICAS", "PUNTOS", "TWIPS", "PIXELES" };

                    System.out.println("Unidad de medida fijada a " + nm[unitCode]);
                } else {
                    System.out.println("No se pudo negociar unidad de medida.");
                }
            } else {
                System.out.println("Código de unidad de medida incorrecto (debe ser entre 0 y 5).");
            }
        } else {
            System.out.println("No se puede negociar unidad de medida. No se ha abierto una fuente.");
        }
    }

    /**
     * Cuando se inicia el servidor, permite escoger la fuente TWAIN que se utilizara
     * para todas las adquisiciones de imagenes.
     * 
     * @throws RemoteException
     */
    private void init() throws RemoteException {
        JPanel jpanel    = new JPanel();
        JComboBox jcombo = new JComboBox();

        if (fuente.equals("")) {
            String[] fuentes = getFuentesDisp();
            if (fuentes != null) {
                if (fuentes.length > 0) {
                    for (String fuente2 : fuentes) {
                        jcombo.addItem(fuente2);
                    }

                    jcombo.setSelectedIndex(0);
                    jpanel.add(new JLabel("Escoja fuente TWAIN:"));
                    jpanel.add(jcombo);

                    JOptionPane.showMessageDialog(null, jpanel, "Escoger fuente TWAIN",
                            					  JOptionPane.INFORMATION_MESSAGE);

                    selFnt = (String) jcombo.getSelectedItem();
                    System.out.println("Fuente a utilizar para toda adquisición: " + selFnt);
                    System.out.println("Servidor inicializado.");
                } else {
                    JOptionPane.showMessageDialog(null, "No hay fuentes TWAIN disponibles.",
                            					  "Error de TWAIN", JOptionPane.ERROR_MESSAGE);
                    System.out.println("No se pudo inicializar servidor.");
                    System.exit(1);
                }
            } else {
                JOptionPane.showMessageDialog(null, "No hay drivers TWAIN instalados en el sistema.",
                        					  "Error de TWAIN", JOptionPane.ERROR_MESSAGE);
                System.out.println("No se pudo inicializar servidor.");
                System.exit(1);
            }
        }
    }

    /**
     * Inicia el servidor.
     * 
     * @param args No hay argumentos adicionales.
     */
    public static void main(String args[]) {
        final Object candado = "";
        new Thread() {
            @Override
            public void run() {
                try {
                    LocateRegistry.createRegistry(1089);
                    synchronized (candado) {
                        candado.wait();
                    }
                } catch (Exception ex) {
                    Debug.imprimirError(ex);
                    System.exit(1);
                }
            }
        }.start();

        try {
            ServidorEscanerImpl servEsc = new ServidorEscanerImpl();
            Naming.rebind("//localhost:1089/ServidorEscaner", servEsc);
            servEsc.init();
        } catch (Exception ex) {
            Debug.imprimirError(ex);
            System.exit(1);
        }
    }
}
