/**
 * UFRGS - II - PPGC - MESTRADO EM CIENCIA DA COMPUTACAO
 * AUTORA MANUELE KIRSCH PINHEIRO
 * Classe UML_BW_Mediator
 * PACOTE BW.UML
 * DATA DE CRIACAO 04 / 01 / 2001
 */
package BW.UML;


//REVER os imports!!
import BW.Interface.*;
import BW.control.*;
import BW.storage.*;
import BW.kernel.*;
import BW.*;

import COPSE.CEvent;

import java.util.*;


/**
 * Classe UML_BW_Mediator faz serve de intermediario
 * entre o groupware CUTE (construido com o framework
 * COPSE) e o framework para awareness BW.
 * COPSE e CUTE sao de autoria de Marcio Dias, pela
 * COPPE/UFRJ, 1998.
 * @author Manuele Kirsch Pinheiro
 * @version 1.0
 */
public class UML_BW_Mediator extends GW_BW_Mediator {


     ////////////////////////////// CONSTANTES UTILIZADAS //////////////////////////

     /* ***** TYPEIDS para os eventos ***** */

     	/** typeId identificador do evento "USERSESSION".
     	 * Este evento indica a ocorrencia de uma sessao de usuario no sistema.
     	 */
	public static final int USERSESSION = CEvent.EvCOPSE_Connection_Open;
	
	/** typeId indentificador do evento "SAVEDIAGRAM"
	 * Este evento indica a ocorrencia de uma requisicao de save para o
	 * diagrama ativo
	 */
	public static final int SAVEDIAGRAM = CEvent.EvCOPSE_FileController_Save;
	
	/** typeId indentificador do evento "NEWCLASS"
	 * Este evento indica a criacao de uma nova classe no
	 * diagrama ativo
	 */
	public static final int NEWCLASS = CEvent.EvCOPSE_FileController_Element_New;

	/** typeId indentificador do evento "CLASSEDITED"
	 * Este evento indica o processo de edicao/alteracao de uma classe no
	 * diagrama ativo
	 */
	public static final int CLASSEDITED = CEvent.EvCOPSE_FileController_Element_Update;
	
	/** typeId indentificador do evento "CLASSREMOVED"
	 * Este evento indica a remocao de uma classe do
	 * diagrama ativo
	 */
	public static final int CLASSREMOVED = CEvent.EvCOPSE_FileController_Element_Delete;
	
	/** typeId indentificador do evento "NEWRELATION"
	 * Este evento indica a criacao de um novo relacionamento entre classes no
	 * diagrama ativo
	 */
	public static final int NEWRELATION = CEvent.EvCOPSE_FileController_Element_New + 1000;

	/** typeId indentificador do evento "RELATIONEDITED"
	 * Este evento indica o processo de edicao/alteracao de um relacionamento
	 * entre classes do diagrama ativo
	 */
	public static final int RELATIONEDITED = CEvent.EvCOPSE_FileController_Element_Update + 1000;
	
	/** typeId indentificador do evento "RELATIONREMOVED"
	 * Este evento indica a remocao de um relacionamento entre classes do
	 * diagrama ativo
	 */
	public static final int RELATIONREMOVED = CEvent.EvCOPSE_FileController_Element_Delete + 1000;

	/** typeId indentificador do evento "BROADCASTMESSAGE"
	 * Este evento indica o envio de uma mensagem para todo o grupo (broadcast)
	 */
	public static final int BROADCASTMESSAGE = CEvent.EvCollaboration_Communication_Call_Message;
	

	public static int MAX = 10;
	
     ///////////////////////////////// ATRIBUTOS //////////////////////////////


		
     /** Hashtable contendo as pilhas dos eventos em aberto - uma para cada tipo de evento */
      Hashtable openEvents;

     /** fila com os eventos ja concluidos */
      Vector events;

     /** identificador do ultimo objeto gerado */
     int lastObjId;

     /** ST_Implementor especifico usado para esta aplicacao */
     //ST_DatabaseImplementor implementor;

     /** Principal elemento de interface com o usuario */
     //AwarenessMainWindow mainInterface;

     /** Canal de comunicacao com a camada de interface */
     UI_Interface Interface;

     /** Canal de comunicacao com a camada de controle */
     FC_CL_Monitor monitor;



     ////////////////////////////////// CONSTRUTOR ////////////////////////////

/* -------------------------------------------------------------------------------- */

     /** construtor default */
     public UML_BW_Mediator () {
    	this.openEvents = new Hashtable();
    	this.initStacks();
    	this.events = new Vector();
    	this.lastObjId = typeIdDefault.OBJID;
    	
    	//implementor = null;
    	//mainInterface = null;
    	
     }

/* -------------------------------------------------------------------------------- */

     /** finaliza as atividades do mediador */
     protected void finalize () throws Throwable {
     	this._stop();
     	super.finalize();
     }
	

/* -------------------------------------------------------------------------------- */


     ///////////////////////////////// METODOS ////////////////////////////////


/* -------------------------------------------------------------------------------- */

     /** inicializa as pilhas de eventos em aberto */
     void initStacks() {
          openEvents.put (mountKey (UML_BW_Mediator.USERSESSION),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.SAVEDIAGRAM),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.NEWCLASS),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.CLASSEDITED),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.CLASSREMOVED),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.NEWRELATION),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.RELATIONEDITED),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.RELATIONREMOVED),new Stack());
          openEvents.put (mountKey (UML_BW_Mediator.BROADCASTMESSAGE),new Stack());
     }

/* -------------------------------------------------------------------------------- */

     /** monta a chave utilizada na Hash de pilhas em aberto */
     Object mountKey (int typeId) {
     	return new Integer (typeId);
     }
     
/* -------------------------------------------------------------------------------- */

     /** busca o ultimo evento do tipo indicado que foi colocado na pilha de eventos incompletos */
      BW_Event pop (int typeId) {
		Object key  = this.mountKey (typeId);
	   	Stack s = (Stack) openEvents.get (key);
	   	return (BW_Event) s.pop();
	}
		 
/* -------------------------------------------------------------------------------- */

      /** coloca um evento de um tipo determinado na fila de eventos em aberto */
       void push (int type, BW_Event evt) {
		Object key = this.mountKey (type);     	
		Stack s = (Stack) openEvents.get (key);
        	s.push (evt);		 	
	}

/* -------------------------------------------------------------------------------- */
     public static Vector getPrototypes () {
		UML_BW_Mediator lixo = new UML_BW_Mediator ();
		Vector v = lixo.makePrototypes();
		return v;
     }

     /** cria um vetor com eventos prototipos de todos os 9 tipos de eventos utilizados */
     Vector makePrototypes () {

     	Vector prot = new Vector();
     	
     	BW_Event evt = new BW_Event (UML_BW_Mediator.USERSESSION,UML_BW_Mediator.USERSESSION);
      evt.setName ("User Session");
     	prot.addElement (evt);
     	evt = new BW_Event (UML_BW_Mediator.SAVEDIAGRAM,UML_BW_Mediator.SAVEDIAGRAM);
	evt.setName ("Save Diagram");
     	prot.addElement (evt);
     	evt = new BW_Event (UML_BW_Mediator.BROADCASTMESSAGE,UML_BW_Mediator.BROADCASTMESSAGE);
	evt.setName ("Broadcast Message");
     	prot.addElement (evt);
     	evt = new BW_Event (UML_BW_Mediator.NEWCLASS,UML_BW_Mediator.NEWCLASS);
	evt.setName ("New Class");
     	prot.addElement (evt);
     	evt = new BW_Event (UML_BW_Mediator.CLASSEDITED,UML_BW_Mediator.CLASSEDITED);
	evt.setName ("Class Edited");
     	prot.addElement (evt);     	
     	evt = new BW_Event (UML_BW_Mediator.CLASSREMOVED,UML_BW_Mediator.CLASSREMOVED);
	evt.setName ("Class Removed");
     	prot.addElement (evt);
     	evt = new BW_Event (UML_BW_Mediator.NEWRELATION,UML_BW_Mediator.NEWRELATION);
	evt.setName ("New Relation");
     	prot.addElement (evt);
     	evt = new BW_Event (UML_BW_Mediator.RELATIONEDITED,UML_BW_Mediator.RELATIONEDITED);
	evt.setName ("Relation Edited");
     	prot.addElement (evt);     	
     	evt = new BW_Event (UML_BW_Mediator.RELATIONREMOVED,UML_BW_Mediator.RELATIONREMOVED);
	evt.setName ("Relation Removed");
     	prot.addElement (evt);

     	return prot;
     	     	
     }

/* -------------------------------------------------------------------------------- */

     /** preenche os campos ainda em branco do evento recem gerado */
     void fillEvent (int type, BW_Event evt) {        

        if (evt.getResponsible()==null)
     	    	evt.setResponsible (Interface.getMember());

     	switch (type) {
     		case USERSESSION:
     		        evt.setName ("User Session");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Sessao de um usuario");     		        	     		
     			break;	
     			
     		case SAVEDIAGRAM:
     		        evt.setName ("Save Diagram");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Salvamento de diagrama");     		        	     		     		
     			break;	
     			
     		
     		case BROADCASTMESSAGE:
     		        evt.setName ("Broadcast Message");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Mensagem de broadcast para o grupo");     		        	     		
     		     		
     			break;	
     			     		
     		case NEWCLASS:
     		        evt.setName ("New Class");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Nova classe introduzida no diagrama");     		        	     		
     		
     			break;	
     			
     		case CLASSEDITED:
     		        evt.setName ("Class Edited");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Classe do diagrama alterada");     		        	     		
     		
     			break;	
     			
     		case CLASSREMOVED:
     		        evt.setName ("Class Removed");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Classe do diagrama removida");     		        	     		
     		
     			break;	
     			
     		case NEWRELATION:
     		        evt.setName ("New Relation");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Novo relacionamento entre classes introduzido no diagrama");     		        	     		
     		
     			break;	
     			
     		case RELATIONEDITED:
     		        evt.setName ("Relation Edited");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Relacionamento entre classes alterado");     		        	     		
     		
     			break;	
     			
     		case RELATIONREMOVED:
     		        evt.setName ("Relation Removed");
     		        if (evt.getDescription().equals(""))
     		        	evt.setDescription ("Relacionamento entre classes removido");     		        	     		
     		
     			break;	
     			
     	}

     }


/* -------------------------------------------------------------------------------- */

     /** retorna o proximo identificador de objeto a ser usado */
     int getNextObjId () {
	  return this.lastObjId++;	
     }	

/* -------------------------------------------------------------------------------- */

     /** coloca o evento ja concluido na fila de eventos prontos */
     synchronized void finished (BW_Event evt) {
     	  events.addElement (evt);
     	
     	  //se ja chegou ao limite, manda salvar
     	  if (events.size()>= UML_BW_Mediator.MAX) {
     	  	monitor.eventOccurence (events);
     	  	events.removeAllElements();
     	  }
     	
     }
     
/* -------------------------------------------------------------------------------- */


     /////////////////////////////// METODOS REDEFINIDOS //////////////////////


/* -------------------------------------------------------------------------------- */

     /** envia o sinal de inicio de processamento para o mediator,
      * avisando-o do inicio das atividades. Chamado normalmente pelo metodo
      * estatico "Start" da classe GW_BW_Mediator
      * @see 	GW_BW_Mediator#Start
      * @return boolean	true se foi possivel inicializar o mediador concreto;
      *			false se nao foi possivel
      */
     public boolean _start () {
        return this._start("localhost");
     }

/* -------------------------------------------------------------------------------- */

     /** envia o sinal de inicio de processamento para o mediator,
      * avisando-o do inicio das atividades. Chamado normalmente pelo metodo
      * estatico "Start" da classe GW_BW_Mediator
      * @see 	GW_BW_Mediator#Start
      * @param	String host	servidor utilizado
      * @return boolean	true se foi possivel inicializar o mediador concreto;
      *			false se nao foi possivel
      */
     public boolean _start (String host) {
          boolean ret = false;

          try {
              //inicializa o implementor
              //implementor = new ST_DatabaseImplementor (host);

              //inicializa mainInterface
              //mainInterface = new AwarenessMainWindow();

              //inicializa camada storage
              //Vector v1 = ST_StartUp.Start(implementor);

              //inicializa camada control
              //Vector v2 = CL_StartUp.Start (v1);
              //this.monitor = CL_StartUp.getMonitorFacade();

              //inicializa camada interface
              //this.Interface = UI_StartUp.Start(v2);

              //seta interface principal
              //Interface.addGUIElement (mainInterface,this.makePrototypes());

              //ret = true;
          } catch (Exception e) {
              ret = false;
          }

          return false;
     }

/* -------------------------------------------------------------------------------- */

     /** envia o sinal de fim do processamento para o mediator,
      * avisando-o do termino das atividades. Causa o fechamento das
      * comunicacoes com o servidor.
      * Normalmente chamado pelo metodo estatico "Stop" da classe
      * GW_BW_Mediator.
      * @see 	GW_BW_Mediator#Stop
      * @return boolean	true se foi possivel finalizar o mediador concreto;
      *			false se nao foi possivel
      */
     public boolean _stop () {
     	   boolean ret = false;
     	
     	  //chama o stop do implementor para fechar o acesso ao banco
	  //if (implementor != null)
     	  //      ret = implementor.stop();
	  //else  ret = true;

     	  return ret;
     }

/* -------------------------------------------------------------------------------- */


     /** assinala o inicio da ocorrencia de um evento.
      * Assinalado o inicio de um evento, este devera ficar
      * em uma pilha especifica para o seu tipo, aguardando
      * ate que seja assinalado o seu termino. Normalmente
      * chamado pelo metodo "BeginEvent" da classe mae.
      *
      * @see	GW_BW_Mediator#BeginEvent
      * @param	BW_Event evt	evento que se inicia
      * @param	int typeId	tipo do evento
      * @return boolean	true	se tudo ocorreu como de esperado
      *			false	caso contrario
      *
      */
     public boolean _beginEvent (int typeId, BW_Event evt) {
        boolean ret = false;

        try {
     		//identifica o tipo do evento
     		int type = evt.getTypeId();     		
     	
     		//preenche o que nao estiver ainda preenchido no evento
     		evt.setObjId (this.getNextObjId());
     		this.fillEvent (type,evt);
     	
     		//coloca o evento ainda incompleto na pilha certa
        	this.push (type,evt);
        	
        	ret = true;
        	
        } catch (Exception e) {
                ret = false;
        }	

        return ret;
     }

/* -------------------------------------------------------------------------------- */


     /** assinala o inicio da ocorrencia de um evento.
      * Assinalado o inicio de um evento, este devera ficar
      * em uma pilha especifica para o seu tipo, aguardando
      * ate que seja assinalado o seu termino. Normalmente
      * chamado pelo metodo "BeginEvent" da classe mae.
      *
      * @see	GW_BW_Mediator#BeginEvent
      * @param	int typeId	tipo do evento
      * @return boolean	true	se tudo ocorreu como de esperado
      *			false	caso contrario
      *
      */
     public boolean _beginEvent (int typeId) {
     	   BW_Event evt = new BW_Event(typeId,lastObjId);
     	   return this._beginEvent (typeId,evt);	
     }


/* -------------------------------------------------------------------------------- */

      /** assinala o termino da ocorrencia de um evento.
      * Assinalado o termino de um evento, este devera ser
      * retirado da pilha especifica para o seu tipo, e
      * sera calculada a sua duracao total. Normalmente
      * chamado pelo metodo "BeginEvent" da classe mae.
      *
      * @see	GW_BW_Mediator#EndEvent
      * @param 	BW_Event evt	evento que termina
      * @param	int typeId	tipo do evento
      * @return boolean	true	se tudo ocorreu como de esperado
      *			false	caso contrario
      *
      */
     public boolean _endEvent (int typeId, BW_Event evt) {
	  boolean ret = false;     	
     	
     	  try {
         	//pega o tempo final    	
         	Calendar c = Calendar.getInstance (evt.getInterval().getTimeZone(),evt.getInterval().getLocale());
         
		//busca o evento na pilha
		BW_Event e = this.pop (typeId);
										
		//seta o tempo do evento (inicial e final)
		BW_TimeInterval i1 = evt.getInterval();
		BW_TimeInterval i2 = e.getInterval();
					
		i1.setBegin (i2.getBegin());
		i1.setEnd (c);
					
		evt.setInterval (i1);
					
		//seta o objid do evento e preenche o que nao esta preenchido
		evt.setObjId (e.getObjId());
		this.fillEvent (typeId,evt);
										
		//coloca na fila de eventos prontos
		this.finished (evt);
					
		ret = true;
					
	   } catch (Exception ex) {
		ret = false;	
	   }							
				
	   return ret;

     }


/* -------------------------------------------------------------------------------- */

      /** assinala o termino da ocorrencia de um evento.
      * Assinalado o termino de um evento, este devera ser
      * retirado da pilha especifica para o seu tipo, e
      * sera calculada a sua duracao total. Normalmente
      * chamado pelo metodo "BeginEvent" da classe mae.
      *
      * @see	GW_BW_Mediator#EndEvent
      * @param	int typeId	tipo do evento
      * @return boolean	true	se tudo ocorreu como de esperado
      *			false	caso contrario
      *
      */
     public boolean _endEvent (int typeId){
	  boolean ret = false;     	
     	
     	  try {        
		//busca o evento na pilha
		BW_Event evt = this.pop (typeId);
				
		//pega o tempo final    	
         	Calendar c = Calendar.getInstance (evt.getInterval().getTimeZone(),evt.getInterval().getLocale());

		//seta o tempo do evento final
		BW_TimeInterval i1 = evt.getInterval();
		i1.setEnd (c);					
		evt.setInterval (i1);
					
		//preenche o que nao esta preenchido
		this.fillEvent (typeId,evt);
										
		//coloca na fila de eventos prontos
		this.finished (evt);
					
		ret = true;
					
	   } catch (Exception ex) {
		ret = false;	
	   }							
			
	   return ret;
     }

/* -------------------------------------------------------------------------------- */

     /** assinala o cancelamento da ocorrencia de um evento.
      * O proximo evento na pilha de eventos do tipo indicado
      * devera ser retirado desta e descartado. Normalmente
      * chamado pelo metodo "CancelEvent" da classe mae.
      *
      * @param	int typeId	tipo do evento
      * @return boolean	true	se tudo ocorreu como de esperado
      *			false	caso contrario
      * @see	GW_BW_Mediator#CancelEvent
      */
      public boolean _cancelEvent (int typeId){
	  boolean ret = false;
					
	  try {					
		 //tira o evento da fila
		 BW_Event evt = this.pop (typeId);
							 
		 if (evt!=null) ret = true;
		 		
	  } catch (Exception e) {
		 ret = false;		
	  }
				  
	  return ret;						
     }
     
/* -------------------------------------------------------------------------------- */

     /** seta o elemento de interface principal. Normalmente
      * chamado pelo metodo "SetMainUIElement" da classe mae.
      * @see	GW_BW_Mediator#SetMainUIElement
      * @param UI_Element main	elemento principal (gerente de interface)
      * @return	boolean	true se tudo ocorreu bem, false caso contrario
      */
     public boolean _setMainUIElement (UI_GUIElement main){
     	 //mainInterface = main;
     	 return true;	
     }

/* -------------------------------------------------------------------------------- */

     /** retorna o elemento de interface principal, se disponivel
      * @return	UI_Element	elemento principal (gerente de interface)
      *				null caso este nao tenha sido setado 	
      */
     public UI_GUIElement _getMainUIElement (){
     	  UI_GUIElement ret = null;
     	  //ret = (UI_GUIElement) mainInterface;
     	  return ret;
     }
/* -------------------------------------------------------------------------------- */

}