//--------------------------------------------------------------------------------//
// COPYRIGHT NOTICE //
//--------------------------------------------------------------------------------//
// Copyright (c) 2012, Instituto de Microelectronica de Sevilla (IMSE-CNM) //
// //
// All rights reserved. //
// //
// Redistribution and use in source and binary forms, with or without //
// modification, are permitted provided that the following conditions are met: //
// //
// * Redistributions of source code must retain the above copyright notice, //
// this list of conditions and the following disclaimer. //
// //
// * Redistributions in binary form must reproduce the above copyright //
// notice, this list of conditions and the following disclaimer in the //
// documentation and/or other materials provided with the distribution. //
// //
// * Neither the name of the IMSE-CNM nor the names of its contributors may //
// be used to endorse or promote products derived from this software //
// without specific prior written permission. //
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" //
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE //
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE //
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE //
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL //
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR //
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, //
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE //
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //
//--------------------------------------------------------------------------------//
package xfuzzy.xfsp.controller;
import java.awt.Point;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.swing.SwingUtilities;
import xfuzzy.lang.ParamMemFunc;
import xfuzzy.lang.Type;
import xfuzzy.lang.Rulebase;
import xfuzzy.xfsp.XfspEvent;
import xfuzzy.xfsp.model.XfspModel;
import xfuzzy.xfsp.model.types.XfspCustomMFMerger;
import xfuzzy.xfsp.view.XfspView;
import xfuzzy.xfsp.view.XfspFunctionMergeView;
/**
* <p> <b>Descripci�n:</b> Clase que recibe eventos y coordina su destino
* (vista, <b>XfspView</b>, y/o modelo, <b>XfspModel</b>).
* <p> <b>E-mail</b>: <ADDRESS>joragupra@us.es</ADDRRESS>
* @author Jorge Agudo Praena
* @version 2.1
* @see XfspModel
* @see XfspView
*
*/
public class XfspController
implements Observer, Runnable {
//modelo al que est� ligado el controlador
private XfspModel model;
//almac�n donde se guardan los eventos de entrada hasta que son procesados
//por el modelo
private XfspStore store;
//conjunto de vistas gestionadas por el controlador
private List view;
//evento de entrada que le llega al controlador
private XfspEvent newEvent;
private XfspCustomMFMerger customMerger;
/**
* <p> <b>Descripci�n:</b> crea un nuevo controlador que no gestiona ninguna
* vista ni tiene asignado ning�n almac�n donde guardar los elementos de
* entrada ni ha sido registrado por ning�n modelo.
*
*/
public XfspController() {
//hace que el conjunto de vistas gestionadas sea el vac�o
view = new ArrayList();
//indica que no se est� procesando ninguna petici�n de simplificaci�n
}
/**
* <p> <b>Descripci�n:</b> inicializa el controlador indic�ndolo el modelo
* que lo ha registrado y el almac�n donde debe buscar los eventos de
* entrada.
* @param model Modelo que ha registrado el controlador.
* @param store Almac�n donde se guardar�n los eventos de entrada antes de
* ser procesados por el controlador.
*
*/
public void init(XfspModel model, XfspStore store) {
//indicamos el modelo que va a registrar al controlador actual
this.model = model;
//indicamos el almac�n donde se guardar�n los eventos de entrada
this.store = store;
//hacemos que el modelo registre al controlador
model.registerController(this);
}
/**
* <p> <b>Descripci�n:</b> indica al controlador que debe registrar y
* gestionar una nueva vista. Si la vista indicada ya estaba siendo
* gestionada por el controlador, no hace nada.
* @param view Vista que pasar� a formar parte de las gestionadas por el
* controlador.
*
*/
public void registerView(XfspView view) {
//inicializamos a falso un booleano que nos indique si hemos encontrado la
//vista que queremos a�adir entre las ya gestionadas por el controlador
boolean found = false;
//�ndice que nos servir� para recorrer el conjunto de vistas gestionadas por
//el controlador
int i = 0;
//mientras nos queden vistas por examinar y no hayamos encontrado la vista
//que queremos a�adir entre las ya gestionadas por el controaldor...
while ( (i < this.view.size()) && (found == false)) {
//...examinamos si la vista actual coincide con la que queremos a�adir...
if (view == this.view.get(i)) {
//...si es as�, dejamos de buscar
found = true;
}
else {
//...si no, seguimos buscando
i++;
}
}
//si la vista que queremos a�adir no esta siendo gestionada por el
//controlador...
if (found == false) {
//...la a�adimos a la lista de vistas que tiene que gestionar el
//controlador
this.view.add(view);
}
}
/**
* <p> <b>Descripci�n:</b> hace que el controlador deje de gestionar la vista
* indicada. Caso de que dicha vista no estuviera siendo gestionada por el
* controlador, este m�todo no hace nada.
* @param view Vista que debe dejar de ser gestionada por el controlador.
*
*/
public void deleteView(XfspView view) {
//buscamos entre todas las vistas gestionadas por el controlador
for (int i = 0; i < this.view.size(); i++) {
//si la vista actual coincide con la indicada...
if (view == this.view.get(i)) {
//...la eliminamos de las listas gestionadas por el controlador
view.remove(i);
}
}
}
/**
* <p> <b>Descripci�n:</b> acci�n realizada por el controlador (observador)
* cuando el almac�n (observable) recibe un nuevo evento de entrada.
* @param obs Almac�n donde se almacenan los eventos de entrada y que est�
* siendo observado por el controlador.
* @param ev Evento de entrada que ha sido guardado en el almac�n.
*
*/
public void run() {
//el controlador analiza de qu� tipo de evento se trata
//eventos que provienen de las vistas:
//si el evento es una petici�n de volver a la especificaci�n anterior...
if (newEvent.getType().equals("Reload")) {
//...llamamos al m�todo "reload" del modelo
model.reload((Point)newEvent.getArgs()[0]);
}
//si el evento es una petici�n de aplicaci�n de los cambios realizados en
//la especificaci�n...
else if (newEvent.getType().equals("Apply")) {
//...llamamos al m�todo "apply" del modelo
model.apply();
}
//si el evento es una petici�n de guardar los cambios realizados a la
//especificaci�n...
else if (newEvent.getType().equals("Save")) {
//...llamamos al metodo "save" del modelo
model.save();
}
//si el evento es una petici�n de terminar la simplificaci�n de la
//especificaci�n...
else if (newEvent.getType().equals("Close")) {
//...llamamos al m�todo "close" del modelo
model.close();
//...y cierra todas las vistas
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setVisible(false);
}
}
//si el evento es una petici�n de simplificaci�n de tipos por eliminaci�n
//de aquellas funciones de pertenencia que no se usan en ninguna regla...
else if (newEvent.getType().equals("Elementary")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
//...hacemos que el modelo simplifique el tipo indicado mediante la
//eliminaci�n de las funciones de pertenencia del tipo que no se usen en
//ninguna regla
model.simplifyType( (Type) newEvent.getArgs()[0], "Elementary",
newEvent.getArgs());
}
//si se solicita la simplificaci�n de tipos de la especificaci�n mediante
//clustering...
else if (newEvent.getType().equals("Clustering")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
//...hacemos que el modelo simplifique el tipo indicado mediante
//clustering con los par�metros que haya introducido el usuario
model.simplifyType( (Type) newEvent.getArgs()[0], "Clustering",
newEvent.getArgs());
}
//si se solicita la simplificaci�n de tipos de la especificaci�n mediante
//el estudio de la similaridad de funciones de pertenencia...
else if (newEvent.getType().equals("Similarity")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
//...hacemos que el modelo simplifique el tipo indicada con t�cnicas de
//estudio de similaridad y utilizando los par�metros que haya introducido
//el usuario
Object[] args = new Object[newEvent.getArgs().length];
for (int i = 1; i < newEvent.getArgs().length; i++) {
args[i - 1] = newEvent.getArgs()[i];
}
args[args.length - 1] = store;
model.simplifyType( (Type) newEvent.getArgs()[0], "Similarity",
args); //newEvent.getArgs());
}
//si se solicita la simplificaci�n de bases de reglas mediante podado...
else if (newEvent.getType().equals("Prunning")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
//...hacemos que el modelo simplifique la base de reglas seleccionada
//mediante podado seg�n los grados de activaci�n
model.simplifyRulebase( (Rulebase) newEvent.getArgs()[0], "Prunning",
newEvent.getArgs());
}
//si se solicita la uni�n de las reglas que tengan en mismo consecuente...
else if (newEvent.getType().equals("Union")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
//...hacemos que el modelo una las reglas con iguales consecuentes
//mediante la disyunci�n de las premisas de dichas reglas
model.simplifyRulebase( (Rulebase) newEvent.getArgs()[0], "Union",
newEvent.getArgs());
}
//se se solicita la separaci�n de reglas cuya premisa es un conjunto de
//AND...
else if (newEvent.getType().equals("Separation")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
//...hacemos que el modelo sustituya las reglas con AND en su premisa por
//tantas reglas como operandos tenga la premisa
model.simplifyRulebase( (Rulebase) newEvent.getArgs()[0], "Separation",
newEvent.getArgs());
}
else if (newEvent.getType().equals("Tabular")) {
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(false);
}
model.simplifyRulebase( (Rulebase) newEvent.getArgs()[0], "Tabular", newEvent.getArgs());
}
//si se solicita la continuaci�n del proceso de mezcla de funciones de
//pertenencia...
else if (newEvent.getType().equals("RestartMerging")) {
//...hacemos que el modelo contin�e el proceso de mezcla de funciones de
//pertenencia durante la simplificaci�n de tipos por similaridad con los
//par�metros que haya indicado el usuario
customMerger.setMergedMemFunction((ParamMemFunc) newEvent.getArgs()[0]);
}
//eventos que provienen del modelo que ha registrado al controlador:
//si el modelo solicita que se actualice el gr�fico de representaci�n de
//las funciones de pertenencia de los tipos...
else if (newEvent.getType().equals("Refresh")) {
Object [] args = newEvent.getArgs();
//...indicamos a todas las vistas gestionadas por el modelo que deben
//actualizar el gr�fico de simplificaci�n de tipos llamando al metodo
//"refresh" de las vistas asi como el campo de texto donde se muestran
//las bases de reglas
try {
for (int i = 0; i < view.size(); i++) {
( (XfspView) view.get(i)).setTypes( (Type[]) args[0]);
( (XfspView) view.get(i)).setRuleBases( (Rulebase[]) args[1]);
}
//para todas las vistas registradas por el controlador...
for (int i = 0; i < view.size(); i++) {
final XfspView currentView = (XfspView) view.get(i);
Runnable refreshRun = new Runnable() {
public void run() {
currentView.refresh();
}
};
SwingUtilities.invokeAndWait(refreshRun);
}
//recoge el mensaje que se debe mostrar al refrescar
String [] msg = (String []) newEvent.getArgs()[2];
for(int i=0;i<view.size();i++){
((XfspView) view.get(i)).showMessage(msg);
}
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(true);
( (XfspView) view.get(i)).toFront();
}
}
catch (InterruptedException e) {
}
catch (InvocationTargetException e) {
}
}
//esta parte no est� todo clara y debe ser revisada
else if (newEvent.getType().equals("Rebuild")) {
Object [] args = newEvent.getArgs();
for (int i = 0; i < view.size(); i++) {
( (XfspView) view.get(i)).setTypes( (Type[]) args[0]);
( (XfspView) view.get(i)).setRuleBases( (Rulebase[]) args[1]);
}
for (int i = 0; i < view.size(); i++) {
XfspView currentView = new XfspView(this.store);
currentView.xfuzzy(true);
currentView.setParentLocation(((XfspView) view.get(i)).getParentLocation());
currentView.setLocation(((XfspView) view.get(i)).getLocation());
currentView.setTypes(((XfspView) view.get(i)).getTypes());
currentView.setRuleBases(((XfspView) view.get(i)).getRuleBases());
((XfspView)view.remove(i)).close();
view.add(i,currentView);
currentView.build();
currentView.setVisible(true);
}
for(int i=0;i<view.size();i++){
( (XfspView) view.get(i)).setEnabled(true);
( (XfspView) view.get(i)).toFront();
}
}
//si el modelo solicita al usuario la funci�n de pertenencia que debe
//sustituir a dos funciones similares...
else if (newEvent.getType().equals("Merge")) {
//...crea la ventana para que el usuario elija la funci�n que debe
//reemplazar a las dos funciones similares
this.customMerger = (XfspCustomMFMerger) newEvent.getArgs()[3];
for (int i = 0; i < view.size(); i++) {
XfspFunctionMergeView mergeView = new XfspFunctionMergeView( (
ParamMemFunc) newEvent.getArgs()[0],
(ParamMemFunc) newEvent.getArgs()[1], this.store);
mergeView.setSimilarityDegree( ( (Double) newEvent.getArgs()[2]).
doubleValue());
mergeView.setParentLocation( ( (XfspView) view.get(0)).getLocation());
mergeView.build();
mergeView.setVisible(true);
}
}
}
/**
* <p> <b>Descripci�n:</b> hace que el controlador deje de gestionar la vista
* indicada. Caso de que dicha vista no estuviera siendo gestionada por el
* controlador, este m�todo no hace nada.
* @param view Vista que debe dejar de ser gestionada por el controlador.
*
*/
public void update(Observable obs, Object ev) {
//convertimos el evento de entrada a un objeto de tipo XfspEvent
this.newEvent = (XfspEvent) ev;
//convertimos el observable en un objeto de tipo XfspStore
this.store = (XfspStore) obs;
//creamos un nuevo hilo para el proceso...
Thread newThread = new Thread(this);
//...y lo lanzamos
newThread.start();
}
}