package com.FitBank.twain;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

import javax.swing.JOptionPane;

/**
 * Clase que realiza la conexion nativa con el DLL de TWAIN.
 * 
 * @author FITBANK
 * @version 1.0 Junio del 2005
 */
public class LectorTwain {
    /**
     * Constantes que definen las unidades a utilizar para tamanios.
     */
    public static final int INCHES      = 0,
    						CENTIMETERS = 1,
    						PICAS       = 2,
    						POINTS      = 3,
    						TWIPS       = 4,
    						PIXELS      = 5;

    /**
     * Genera una instancia de esta clase.
     */
    private static final LectorTwain mInstancia = new LectorTwain();

    private static boolean isOpen = false;

    /**
     * Nombre del DLL. No debe incluir la extension .dll.
     */
    protected final String DLL_NAME = "jtwain";

    /**
     * Constructor privado
     */
    private LectorTwain() {
        initLib();
    }

    /**
     * Genera una instancia de LectorTwain.
     * 
     * @return Una instancia de LectorTwain.
     */
    public static LectorTwain getInstance() {

    	return LectorTwain.isOpen ?  mInstancia  : null;
    }

    /**
     * Chequea si TWAIN esta activo en el sistema operativo.
     * 
     * @return true - TWAIN esta activo; false - TWAIN no esta disponible.
     */
    public native boolean isTwainDisp();

    /**
     * Obtiene los nombres de las fuentes disponibles de TWAIN.
     * 
     * @return un arreglo String[] con los nombres de las fuentes disponibles.
     */
    public native String[] getFuentesDisp();

    /**
     * Procesa un pedido de adquisicion de imagen simple.
     * 
     * @return El nombre del archivo donde se guardo la imagen JPEG.
     */
    public native String adquirir();

    /**
     * Procesa un pedido de adquisicion de imagen, el dispositivo TWAIN debe
     * adquirir la imagen y guardarla en un archivo temporal con formato JPEG.
     * Este archivo esta predefinido en el DLL.
     * 
     * @param sourceName Nombre de la fuente TWAIN.
     * @param result Resultado del metodo setAbrirFuente().
     * 
     * @return Nombre del archivo temporal donde se guardo la imagen JPEG.
     */
    public native String adquirir(String sourceName, int result);

    /**
     * Procesa un pedido de cambio de Profundidad de bits de la imagen.
     * 
     * @param bits Numero de bits por pixel.
     * @return != 0 si el pedido fue aceptado y procesado.
     */
    public native int setBitDepth(int bits);

    /**
     * Procesa un pedido de cambio de Resolucion de imagen.
     * 
     * @param res DPIs de la imagen (puntos por pulgada).
     * 
     * @return != 0 si el pedido fue aceptado y procesado.
     */
    public native int setResolucion(double res);

    /**
     * Procesa un pedido de cambio de Brillo de la imagen.
     * 
     * @param bri Entre -1000 y +1000, siendo 0 el brillo original.
     * 
     * @return != 0 si el pedido fue aceptado y procesado.
     */
    public native int setBrillo(double bri);

    /**
     * Procesa un pedido de cambio de Contraste de la imagen.
     * 
     * @param con Entre -1000 y +1000, siendo 0 el contraste original.
     * 
     * @return != 0 si el pedido fue aceptado y procesado.
     */
    public native int setContraste(double con);

    /**
     * Permite ocultar el GUI provisto por el driver TWAIN del dispositivo.
     * 
     * @param hide != 0 si se desea ocultar el GUI, 0 si se desea que aparezca.
     */
    public native void setOcultarUI(int hide);

    /**
     * Abre una fuente TWAIN y la prepara para recibir pedidos.
     * 
     * @param fuente Nombre de la fuente TWAIN.
     * @return != 0 si la fuente fue abierta exitosamente.
     */
    public native int setAbrirFuente(String fuente);

    /**
     * Verifica si el GUI del driver TWAIN esta en modo oculto.
     * 
     * @return 0 si esta en modo de aparecer, != 0 si esta en modo oculto.
     */
    public native int getOcultarUI();

    /**
     * Verifica en que estado esta el driver TWAIN.
     * 
     * @return El estado de TWAIN (ver documentacion de TWAIN),
     * 		   siendo el estado 4 cuando el dispositivo esta listo para recibir pedidos.
     */
    public native int getEstado();

    /**
     * Realiza un pedido de cambio de area de adquisicion (escaneo) de imagen.
     * 
     * @param left   Coordenada X de la esquina superior izquierda.
     * @param top    Coordenada Y de la esquina superior izquierda.
     * @param right  Coordenada X de la esquina inferior derecha.
     * @param bottom Coordenada Y de la esquina inferior derecha.
     * 
     * @return != 0 si el pedido fue aceptado y procesado.
     */
    public native int setTamano(double left, double top, double right, double bottom);

    /**
     * Obtiene el valor de TWAIN que indica en que unidades de medida se especifican los tamanios de area de adquisicion.
     * 
     * @return Valor que indica en que unidades se hacen las medidas, entre 0 y 5 (ver constantes).
     */
    public native int getUnidades();

    /**
     * Fija un valor que indica que unidades se debe utilizar para realizar mediciones de tamanio de imagen.
     * 
     * @param unid Valor entre 1 y 5 que indican las unidades deseadas (ver constantes).
     * 
     * @return != 0 si el pedido fue aceptado y procesado.
     */
    public native int setUnidades(int unid);

    /**
     * Metodo que realiza la conexion entre el DLL y esta interfaz nativa.
     */
    private void initLib() {

        try {
            System.loadLibrary(DLL_NAME);
            System.out.println(DLL_NAME + ".dll abierto exitosamente");
            isOpen = true;
        } catch (UnsatisfiedLinkError ex) {
            String winDir = "c:\\windows\\system32";
            System.out.println("Error cargando DLL");
            System.out.println("Intentando copiar jtwain.dll desde escaner.jar...");

            try {
                InputStream in = ClassLoader.getSystemResourceAsStream(DLL_NAME + ".dll");

                winDir = JOptionPane.showInputDialog(null, "Ingrese el directorio de sistema \n"
                                        + "(ej., c:\\windows\\system32, c:\\winnt\\system32)", winDir);

                FileOutputStream newDll = new FileOutputStream(winDir + File.separator + "jtwain.dll");

                System.out.println("Copiando " + DLL_NAME + ".dll a " + winDir + "...");
                while (in.available() > 0) {
                    newDll.write(in.read());
                }

                in.close();
                newDll.close();
                isOpen = true;
                System.out.println(DLL_NAME + ".dll copiado exitosamente");

            } catch (Exception ex2) {
                JOptionPane.showMessageDialog(null, "No se pudo copiar " + DLL_NAME + ".dll a " + winDir,
                							  "Error", JOptionPane.ERROR_MESSAGE);
                System.out.println("No se pudo copiar " + DLL_NAME + ".dll a " + winDir);
                System.out.println("Error: " + ex2.getMessage());
                isOpen = false;
            }

            if (isOpen) {
                isOpen = false;
                try {
                    System.loadLibrary(DLL_NAME);
                    System.out.println(DLL_NAME + ".dll abierto exitosamente");
                    isOpen = true;
                } catch (Exception ex3) {
                    JOptionPane.showMessageDialog(null, "No se pudo abrir " + DLL_NAME + ".dll desde " + winDir,
                    							  "Error", JOptionPane.ERROR_MESSAGE);
                    System.out.println("No se pudo abrir " + DLL_NAME + ".dll desde " + winDir);
                    isOpen = false;
                }
            }
        }
    }
}
