package siprp.higiene.relatorio;

import static com.evolute.utils.strings.UnicodeLatin1Map.atilde;
import static com.evolute.utils.strings.UnicodeLatin1Map.ccedil;
import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstraints;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import leaf.ui.LeafButton;
import leaf.ui.LeafDialog;
import leaf.ui.LeafIconButton;
import leaf.ui.LeafTree;
import leaf.ui.TreeInserterDialog;
import siprp.database.cayenne.objects.HsPostoRisco;
import siprp.database.cayenne.objects.HsRelatorioMedida;
import siprp.database.cayenne.objects.HsRelatorioPosto;
import siprp.database.cayenne.objects.HsRelatorioPostoMedida;
import siprp.database.cayenne.objects.HsRelatorioPostoRisco;
import siprp.database.cayenne.objects.HsRelatorioRisco;
import siprp.database.cayenne.objects.HsRisco;
import siprp.logic.HigieneSegurancaLogic;
import siprp.logic.node.MedidaRelatorioNode;
import siprp.logic.node.NodeRisco;
import siprp.logic.node.RiscoRelatorioNode;

import com.evolute.utils.ui.trees.TreeTools;

public class GerirMedidasRelatorioPanel extends JPanel
{

	private static final long serialVersionUID = 1L;

	public static final String SELECTION_CHANGED = "RISCOS_SELECTION_CHANGED";

	public static final String VALUE_CHANGED = "VALUE_CHANGED";

	private static final String ICON_NAME_SAVE = "siprp/higiene/gestao/add.png";

	private static final String ICON_NAME_REVERT = "siprp/higiene/gestao/delete.png";
	
	private final LeafButton buttonAdicionar = LeafIconButton.createButton( ICON_NAME_SAVE );

	private final LeafButton buttonRemover = LeafIconButton.createButton( ICON_NAME_REVERT );

	private final DefaultMutableTreeNode root = new DefaultMutableTreeNode();

	private final DefaultTreeModel model = new DefaultTreeModel( root );

	public final LeafTree tree = new LeafTree( model );

	private final JScrollPane scroll = new JScrollPane( tree );

	private HsRelatorioPosto posto = null;
	
	private HsRelatorioPostoMedida selectedMedida = null;

	public GerirMedidasRelatorioPanel()
	{
		startupComponents();
		setupLayout();
		placeComponents();
		startupListeners();
	}

	private void startupComponents()
	{
		buttonAdicionar.setEnabled( false );
		buttonRemover.setEnabled( false );
		tree.setRootVisible( false );
		tree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
		tree.setCellRenderer( new DefaultTreeCellRenderer()
		{

			private static final long serialVersionUID = 1L;

			public Component getTreeCellRendererComponent( JTree pTree, Object pValue, boolean pIsSelected, boolean pIsExpanded, boolean pIsLeaf, int pRow, boolean pHasFocus )
			{
				super.getTreeCellRendererComponent( pTree, pValue, pIsSelected, pIsExpanded, pIsLeaf, pRow, pHasFocus );
				boolean highlight = false;
				Color highColor = null;
				Color lowColor = null;
				if( pValue instanceof RiscoRelatorioNode )
				{
					Object userObject = ((RiscoRelatorioNode) pValue).getUserObject();
					if( userObject instanceof HsRelatorioPostoRisco )
					{
						highlight = HigieneSegurancaLogic.isRelatorioRiscoPreenchido( (HsRelatorioPostoRisco) userObject );
						highColor = RelatorioHigieneSegurancaWindow.COLOR_RISCO_OK_SEL;
						lowColor = RelatorioHigieneSegurancaWindow.COLOR_RISCO_OK;
					}
				}
				else if( pValue instanceof MedidaRelatorioNode )
				{
					Object userObject = ((MedidaRelatorioNode) pValue).getUserObject();
					if( userObject instanceof HsRelatorioPostoMedida )
					{
						HsRelatorioPostoMedida medida = (HsRelatorioPostoMedida) userObject;
						if( medida.getIsPlanoActuacao() != null )
						{
							highlight = medida.getIsPlanoActuacao();
							highColor = RelatorioHigieneSegurancaWindow.COLOR_MEDIDA_OK_SEL;
							lowColor = RelatorioHigieneSegurancaWindow.COLOR_MEDIDA_OK;
						}
					}
				}
				if( highlight )
				{
					setOpaque( true );
					setBackground( pIsSelected ? highColor : lowColor );
				}
				else
				{
					setOpaque( false );
				}
				return (this);
			}
		} );
	}

	private void setupLayout()
	{
		TableLayout layout = new TableLayout( new double[] {
			TableLayout.FILL
		}, new double[] {
				TableLayout.MINIMUM, TableLayout.FILL
		} );
		layout.setHGap( 5 );
		layout.setVGap( 5 );
		setLayout( layout );
	}

	private void placeComponents()
	{
		JPanel panel = new JPanel();
		TableLayout layout = new TableLayout( new double[] {
				TableLayout.MINIMUM, TableLayout.MINIMUM, TableLayout.FILL
		}, new double[] {
			TableLayout.MINIMUM
		} );
		layout.setHGap( 5 );
		layout.setVGap( 5 );
		panel.setLayout( layout );
		panel.add( buttonAdicionar, new TableLayoutConstraints( 0, 0 ) );
		panel.add( buttonRemover, new TableLayoutConstraints( 1, 0 ) );

		add( panel, new TableLayoutConstraints( 0, 0 ) );
		add( scroll, new TableLayoutConstraints( 0, 1 ) );
	}

	private void startupListeners()
	{
		tree.getSelectionModel().addTreeSelectionListener( new TreeSelectionListener()
		{
			@Override
			public void valueChanged( TreeSelectionEvent e )
			{
				Object object = null;
				TreePath path = tree.getSelectionPath();
				if( path != null )
				{
					Object selection = path.getLastPathComponent();
					if( selection instanceof RiscoRelatorioNode )
					{
						object = selection == null ? null : ((RiscoRelatorioNode) selection).getUserObject();

					}
					else if( selection instanceof MedidaRelatorioNode )
					{
						object = selection == null ? null : ((MedidaRelatorioNode) selection).getUserObject();
						selectedMedida = (HsRelatorioPostoMedida) object;
					}
				}
				setEnabled();
				firePropertyChange( SELECTION_CHANGED, null, object );
			}
		} );
		buttonAdicionar.addActionListener( new ActionListener()
		{

			@Override
			public void actionPerformed( ActionEvent e )
			{
				add();

			}

		} );
		buttonRemover.addActionListener( new ActionListener()
		{

			@Override
			public void actionPerformed( ActionEvent e )
			{
				rem();
			}

		} );
	}

	private HsRelatorioPostoRisco getSelectedRisco()
	{
		HsRelatorioPostoRisco result = null;
		TreePath path = tree.getSelectionPath();
		if( path != null )
		{
			Object selection = path.getLastPathComponent();
			if( selection instanceof RiscoRelatorioNode )
			{
				result = selection == null ? null : (HsRelatorioPostoRisco) ((RiscoRelatorioNode) selection).getUserObject();
			}
		}
		return result;
	}

	private HsRelatorioPostoMedida getSelectedMedida()
	{
		HsRelatorioPostoMedida result = null;
		TreePath path = tree.getSelectionPath();
		if( path != null )
		{
			Object selection = path.getLastPathComponent();
			if( selection instanceof MedidaRelatorioNode )
			{
				result = selection == null ? null : (HsRelatorioPostoMedida) ((MedidaRelatorioNode) selection).getUserObject();
			}
		}
		return result;
	}

	private void add()
	{
		try
		{
			DefaultMutableTreeNode allRiscos = getAllRiscos();
			TreeTools.removeAll( allRiscos, getRiscosTree() );
			TreeInserterDialog dialog = new TreeInserterDialog( "Adicionar Riscos", allRiscos );
			DefaultMutableTreeNode result = dialog.getResult();
			if( result != null )
			{
				addResult( result );
				refresh();
			}
			setEnabled();
		}
		catch( Exception e )
		{
			LeafDialog.error( e );
		}
	}

	private DefaultMutableTreeNode getAllRiscos()
	{
		DefaultMutableTreeNode result = new DefaultMutableTreeNode();
		if( posto != null )
		{
			result = HigieneSegurancaLogic.getRiscosTree( posto.getToHsRelatorioArea().getToHsRelatorio().getToHsMarcacoesEstabelecimento().getToEstabelecimentos().getToEmpresas() );
		}
		return result;
	}

	private DefaultMutableTreeNode getRiscosTree()
	{
		DefaultMutableTreeNode result = new DefaultMutableTreeNode();
		for( int i = 0; i < root.getChildCount(); ++i )
		{
			DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) root.getChildAt( i );
			HsRelatorioPostoRisco relPostoRisco = null;
			if( childNode instanceof RiscoRelatorioNode )
			{
				relPostoRisco = (HsRelatorioPostoRisco) ((RiscoRelatorioNode) childNode).getUserObject();
			}
			HsRelatorioRisco relRisco = relPostoRisco == null ? null : relPostoRisco.getToHsRelatorioRisco();
			if( relRisco != null )
			{
				HsRisco risco = HigieneSegurancaLogic.findHsRiscoFor( relRisco );
				if( risco != null )
				{
					result.add( new NodeRisco( risco ) );
				}
			}
		}
		return result;
	}

	private void addResult( DefaultMutableTreeNode root )
	{
		if( root != null )
		{
			if( root instanceof NodeRisco )
			{
				HsRisco risco = (HsRisco) ((NodeRisco)root).getUserObject();
				addRisco( risco );
			}
			for( int i = 0; i < root.getChildCount(); ++i )
			{
				addResult( (DefaultMutableTreeNode) root.getChildAt( i ) );
			}
		}
	}
	
	private void addRisco( HsRisco risco )
	{
		if( posto != null )
		{
			Integer order = 0;
			List<HsPostoRisco> toPostos = risco.getHsPostoRiscoArray();
			if( !toPostos.isEmpty() )
			{
				for (HsPostoRisco hsPostoRisco : toPostos)
				{
					order = Math.max(order, hsPostoRisco.getOrder() == null ? 0 : hsPostoRisco.getOrder() );
				}
			}
			HigieneSegurancaLogic.addRiscoToRelatorioPosto( risco, order+1, posto );
		}
	}

	private boolean confirm( String message )
	{
		return JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog( this, message, "Confirma"+ccedil+atilde+"o", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null );
	}
	
	private void rem()
	{
		for( TreePath path : tree.getSelectionPaths() )
		{
			if( !rem(path) )
			{
				break;
			}
		}
		refresh();
		setEnabled();
	}
	
	
	private String shortenString( String string )
	{
		return string == null ? null : (string.length() <= 40 ? string : (string.substring(0,40) + "..."));
	}
	
	
	private boolean rem(TreePath path)
	{
		boolean outcome = false;
		try
		{
			if( path != null )
			{
				Object selection = path.getLastPathComponent();
				if( selection instanceof MedidaRelatorioNode )
				{
					HsRelatorioPostoMedida rel = selection == null ? null : (HsRelatorioPostoMedida) ((MedidaRelatorioNode) selection).getUserObject();
					if( confirm("Tem a certeza que deseja remover o requisito '" + shortenString( rel.getToHsRelatorioMedida().toString() ) + "'?") )
					{
						rel.getToHsRelatorioMedida().setDeletedDate( new Date() );
						rel.delete();
						outcome = true;
					}
				}
				else if( selection instanceof RiscoRelatorioNode )
				{
					HsRelatorioPostoRisco rel = (HsRelatorioPostoRisco) ((RiscoRelatorioNode)selection).getUserObject();
					if( confirm("Tem a certeza que deseja remover o risco '" + shortenString( rel.getToHsRelatorioRisco().toString() ) + "'?")  )
					{
						for( HsRelatorioMedida medida : rel.getToHsRelatorioRisco().getHsRelatorioMedidaArray() )
						{
							while( true )
							{
								List<HsRelatorioPostoMedida> list = medida.getHsRelatorioPostoMedidaArray();
								HsRelatorioPostoMedida relMedida = list.isEmpty() ? null : list.get(0);
								if( relMedida != null )
								{
									relMedida.delete();
								}
								else
								{
									break;
								}
							}
							medida.setDeletedDate( new Date() );
						}
						rel.getToHsRelatorioRisco().setDeletedDate( new Date() );
						outcome = true;
					}
				}
			}
		}
		catch( Exception e )
		{
			LeafDialog.error( e );
		}
		return outcome;
	}

	private void setEnabled()
	{
		boolean add = false;
		boolean rem = false;
		if( posto != null )
		{
			if( posto.getToHsRelatorioArea() != null && posto.getToHsRelatorioArea().getToHsRelatorio() != null && posto.getToHsRelatorioArea().getToHsRelatorio().getIsSubmetido() == null )
			{
				add = true;
				rem = true;
			}
		}
		buttonAdicionar.setEnabled( add );
		buttonRemover.setEnabled( rem && ( getSelectedMedida() != null || getSelectedRisco() != null ) );
	}

	public void refresh()
	{
		root.removeAllChildren();
		if( posto != null )
		{
			List<HsRelatorioPostoRisco> list = posto.getHsRelatorioPostoRiscoArray();
			Collections.sort( list );
			for( HsRelatorioPostoRisco rel : list )
			{
				RiscoRelatorioNode node = new RiscoRelatorioNode( rel );
				HsRelatorioRisco risco = rel.getToHsRelatorioRisco();
				if( risco.getDeletedDate() == null )
				{
					for( HsRelatorioMedida medida : risco.getHsRelatorioMedidaArray() )
					{
						for( HsRelatorioPostoMedida medidaRel : medida.getHsRelatorioPostoMedidaArray() )
						{
							node.add( new MedidaRelatorioNode( medidaRel ) );
						}
					}
					root.add( node );
				}
			}
		}
		setEnabled();
		TreeTools.sort( root, new Comparator<DefaultMutableTreeNode>()
		{
			@Override
			public int compare( DefaultMutableTreeNode o1, DefaultMutableTreeNode o2 )
			{
				Integer result = null; 
				if( (o1 instanceof RiscoRelatorioNode) && o2 instanceof RiscoRelatorioNode )
				{
					HsRelatorioPostoRisco risco1 = (HsRelatorioPostoRisco) o1.getUserObject();
					HsRelatorioPostoRisco risco2 = (HsRelatorioPostoRisco) o2.getUserObject();
					if( risco1 != null )
					{
						return risco1.compareTo( risco2 == null ? null : risco2 );
					}
				}
				return result == null ? o1.toString().compareTo( o2.toString() ) : result;
			}
		});
		TreeTools.refreshTree( tree, root, false );
		if( selectedMedida != null )
		{
			selectMedida();
		}
	}
	
	private void selectMedida( )
	{
		DefaultMutableTreeNode node = TreeTools.findNodeWithUserObject( selectedMedida, root );
		if( node != null )
		{
			TreePath path = TreeTools.getPathFor( node );
			if( path != null )
			{
				tree.setSelectionPath( path );
			}
		}
		else
		{
			selectedMedida = null;
		}
	}

	public void setPosto( HsRelatorioPosto posto )
	{
		this.posto = posto;
		this.selectedMedida = null;
		refresh();
		setEnabled();
	}

}
