/* @(#)$RCSfile$ 
 * $Revision$ $Date$ $Author$
 */
package org.knime.example;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JMenu;
import javax.swing.JMenuItem;

import org.knime.core.data.DataCell;
import org.knime.core.node.NodeModel;
import org.knime.core.node.NodeView;
import org.knime.core.node.property.hilite.HiLiteHandler;

/**
 * <code>NodeView</code> for the "NumericBinner" Node.
 * 
 *
 * @author Fabian Dill, University of Konstanz
 */
public class NumericBinnerNodeView extends NodeView {
    
    private JMenuItem m_hilite;
    
    private JMenuItem m_unhilite;
    
    private Set<NumericBin>m_selected;
    
    private int m_numberOfHilitedBins = 0;
    

    // panel which actually paints the bins
    private NumericBinnerViewPanel m_panel;
    
    /**
     * Creates a new view.
     * 
     * @param nodeModel the model class: {@link NumericBinnerNodeModel}
     */
    protected NumericBinnerNodeView(final NodeModel nodeModel) {
        super(nodeModel);
        // get the bins
        final NumericBin[] bins = ((NumericBinnerNodeModel)getNodeModel())
        	.getBinRepresentations();
        if (bins != null && bins.length > 0) {
            // create the panel that draws the bins
            m_panel = new NumericBinnerViewPanel(bins);
        } 
        // sets the view content in the node view
        setComponent(m_panel);
        
        //************* mouse listener for selection of a bin *****************
        
        // add a mouse listener in order to determine the selected bins
        m_selected = new HashSet<NumericBin>();
        m_panel.addMouseListener(new MouseAdapter() {

            /**
             * @see java.awt.event.MouseAdapter#mouseReleased(
             * java.awt.event.MouseEvent)
             */
            @Override
            public void mouseReleased(final MouseEvent e) {
                if (!e.isControlDown()) {
                    m_selected.clear();
                    for (NumericBin bin : m_panel.getBins()) {
                        bin.setSelected(false);
                    }
                }
                for (NumericBin bin : m_panel.getBins()) {
                    if (bin.getViewRepresentation() != null &&
                    		bin.getViewRepresentation().contains(
                    				e.getX(), e.getY())){
                        bin.setSelected(true);
                        m_selected.add(bin);
                        break;
                    }
                }
                // update the hilite menu
                if (m_selected.size() > 0) {
                    m_hilite.setEnabled(true);
                } else {
                    m_hilite.setEnabled(false);
                }
                
                if (m_numberOfHilitedBins > 0 && m_selected.size() > 0) {
                    m_unhilite.setEnabled(true);
                } else {
                    m_unhilite.setEnabled(false);
                }
                m_panel.repaint();
            }
        });
        
        //************** the hilite menu **************************
        
        // create the hilite menu 
        // the HiliteHandler provides standard names 
        m_hilite = new JMenuItem(HiLiteHandler.HILITE_SELECTED);
        m_hilite.setEnabled(false);
        m_hilite.addActionListener(new ActionListener() {

            /**
             * @see java.awt.event.ActionListener#actionPerformed(
             * java.awt.event.ActionEvent)
             */
            public void actionPerformed(final ActionEvent e) {
                Set<DataCell> toBeHilited = new HashSet<DataCell>();
                for (NumericBin bin : m_selected) {
                    // store all row ids from the selected bin
                    toBeHilited.addAll(bin.getContainedRowIds());
                    // set the bin hilited
                    bin.setHilited(true);
                    // count the number of hilited bins for a 
                    // correct menu display (see below)
                    m_numberOfHilitedBins++;
                }
                // now get the hilite handler and hilite the rows
                getNodeModel().getInHiLiteHandler(
                        NumericBinnerNodeModel.IN_PORT).fireHiLiteEvent(toBeHilited);
                // and repaint to have the hilited bins displayed correctly
                m_panel.repaint();
            }
            
        });
        m_unhilite = new JMenuItem(HiLiteHandler.UNHILITE_SELECTED);
        m_unhilite.setEnabled(false);
        m_unhilite.addActionListener(new ActionListener() {

            /**
             * @see java.awt.event.ActionListener#actionPerformed(
             * java.awt.event.ActionEvent)
             */
            public void actionPerformed(final ActionEvent e) {
                Set<DataCell> toBeUnhilited = new HashSet<DataCell>();
                for (NumericBin bin : m_selected) {
                    // store all row ids that should be unhilited
                    toBeUnhilited.addAll(bin.getContainedRowIds());
                    // unhilite the bin
                    bin.setHilited(false);
                    // decrease the number of hilited bins
                    m_numberOfHilitedBins--;
                }
                // get the hilite handler and unhilite the rows
                getNodeModel().getInHiLiteHandler(
                        NumericBinnerNodeModel.IN_PORT).fireUnHiLiteEvent(toBeUnhilited);
                // repaint to have the bins displayed correctly
                m_panel.repaint();
            }
            
        });
        
        JMenuItem clear = new JMenuItem(HiLiteHandler.CLEAR_HILITE);
        clear.addActionListener(new ActionListener() {

            /**
             * @see java.awt.event.ActionListener#actionPerformed(
             * java.awt.event.ActionEvent)
             */
            public void actionPerformed(final ActionEvent e) {
                // get the hilite handler and unhilite all
                getNodeModel().getInHiLiteHandler(
                        NumericBinnerNodeModel.IN_PORT).fireClearHiLiteEvent();
                // unhilite all bins
                for (NumericBin bin : m_panel.getBins()) {
                    bin.setHilited(false);
                }
                // no bin is hilited anymore
                m_numberOfHilitedBins = 0;
                // repaint to display the bins correctly
                m_panel.repaint();
            } 
        });
        // create the menu and all the menu items to it
        JMenu menu = new JMenu(HiLiteHandler.HILITE);
        menu.add(m_hilite);
        menu.add(m_unhilite);
        menu.add(clear);
        // get the JMenu bar of the NodeView and add this menu to it
        getJMenuBar().add(menu);        
    }

    /**
     * @see de.unikn.knime.core.node.NodeView#modelChanged()
     */
    @Override
    protected void modelChanged() {
        // if the model had changed get the new bins
        NumericBin[] bins = ((NumericBinnerNodeModel)getNodeModel())
        .getBinRepresentations();
        if (bins != null && bins.length > 0 && m_panel != null) {
            // and paint the bins
            ((NumericBinnerViewPanel)m_panel).updateView(bins);
        }
    }

    /**
     * @see de.unikn.knime.core.node.NodeView#onClose()
     */
    @Override
    protected void onClose() {
    }

    /**
     * @see de.unikn.knime.core.node.NodeView#onOpen()
     */
    @Override
    protected void onOpen() {
    }

}
