package practica1.controller;
import java.io.File;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import practica1.Practica1;
import practica1.controller.event.ControllerExperimentoEvent;
import practica1.controller.event.ControllerListenerEvent;
import practica1.controller.event.ControllerPoblacionEvent;
import practica1.controller.listener.ControllerExperimentoListener;
import practica1.controller.listener.ControllerListener;
import practica1.controller.listener.ControllerPoblacionListener;
import practica1.language.Language;
import practica1.logic.LogicExperimento;
import practica1.logic.LogicPoblacion;
import practica1.logic.adapter.LogicExperimentoAdapter;
import practica1.logic.event.LogicExperimentoEvent;
import practica1.manejoExperimento.ExperimentoInvalidoException;
import practica1.manejoExperimento.ManejoExperimento;
import practica1.preferences.PreferencesListener;
import practica1.preferences.PreferencesXML;
/**
* Clase que actua como punto de unión de la aplicación permitiéndo controlar
* tanto experimentos como poblaciones y subscribirse a sus cambios.
* @author Miguel González - Ceura
*/
public class Controller implements PreferencesListener {
private static Controller INSTANCE = null;
private PreferencesXML prefs;
//Experimentos que se han abierto
private ArrayList<LogicExperimento> experimentosAbiertos;
private LogicExperimento experimentoSeleccionado;
private LogicPoblacion poblacionSeleccionada;
private LogicExperimento experimentoPrincipal;
//Listeners
private ArrayList<ControllerExperimentoListener> listenersExperimento;
private ArrayList<ControllerPoblacionListener> listenersPoblacion;
private ArrayList<ControllerListener> listenersController;
private EscuchadorExperimento escuchadorExperimento;
/**
* Constructor privado de la clase
*/
private Controller() {
//Obtenemos las preferencias de esta clase
prefs = PreferencesXML.getInstance();
//Agregamos el manejador de preferencias
prefs.addPreferencesListener(this);
experimentosAbiertos = new ArrayList<LogicExperimento>();
listenersExperimento = new ArrayList<ControllerExperimentoListener>();
listenersPoblacion = new ArrayList<ControllerPoblacionListener>();
listenersController = new ArrayList<ControllerListener>();
experimentoSeleccionado = null;
poblacionSeleccionada = null;
experimentoPrincipal = null;
escuchadorExperimento = new EscuchadorExperimento();
restorePreferences();
}
/**
* Devuelve la instancia de la clase
* @return Controller Controlador que se enncarga de manejar los experimentos
* y las poblaciones.
*/
public static Controller getInstance() {
if(INSTANCE == null) {
INSTANCE = new Controller();
}
return INSTANCE;
}
/**
* Método que se encarga de restaurar las preferencias de la aplicación,
* en este caso de cargar los experimentos que quedaron abiertos.
*/
private void restorePreferences() {
int numExp = Integer.parseInt(prefs.getValue(this, "numExpAbiertos", "0"));
String mensajeInvalido = "Ha habido problemas al cargar los siguientes"
+ " experimentos:\n";
boolean mostrarMensaje = false;
for(int i=0; i<numExp; i++) {
//Recuperamos las rutas de los experimentos
String ruta = prefs.getValue(this, "exp-" + (i + 1), "");
if(!ruta.isEmpty()) {
try {
addExperimento(ManejoExperimento.abrirExperimento(
new File(ruta)));
} catch (ExperimentoInvalidoException ex) {
Practica1.log.error("Error", ex);
mensajeInvalido += ruta + "\n";
mostrarMensaje = true;
}
}
}
if(mostrarMensaje) {
JOptionPane.showMessageDialog(Practica1.getInstance(),
mensajeInvalido, "Advertencia",
JOptionPane.WARNING_MESSAGE);
}
}
/**
* Método que es llamado al cerrar la aplicación y se encarga de guardar
* los experimentos que han quedado abiertos
*/
@Override
public void savePreferences() {
//Guardamos los experimentos abiertos
prefs.setValue(this, "numExpAbiertos",
Integer.toString(experimentosAbiertos.size()));
for(int i=0; i<experimentosAbiertos.size(); i++) {
prefs.setValue(this, "exp-" + (i + 1),
experimentosAbiertos.get(i).getFichExperimento()
.getAbsolutePath());
}
}
/**
* Devuelve los experimentos abiertos
* @return ArrayList<LogicExperimento> ArrayList con los experimentos abiertos
*/
public ArrayList<LogicExperimento> getExperimentosAbiertos() {
return experimentosAbiertos;
}
/**
* Permite subscribirse a las escuchas del controlador
* @param l ControllerListener
*/
public void addControllerListener(ControllerListener l) {
listenersController.add(l);
}
/**
* Permite desuscribirse a las escuchas del controlador
* @param l ControllerListener
*/
public void removeControllerListener(ControllerListener l) {
listenersController.remove(l);
}
/**
* Permite suscribirse a las escuchas de los experimentos abiertos
* @param l ControllerExperimentoListener
*/
public void addControllerExperimentoListener(ControllerExperimentoListener l) {
if(l != null) {
listenersExperimento.add(l);
}
}
/**
* Permite desuscribirse a las esccuchas de los experimentos abiertos
* @param l ControllerExperimentoListener
*/
public void removeControllerExperimentoListener(
ControllerExperimentoListener l) {
if(l != null) {
listenersExperimento.remove(l);
}
}
/**
* Permite suscribirse a las escucuchas de las poblaciones de los experimentos
* abiertos
* @param l ControllerPoblacionListener
*/
public void addControllerPoblacionListener(ControllerPoblacionListener l) {
if(l != null) {
listenersPoblacion.add(l);
}
}
/**
* Permite desuscrbirise a las escuchas de las poblaciones de los experimentos
* abiertos
* @param l ControllerPoblacionListener
*/
public void removeControllerPoblacionListener(ControllerPoblacionListener l) {
if(l != null) {
listenersPoblacion.remove(l);
}
}
/**
* Añade un experimento a la aplicación
* @param experimento LogicExperimento
*/
public void addExperimento(LogicExperimento experimento) {
experimentoPrincipal = experimento;
experimento.addLogicExperimentoListener(escuchadorExperimento);
experimentosAbiertos.add(experimento);
for(ControllerListener l : listenersController) {
l.experimentoPrincipalChange(new ControllerListenerEvent(experimento));
}
for(ControllerExperimentoListener l : listenersExperimento) {
l.addedExperimento(new ControllerExperimentoEvent(experimento));
}
}
/**
* Quita un experimento de la aplicación
* @param experimento LogicExperimento
*/
public void removeExperimento(LogicExperimento experimento) {
//Cerramos primero todas las poblaciones abiertas
experimento.cerrarTodasPoblaciones();
experimentosAbiertos.remove(experimento);
for(ControllerExperimentoListener l : listenersExperimento) {
l.removedExperimento(new ControllerExperimentoEvent(experimento));
}
}
/**
* Añade una población a la aplicación
* @param poblacion LogicPoblacion
*/
public void addPoblacion(LogicPoblacion poblacion) {
poblacion.getExperimentoPadre().addPoblacion(poblacion);
//Notificamos a todos de que se ha agregado una población
for(ControllerPoblacionListener l : listenersPoblacion) {
l.addedPoblacion(new ControllerPoblacionEvent(poblacion));
}
//Despues abrimos la población
abrirPoblacion(poblacion);
}
/**
* Quita una población de la aplicación
* @param poblacion LogicPoblacion
*/
public void removePoblacion(LogicPoblacion poblacion) {
poblacion.getExperimentoPadre().removePoblacion(poblacion);
for(ControllerPoblacionListener l : listenersPoblacion) {
l.removedPoblacion(new ControllerPoblacionEvent(poblacion));
}
}
/**
* Establece un experimento como seleccionado
* @param experimento LogicExperimento
*/
public void setExperimentoSeleccionado(LogicExperimento experimento) {
experimentoSeleccionado = experimento;
}
/**
* Devuelve el experimento seleccionado
* @return LogicExperimento
*/
public LogicExperimento getExperimentoSeleccionado() {
return experimentoSeleccionado;
}
/**
* Dice si un experimento está abierto o no
* @param experimento LogicExperimento
* @return boolean True si lo está, False sinó
*/
public boolean isExperimentoAbierto(LogicExperimento experimento) {
return experimentosAbiertos.contains(experimento);
}
/**
* Dice si un experimento está abierto o no
* @param fichExperimento Fichero del experimento
* @return boolean True si lo está, False sinó
*/
public boolean isExperimentoAbierto(File fichExperimento) {
for(LogicExperimento experimento : experimentosAbiertos) {
if(experimento.getFichExperimento().equals(fichExperimento)) {
return true;
}
}
return false;
}
/**
* Establece una población como seleccionada
* @param poblacion LogicPoblacion
*/
public void setPoblacionSeleccionada(LogicPoblacion poblacion) {
poblacionSeleccionada = poblacion;
}
/**
* Devuelve la población seleccionada
* @return LogicPoblacion
*/
public LogicPoblacion getPoblacionSeleccionada() {
return poblacionSeleccionada;
}
/**
* Establece un experimento como experimento principal
* @param experimentoPrincipal LogicExperimento
*/
public void setExperimentoPrincipal(LogicExperimento experimentoPrincipal) {
this.experimentoPrincipal = experimentoPrincipal;
for(ControllerListener l : listenersController) {
l.experimentoPrincipalChange(
new ControllerListenerEvent(experimentoPrincipal));
}
}
/**
* Devuelve el experimento principal de la aplicación
* @return LogicExperimento
*/
public LogicExperimento getExperimentoPrincipal() {
return experimentoPrincipal;
}
/**
* Abre una población
* @param poblacion LogicPoblacion
*/
public void abrirPoblacion(LogicPoblacion poblacion) {
//Le decimos a su experimento que abra la población
poblacion.getExperimentoPadre().abrirPoblacion(poblacion);
}
/**
* Cierra una población
* @param poblacion LogicPoblacion
*/
public void cerrarPoblacion(LogicPoblacion poblacion) {
//Le decimos a su experimento que abra la población
poblacion.getExperimentoPadre().cerrarPoblacion(poblacion);
}
/**
* Muestra una población
* @param poblacion LogicPoblacion
*/
public void mostrarPoblacion(LogicPoblacion poblacion) {
poblacion.getExperimentoPadre().mostrarPoblacion(poblacion);
}
/**
* Método que sale de la aplicación comprobando si antes se han guardado
* los experimentos. Además pregunta si se quiere salir.
*/
public void salirAplicacion() {
boolean pobNoGuardada = false;
for(int i=0; i<experimentosAbiertos.size() && !pobNoGuardada; i++) {
if(experimentosAbiertos.get(i).isModified()) {
pobNoGuardada = true;
}
if(!pobNoGuardada) {
ArrayList<LogicPoblacion> poblaciones = experimentosAbiertos.get(i).
getPoblaciones();
for(int j=0; j< poblaciones.size() && !pobNoGuardada; j++) {
if(poblaciones.get(j).isModified()) {
pobNoGuardada = true;
}
}
}
}
if(pobNoGuardada) {
int res = JOptionPane.showConfirmDialog(Practica1.getInstance(),
Language.getI().getP("DESEA_GUARDAR_EXPERIMENTOS")
, Language.getI().getP("SALIR"),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if(res == JOptionPane.OK_OPTION) {
for(LogicExperimento e : experimentosAbiertos) {
try {
ManejoExperimento.guardarExperimento(e);
} catch (ExperimentoInvalidoException ex) {
Practica1.log.error("Error", ex);
JOptionPane.showMessageDialog(Practica1.getInstance(),
Language.getI().getP("PROBLEMA_GUARDAR") + ": "
+ e.getNombreExperimento(),
Language.getI().getP("ERROR"),
JOptionPane.ERROR_MESSAGE);
}
}
PreferencesXML.getInstance().savePreferences();
Practica1.log.info("Saliendo de la aplicación");
System.exit(0);
} else if(res == JOptionPane.NO_OPTION) {
PreferencesXML.getInstance().savePreferences();
Practica1.log.info("Fin de la aplicación");
System.exit(0);
}
} else {
int res = JOptionPane.showConfirmDialog(Practica1.getInstance(),
Language.getI().getP("DESEA_SALIR_APLICACION"),
Language.getI().getP("SALIR"),
JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if(res == JOptionPane.OK_OPTION) {
PreferencesXML.getInstance().savePreferences();
Practica1.log.info("Fin de la aplicación");
System.exit(0);
}
}
}
/**
* Clase que se encarga de escuchar los eventos de los experimentos
*/
private class EscuchadorExperimento extends LogicExperimentoAdapter {
/**
* Evento que se produce cuando se abre la población de un experimento
* @param event LogicExperimentoEvent
*/
@Override
public void abiertaPoblacion(LogicExperimentoEvent event) {
for(ControllerPoblacionListener l : listenersPoblacion) {
l.abiertaPoblacion(new ControllerPoblacionEvent(
event.getLogicPoblacion()));
}
}
/**
* Evento que se produce cuando se cierra la población de un experimento
* @param event LogicExperimentoEvent
*/
@Override
public void cerradaPoblacion(LogicExperimentoEvent event) {
for(ControllerPoblacionListener l : listenersPoblacion) {
l.cerradaPoblacion(new ControllerPoblacionEvent(
event.getLogicPoblacion()));
}
}
/**
* Evento que se produce cuando se quiere mostrar la población de un
* experimento.
* @param event LogicExperimentoEvent
*/
@Override
public void mostrarPoblacion(LogicExperimentoEvent event) {
//Le decimos a todos los que nos escuchan que queremos mostrar la población
for(ControllerPoblacionListener l : listenersPoblacion) {
l.mostrarPoblacion(new ControllerPoblacionEvent(
event.getLogicPoblacion()));
}
}
/**
* Evento que se produce cuando la población de un experimento cambia
* @param event LogicExperimentoEvent
*/
@Override
public void poblacionChanged(LogicExperimentoEvent event) {
for(ControllerPoblacionListener l : listenersPoblacion) {
l.modifiedPoblacion(new ControllerPoblacionEvent(
event.getLogicPoblacion()));
}
}
}
}