package org.lucci.madhoc.simulation.monitor;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import org.lucci.madhoc.gui.MonitorView;
import org.lucci.madhoc.network.Application;
import org.lucci.madhoc.simulation.Monitor;
import org.lucci.madhoc.simulation.measure.NumericalMeasureHistory;
import org.lucci.madhoc.simulation.measure.NumericalSensor;
import org.lucci.madhoc.simulation.measure.Sensor;

/*
 * Created on Jul 3, 2004
 */

/**
 * @author luc.hogie
 */
public class NumericalMeasuresTableView extends MonitorView
{
    private List<NumericalSensor> sensors = new Vector<NumericalSensor>();
    private JTable table;

    public void setMonitor(Monitor app)
    {
        super.setMonitor(app);
        
        setLayout(new GridLayout(1, 1));
        add(new JScrollPane(getTable()));
        getTable().setOpaque(true);
        getTable().setBackground(app.getColor());
        getTable().getTableHeader().setReorderingAllowed(true);
        getTable().setCellSelectionEnabled(false);

        
        getTable().getSelectionModel().addListSelectionListener(new TableSelectionHandler());
        getTable().setDefaultEditor(Object.class, null);
        getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        getTable().setOpaque(false);
        getTable().setDefaultRenderer(Object.class, new ColoredCellRenderer());
        Object[] columnNames = new Object[] {"Measure", "Unit", "Last value", "Minimum", "Maximum", "Average", "Standard deviation"};
        getTable().getTableHeader().setReorderingAllowed(false);
        getTable().getTableHeader().setResizingAllowed(true);

        harvestSensors();
        DefaultTableModel model = new DefaultTableModel(columnNames, sensors.size());
//      TableSorter tableSorterModel = new TableSorter(model);
//      tableSorterModel.setTableHeader(getTable().getTableHeader());
        getTable().setModel(model);
    }

    private void harvestSensors()
    {
        List<Monitor> monitors = new Vector<Monitor>(getMonitor().getNetwork().getMonitorMap().values());
        Collections.sort(monitors, new Comparator<Monitor>()
                {
                    public int compare(Monitor arg0, Monitor arg1)
                    {
                        return arg0.getName().compareTo(arg1.getName());
                    }
                });

        for (Monitor app  : monitors)
        {
            List<NumericalSensor> sensors = new Vector<NumericalSensor>(app.getNumericalMeasures());
            Collections.sort(sensors, new Comparator<NumericalSensor>()
                    {
                        public int compare(NumericalSensor arg0, NumericalSensor arg1)
                        {
                            return arg0.getName().compareTo(arg1.getName());
                        }
                    });
            this.sensors.addAll(sensors);
        }
    }

    
    public JTable getTable()
    {
        if (table == null)
        {
            table = new JTable();
        }
    
        return table;
    }
    
    public String getName()
    {
        return "Numerical measures";
    }

    /* (non-Javadoc)
     * @see org.lucci.madhoc.ui.ApplicationView#updateView()
     */
    public void updateViewContent()
    {
        // defines the rows
        TableModel model = getTable().getModel();
        
        for (int row = 0; row < sensors.size(); ++row)
        {
            Sensor m = (Sensor) sensors.get(row);
            model.setValueAt(m, row, 0);
            model.setValueAt(m, row, 1);
            model.setValueAt(m, row, 2);
            model.setValueAt(m, row, 3);
            model.setValueAt(m, row, 4);
            model.setValueAt(m, row, 5);
            model.setValueAt(m, row, 6);
        }

        getTable().repaint(0);
    }
    
    public class TableSelectionHandler implements ListSelectionListener
    {
        /* (non-Javadoc)
         * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
         */
        public void valueChanged(ListSelectionEvent event)
        {
            if (event.getValueIsAdjusting())
            {
                int selectedRow = getTable().getSelectedRow();

                if (selectedRow >= 0)
                {
                    NumericalSensor measure = (NumericalSensor) sensors.get(selectedRow);
                    NumericalMeasures2DGraphicalView xyView = (NumericalMeasures2DGraphicalView) getProjectionComponent().getMonitorViews().get(NumericalMeasures2DGraphicalView.class);

                    if (xyView.getSelectXCheckbox().isSelected())
                    {
                        xyView.setXMeasure(measure);
                    }

                    if (xyView.getSelectYCheckbox().isSelected())
                    {
                        xyView.setYMeasure(measure);
                    }

                    xyView.updateViewContent();
                }
            }
        }
    }
    

    public class ColoredCellRenderer extends JLabel implements TableCellRenderer
    {
        public ColoredCellRenderer()
        {
            setOpaque(true);
        }

        /*
         * (non-Javadoc)
         * 
         * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable,
         *      java.lang.Object, boolean, boolean, int, int)
         */
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
        {
            Sensor sensor = (Sensor) value;
            
            if (value != null)
            {
                Monitor app = sensor.getMonitor();
                Color color = app.getColor();
                setBackground(color);
                setText(getColumnValue((NumericalMeasureHistory) getProjectionComponent().getProjection().getMeasureHistoryMap().get(sensor), column));
            }

            return this;
        }
        
        String getColumnValue(NumericalMeasureHistory m, int column)
        {
            String undefinedCellText = "-";

            if (m.getValues().isEmpty())
            {
                if (column == 0) return m.getSensor().getName();
                if (column == 1) return m.getNumericalSensor().getUnit() == null ? undefinedCellText : m.getNumericalSensor().getUnit().getFormattedName();
                if (column == 2) return undefinedCellText;
                if (column == 3) return undefinedCellText;
                if (column == 4) return undefinedCellText;
                if (column == 5) return undefinedCellText;
                if (column == 6) return undefinedCellText;
                else throw new IllegalStateException();
            }
            else
            {
                if (column == 0) return m.getNumericalSensor().getName();
                if (column == 1) return m.getNumericalSensor().getUnit() == null ? undefinedCellText : m.getNumericalSensor().getUnit().getFormattedName();
                if (column == 2) return getStringValueOf((Double) m.getLastValue());
                if (column == 3) return getStringValueOf(m.getMinimum());
                if (column == 4) return getStringValueOf(m.getMaximum());
                if (column == 5) return getStringValueOf(m.getAverage());
                if (column == 6) return getStringValueOf(m.getStandardDeviation());
                else throw new IllegalStateException();
            }
        }
        
        private String getStringValueOf(Double d)
        {
            if (d == null)
            {
                return "-";
            }
            else
            {
                double dd = d.doubleValue();
        
                if ((int) dd == dd)
                {
                    return String.valueOf((int) dd);
                }
                else
                {
                    return d.toString();
                }
            }
        }
    }


    public void configure() throws Throwable
    {
        // TODO Auto-generated method stub
        
    }
}