/*
 * EstruturaProcessoPanel.java
 *
 * Created on March 20, 2007, 12:07 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package siprp.medicina.processo.estrutura;

import com.evolute.utils.data.IDObject;
import com.evolute.utils.ui.DialogException;
import java.awt.*;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import siprp.medicina.MedicinaConstants;
import siprp.medicina.MedicinaDataProvider;
import siprp.medicina.processo.*;
import siprp.medicina.processo.data.TrabalhadoresConsultasData;
import siprp.medicina.processo.data.TrabalhadoresProcessoData;

/**
 *
 * @author fpalma
 */
public class EstruturaProcessoPanel extends JPanel
		implements TreeSelectionListener
{
	protected static final DateFormat D_F = DateFormat.getDateInstance( DateFormat.SHORT, new Locale( "pt", "PT" ) );
	
	protected JScrollPane mainScroll;
	protected TrabalhadorMutableTreeNode rootNode;
	protected JTree mainTree;
	
	protected ProcessoDataProvider provider;
	
	protected IDObject trabalhador;
	protected final HashMap<Integer, TrabalhadoresProcessoData> PROCESSOS_POR_ID = 
			new HashMap<Integer,TrabalhadoresProcessoData>();
	
	private final Vector<ProcessoListener> PROCESSO_LISTENERS = new Vector<ProcessoListener>();
	
	/** Creates a new instance of EstruturaProcessoPanel */
	public EstruturaProcessoPanel()
		throws Exception
	{
		provider = ProcessoDataProvider.getProvider();
		setupComponents();
//		setTrabalhador( new MappableObject( new Integer( 12 ), "Alexandre de Matos Monge" ) );
	}
	
	private void setupComponents()
	{
		mainScroll = new JScrollPane();
		mainScroll.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );
		mainScroll.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED );
//		rootNode = new DefaultMutableTreeNode( new MappableObject( new Integer( 12 ), "Frederico Palma" ) );
		rootNode = new TrabalhadorMutableTreeNode( new Integer( -1 ), "" );
		mainTree = new JTree( rootNode );
		mainTree.addTreeSelectionListener( this );
		mainTree.setCellRenderer( new EstruturaProcessoRenderer() );
		mainScroll.setViewportView( mainTree );
		setLayout( new GridLayout( 1, 1 ) );
		add( mainScroll );
		
	}
	
	public void setTrabalhador( IDObject trabalhador )
	{
		clear();
		if( trabalhador == null )
		{
			return;
		}
		this.trabalhador = trabalhador;
//		rootNode.removeAllChildren();
//		PROCESSOS_POR_ID.clear();
		rootNode.setID( trabalhador.getID() );
		rootNode.setDescricao( trabalhador.toString() );
		DefaultMutableTreeNode nodes[] = 
				loadProcessos( trabalhador.getID() );
		rootNode.add( criarProcessoVazio() );
		for( int n = 0; n < nodes.length; n++ )
		{
			rootNode.add( nodes[ n ] );
		}
		int count = mainTree.getRowCount();
		for( int n = count - 1; n >= 0; n-- )
		{
			mainTree.expandRow( n );
		}
	}
	
	protected DefaultMutableTreeNode[] loadProcessos( Integer trabalhadorID )
	{
		try
		{
			Integer ids[] = provider.getIDsProcessosByTrabalhador( trabalhadorID );
			DefaultMutableTreeNode nodes[] = new DefaultMutableTreeNode[ ids.length ];
			for( int n = 0; n < ids.length; n++ )
			{
				nodes[ n ] = loadProcesso( ids[ n ], null );
			}
//System.out.println( "nl: " + nodes.length );
			return nodes;
		}
		catch( Exception ex )
		{
			DialogException.showExceptionMessage( ex, "Erro a carregar dados", true );
			return new DefaultMutableTreeNode[ 0 ];
		}
	}
	
	protected ProcessoMutableTreeNode loadProcesso( Integer id, ProcessoMutableTreeNode node )
		throws Exception
	{
		TrabalhadoresProcessoData processo = provider.getProcessoByID( id );
		Date dataInicio = ( Date ) processo.get( TrabalhadoresProcessoData.DATA_INICIO );
		Date dataFim = ( Date ) processo.get( TrabalhadoresProcessoData.DATA_FIM );
		String codigoEstado = ( String ) processo.get( TrabalhadoresProcessoData.ESTADO );
		String estado = provider.getDescricaoEstadoProcessoByCodigo( codigoEstado );
		String desc = D_F.format( dataInicio );
		Integer motivo = ( Integer ) processo.get( TrabalhadoresProcessoData.MOTIVO );
		desc += ": " + MedicinaDataProvider.MOTIVOS_BY_ID.get( motivo ) + " : " + estado;
		PROCESSOS_POR_ID.put( id, processo );
		ProcessoMutableTreeNode processoNode;
		if( node == null )
		{
			processoNode = new ProcessoMutableTreeNode( id, desc );
		}
		else
		{
			processoNode = node;
			processoNode.setID( id );
			processoNode.setDescricao( desc );
		}
		processoNode.removeAllChildren();
		MarcacaoMutableTreeNode marcacoes[] = loadMarcacoes( id );
//		processoNode.add( new ECDsMutableTreeNode( new Integer( 35 ), "ECDS de 2006/01/01 : Realizado" ) );
		for( int n = 0; n < marcacoes.length; n++ )
		{
			processoNode.add( marcacoes[ n ] );
		}
		
//		processoNode.add( new FichaAptidaoMutableTreeNode( new Integer( 35 ), "Ficha de Aptid\u00e3o de  2006/01/01 : Apto" ) );
		( ( DefaultTreeModel ) mainTree.getModel() ).nodeStructureChanged( processoNode );
		return processoNode;
	}
	
	public MarcacaoMutableTreeNode[] loadMarcacoes( Integer processoID )
	{
		try
		{
			Integer consultaIDs[] = provider.getConsultaIDsForProcesso( processoID );
			Vector<MarcacaoMutableTreeNode> nodesVector = new Vector<MarcacaoMutableTreeNode>();
			for( int n = 0; n < consultaIDs.length; n++ )
			{
				nodesVector.add( loadConsulta( consultaIDs[ n ], null ) );
			}
			
			MarcacaoMutableTreeNode nodes[] = nodesVector.toArray( new MarcacaoMutableTreeNode[ nodesVector.size() ] );
			Arrays.sort( nodes );
			return nodes;
		}
		catch( Exception ex )
		{
			DialogException.showExceptionMessage( ex, "Erro a carregar dados", true );
			return new MarcacaoMutableTreeNode[ 0 ];
		}
	}
	
	public ConsultaMutableTreeNode loadConsulta( Integer id, ConsultaMutableTreeNode node )
		throws Exception
	{
		TrabalhadoresConsultasData consulta = provider.getConsultaByID( id );
		Date data = ( Date ) consulta.get( TrabalhadoresConsultasData.DATA );
		Integer estado = ( Integer ) consulta.get( TrabalhadoresConsultasData.ESTADO );
		String estadoStr = MedicinaConstants.ESTADOS_CONSULTA_STR[ estado != null ? estado.intValue() : 0 ];
		
		String desc = "Consulta de " + ( data != null ? D_F.format( data ) : "--" );
		desc += ": " + estadoStr;
		ConsultaMutableTreeNode consultaNode;
		if( node == null )
		{
			consultaNode = new ConsultaMutableTreeNode( id, desc );
			consultaNode.setData( data );
		}
		else
		{
			consultaNode = node;
			consultaNode.setID( id );
			consultaNode.setDescricao( desc );
			consultaNode.setData( data );
		}
		consultaNode.removeAllChildren();
		Object datas[][] = provider.getDatasConsulta( id );
		for( int n = 0; n < datas.length; n++ )
		{
			Integer dataID = ( Integer ) datas[ n ][ 0 ];
			Date dataData = ( Date ) datas[ n ][ 1 ];
			Integer dataEstado = ( Integer ) datas[ n ][ 2 ];
			String dataEstadoStr = MedicinaConstants.ESTADOS_CONSULTA_STR[ dataEstado != null ? dataEstado.intValue() : 0 ];
			String dataDesc = D_F.format( dataData ) + ": " + dataEstadoStr;
			DataMutableTreeNode dataNode = new DataMutableTreeNode( dataID, dataDesc );
			IDObject observacoes = provider.getObservacoesConsultaData( dataID );
			if( observacoes != null )
			{
				ObservacoesMutableTreeNode observacoesNode = new ObservacoesMutableTreeNode( observacoes.getID(), observacoes.toString() );
				dataNode.add( observacoesNode );
			}
			IDObject emails[] = provider.getEmailConsultaData( dataID );
			for( int em = 0; em < emails.length; em++ )
			{
				MailMutableTreeNode mailNode = new MailMutableTreeNode( emails[ em ].getID(), emails[ em ].toString() );
				dataNode.add( mailNode );
			}
			consultaNode.add( dataNode );
		}
		
		( ( DefaultTreeModel ) mainTree.getModel() ).nodeStructureChanged( consultaNode );
		return consultaNode;
	}
	
	public void valueChanged( TreeSelectionEvent e )
	{
		Object components[] = e.getPath().getPath();
		int tipo = ProcessoEvent.ACCAO_ESCOLHER_PROCESSO;
		if( components == null || components.length == 0 || 
			components[ components.length - 1 ] instanceof TrabalhadorMutableTreeNode ||
			components[ components.length - 1 ] instanceof ProcessoMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_PROCESSO;
		}
		else if( components[ components.length - 1 ] instanceof ConsultaMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_CONSULTA;
		}
		else if( components[ components.length - 1 ] instanceof ECDsMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_ECDS;
		}
		else if( components[ components.length - 1 ] instanceof FichaAptidaoMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_FA;
		}
		else if( components[ components.length - 1 ] instanceof DataMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_DATA;
		}
		else if( components[ components.length - 1 ] instanceof ObservacoesMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_OBSERVACOES;
		}
		else if( components[ components.length - 1 ] instanceof MailMutableTreeNode )
		{
			tipo = ProcessoEvent.ACCAO_ESCOLHER_MAIL;
		}
		HashMap<Integer,Integer> ids = new HashMap<Integer,Integer>();
		for( int n = 0; components != null && n < components.length; n++ )
		{
			Integer id = ( ( EstruturaProcessoMutableTreeNode ) components[ n ] ).getID();
			if(	components[ n ] instanceof ProcessoMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_PROCESSO, id );
			}
			else if( components[ n ] instanceof ConsultaMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_CONSULTA, id );
			}
			else if( components[ n ] instanceof ECDsMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_ECDS, id );
			}
			else if( components[ n ] instanceof FichaAptidaoMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_FICHA_APTIDAO, id );
			}
			else if( components[ n ] instanceof DataMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_DATA, id );
			}
			else if( components[ n ] instanceof ObservacoesMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_OBSERVACOES, id );
			}
			else if( components[ n ] instanceof MailMutableTreeNode )
			{
				ids.put( ProcessoEvent.TIPO_MAIL, id );
			}
		}
		ProcessoEvent event = new ProcessoEvent( this, tipo, ids );
		for( int n = 0; n < PROCESSO_LISTENERS.size(); n++ )
		{
			PROCESSO_LISTENERS.get( n ).processoStateChanged( event );
		}
	}
//	
//	public TrabalhadoresProcessoData getProcessoEscolhido()
//	{
//		TreePath path = mainTree.getSelectionPath();
//		TrabalhadoresProcessoData processo = null;
//		if( path != null )
//		{
//			EstruturaProcessoMutableTreeNode escolhido = ( EstruturaProcessoMutableTreeNode ) path.getLastPathComponent();
//			if( escolhido != null )
//			{
//				processo = PROCESSOS_POR_ID.get( escolhido.getID() );
//				if( processo == null )
//				{
//					processo = new TrabalhadoresProcessoData();
//					PROCESSOS_POR_ID.put( escolhido.getID(), processo );
//				}
//			}
//		}
//		
//		return processo;
//	}
	
	public void addProcessoListener( ProcessoListener listener )
	{
		PROCESSO_LISTENERS.add( listener );
	}
	
	public void removeProcessoListener( ProcessoListener listener )
	{
		PROCESSO_LISTENERS.remove( listener );
	}
	
	public IDObject getTrabalhador()
	{
		return trabalhador;
	}
	
	public void actualizarProcessoEscolhido( Integer id )
		throws Exception
	{
		TreePath path = mainTree.getSelectionPath();
		Enumeration<TreePath> expandedDescendants = mainTree.getExpandedDescendants( path );
		ProcessoMutableTreeNode processoNode = ( ProcessoMutableTreeNode ) path.getPathComponent( 1 );
		boolean vazio = processoNode.getID().intValue() == -1;
		loadProcesso( id, processoNode );
		( ( DefaultTreeModel ) mainTree.getModel() ).nodeChanged( processoNode ) ;
		if( vazio )
		{
			ProcessoMutableTreeNode novo = criarProcessoVazio();
			rootNode.insert( novo, 0 );
			( ( DefaultTreeModel ) mainTree.getModel() ).nodesWereInserted( rootNode, new int[]{ 0 } ) ;
		}
		mainTree.expandPath( path );
		mainTree.setSelectionPath( path );
//		while( expandedDescendants.hasMoreElements() )
//		{
//			mainTree.expandPath( expandedDescendants.nextElement() );
//		}
	}
	
	public void actualizarMarcacaoEscolhida( Integer processoID, Integer marcacaoID )
		throws Exception
	{
		TreePath path = mainTree.getSelectionPath();
		Enumeration<TreePath> expandedDescendants = mainTree.getExpandedDescendants( path );
		ProcessoMutableTreeNode processoNode = ( ProcessoMutableTreeNode ) path.getPathComponent( 1 );
		int countOld = processoNode.getChildCount();
		actualizarProcessoEscolhido( processoID );
		int count = processoNode.getChildCount();
		if( count > countOld )
		{
			( ( DefaultTreeModel ) mainTree.getModel() ).nodesWereInserted( processoNode, new int[]{ countOld } ) ;
		}
		mainTree.expandPath( path );
//		mainTree.expandPath( path );
//		while( expandedDescendants.hasMoreElements() )
//		{
//			mainTree.expandPath( expandedDescendants.nextElement() );
//		}
//		TreePath path = mainTree.getSelectionPath();
//		MarcacaoMutableTreeNode processoNode = ( ProcessoMutableTreeNode ) path.getPathComponent( 1 );
//		boolean vazio = processoNode.getID().intValue() == -1;
//		loadProcesso( id, processoNode );
//		( ( DefaultTreeModel ) mainTree.getModel() ).nodeChanged( processoNode ) ;
//		if( vazio )
//		{
//			ProcessoMutableTreeNode novo = criarProcessoVazio();
//			rootNode.insert( novo, 0 );
//			( ( DefaultTreeModel ) mainTree.getModel() ).nodesWereInserted( rootNode, new int[]{ 0 } ) ;
//		}
	}
	
	public ProcessoMutableTreeNode criarProcessoVazio()
	{
		return new ProcessoMutableTreeNode( new Integer( -1 ), "Novo Processo..." );
	}
	
	public void reload()
	{
	}
	
	public void clear()
	{
		mainTree.clearSelection();
		mainTree.setRootVisible( true );
		this.trabalhador = null;
		rootNode.removeAllChildren();
		PROCESSOS_POR_ID.clear();
		rootNode.setID( null );
		rootNode.setDescricao( "" );
		( ( DefaultTreeModel ) mainTree.getModel() ).nodeStructureChanged( rootNode );
	}
}
