import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Vector;

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import javax.swing.JFrame;

import javax.imageio.ImageIO;
import javax.media.Buffer;
import javax.media.CannotRealizeException;
import javax.media.CaptureDeviceInfo;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.cdm.CaptureDeviceManager;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.imageio.*;

public class ServidorRMI extends UnicastRemoteObject implements InterfazRMI, ActionListener {
    /**   
	 * @param host                  Nombre del host
	 * @param puerto        	Puerto que se usará para la conexión
	 * @param botonCapturar		Boton para la captura
 	 * @param botonGuardar  	Boton para guardar archivo
	 * @param botonSalir		Boton para salir de la aplicación
	 * @param chooser               Para seleccionar carpeta al guardar
	 * @param claves                Claves de usuarios que se pensaba crear
	 * @param clientes              Nº de usuarios
         * @param comboConectados       En un principio para verificar quienes estaban conectados
         * @param conectados            Usuarios conectados
         * @param dispositivo           Nombre de dispositivo a ocupar
         * @param extra                 Variable auxiliar para desplegar en pantalla
         * @param imagen                Imagen a capturar
         * @param panelImagen           Panel en el que se adjunta la imagen para desplegarla en pantalla
         * @param player                Instancia de la clase payer, que nos sirve para mostrar el streaming
         * @param registro              Instancia de la clase Registry, la cual nos sirve para obtener el registro de la conexión para RMI
     */    
    private static String host;
    private static int puerto;
    private JButton botonCapturar;
    private JButton botonGuardar;
    private JButton botonSalir;
    private JFileChooser chooser;
    private String[] claves;
    private int clientes;
    private JComboBox comboConectados;
    private Vector conectados;
    private String dispositivo;
    private JFrame extra;
    private Image imagen = null;
    private ImagePanel panelImagen;
    private Player player;
    private ResourceBundle propiedades;
    private int puertoBase;
    private String[] usuarios;
    private JFrame ventana;
    private Registry registro;
    private int i=0;
    private BufferedImage image = null;

    public static void main(String[] args) {
		JFrame.setDefaultLookAndFeelDecorated(true);
		JDialog.setDefaultLookAndFeelDecorated(true);

        try {
            ServidorRMI servidor = new ServidorRMI();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    
    //------------Se inicializan las variables
    public ServidorRMI() throws RemoteException {
        super();
        

            propiedades = ResourceBundle.getBundle("servidor");

            host = propiedades.getString("host");
            puerto = Integer.parseInt(propiedades.getString("puerto"));
            clientes = Integer.parseInt(propiedades.getString("clientes"));
            puertoBase = puerto;
            usuarios = new String[clientes];
            claves = new String[clientes];
            conectados = new Vector(1, 1);          

            for (int i = 0; i < usuarios.length; i++) {
                usuarios[i] = propiedades.getString("usuario" + (i + 1));
                claves[i] = propiedades.getString("clave" + (i + 1));
            }
            mostrarSeleccion();
        
    }

    //---------------Se asignan acciones al presionar los botones
    public void actionPerformed(ActionEvent evento) {
        String accion = evento.getActionCommand();

        if (evento.getSource() instanceof JRadioButton) {
            dispositivo = evento.getActionCommand();
            JOptionPane.showMessageDialog(ventana, "Dispositivo \"" + dispositivo + "\" seleccionado");
            extra.dispose();

            agregarComponentes();
        }

        if (accion.equalsIgnoreCase("Capturar")) {
            FrameGrabbingControl fgc = (FrameGrabbingControl)
            player.getControl("javax.media.control.FrameGrabbingControl");
            Buffer buffer = fgc.grabFrame();
            BufferToImage btoi = new BufferToImage((VideoFormat) buffer.getFormat());
            imagen = btoi.createImage(buffer);
            panelImagen.setImage(imagen);
        }

        if (accion.equalsIgnoreCase("Guardar")) {
            if (imagen != null) {
                int result = chooser.showOpenDialog(ventana);

                if (result == JFileChooser.APPROVE_OPTION) {
                    File archivo = chooser.getSelectedFile();
                    String nombre = archivo.getName().toLowerCase();

                    if (!nombre.endsWith(".jpg")) {
                        nombre = archivo.getAbsolutePath() + ".jpg";
                    }

                    try {
                        ImageIO.write((RenderedImage) imagen, "JPEG", new File(nombre));
                    } catch (Exception e) {
                        JOptionPane.showMessageDialog(ventana, "No se pudo guardar la imagen");
                    }
                }
            } else {
                JOptionPane.showMessageDialog(ventana, "Primero debe realizar una captura");
            }
        }

        if (accion.equalsIgnoreCase("Salir")) {
            if (player != null) {
                player.close();
            }

            System.exit(0);
        }
    }

    //-------------------Se agregan los componentes de la pantalla de la aplicación
    public void agregarComponentes() {
        chooser = new JFileChooser(".");

        ventana = new JFrame("Servidor de video");
        ventana.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        ventana.getContentPane().add(agregarPanelCamara(), BorderLayout.NORTH);
        ventana.getContentPane().add(agregarPanelBotones(), BorderLayout.CENTER);
        ventana.getContentPane().add(agregarPanelImagen(), BorderLayout.SOUTH);

        ventana.pack();
        ventana.setVisible(true);

        try {
            registro = LocateRegistry.createRegistry(puerto);
            registro.rebind("ServidorRMI", this);
        } catch (RemoteException e) {
        } 
    }

    //-----------------Se agregan los botones del panel
    public JPanel agregarPanelBotones() {
        JPanel panelBotones = new JPanel(new BorderLayout());

        comboConectados = new JComboBox();

        botonCapturar = new JButton("Capturar");
        botonCapturar.setPreferredSize(new Dimension(110,25));
        botonCapturar.addActionListener(this);
        botonGuardar = new JButton("Guardar");
        botonGuardar.setPreferredSize(new Dimension(110,25));
        botonGuardar.addActionListener(this);
        botonSalir = new JButton("Salir");
        botonSalir.setPreferredSize(new Dimension(110,25));
        botonSalir.addActionListener(this);

        panelBotones.add(comboConectados, BorderLayout.NORTH);
        panelBotones.add(botonCapturar, BorderLayout.WEST);
        panelBotones.add(botonGuardar, BorderLayout.CENTER);
        panelBotones.add(botonSalir, BorderLayout.EAST);

        return panelBotones;
    }

    //--------------Se agrega el espacio para la captura de la cámara y se comienza a capturar el streaming
    public JPanel agregarPanelCamara() {
        JPanel panelCamara = new JPanel();

        CaptureDeviceInfo dev = CaptureDeviceManager.getDevice(dispositivo);
        MediaLocator loc = dev.getLocator();

        try {
            player = Manager.createRealizedPlayer(loc);
        } catch (NoPlayerException e1) {
            JOptionPane.showMessageDialog(ventana, e1.getMessage());
        } catch (CannotRealizeException e2) {
            JOptionPane.showMessageDialog(ventana, e2.getMessage());
        } catch (IOException e3) {
            JOptionPane.showMessageDialog(ventana, e3.getMessage());
        }

        player.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }

        Component componente = player.getVisualComponent();

        if (componente != null) {
            panelCamara.add(componente, BorderLayout.CENTER);
        }

        return panelCamara;
    }

    //-------------Agrega la imágen al panel
    public JPanel agregarPanelImagen() {
        panelImagen = new ImagePanel();

        return panelImagen;
    }
    
    //-------------Implementación del método remoto definido en la interfaz, devolverá un entero cada vez que se capture una imágen
    public int recibirMensaje() throws RemoteException {
        return(i++);
    }
    
    //-------------Implementación del método remoto definido en la interfaz, se encarga de transformar la imágen a escala de grises
    public Image transform() throws RemoteException{
        FrameGrabbingControl fgc = (FrameGrabbingControl)
        player.getControl("javax.media.control.FrameGrabbingControl");
        Buffer buffer = fgc.grabFrame();
        BufferToImage btoi = new BufferToImage((VideoFormat) buffer.getFormat());
        imagen = btoi.createImage(buffer);
        BufferedImage imageAux = (BufferedImage) imagen;
        ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        BufferedImage imagenGris = op.filter(imageAux,null);
        Image imageFinal = (Image)imagenGris;
        panelImagen.setImage(imageFinal);
        return imageFinal;
    }

    //---------------Muestra la pantalla inicial, donde se debe elegir el dispositivo
    public void mostrarSeleccion() {
        Vector listaDispositivos = CaptureDeviceManager.getDeviceList();
        Iterator iterador = listaDispositivos.iterator();
        extra = new JFrame("Seleccione el dispositivo");
        extra.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        JPanel panelSeleccion = new JPanel();
        ButtonGroup grupo = new ButtonGroup();

        while (iterador.hasNext()) {
            CaptureDeviceInfo cdi = (CaptureDeviceInfo) iterador.next();
            JRadioButton radio = new JRadioButton(cdi.getName());
            radio.addActionListener(this);
            grupo.add(radio);
            panelSeleccion.add(radio);
        }

        extra.getContentPane().add(panelSeleccion, BorderLayout.CENTER);
        extra.setSize(300, 300);
        extra.setVisible(true);
    }
}