
package event.editor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;

enum UpdateType
{
    Add, Remove, TitleChange
}

class PropertyUpdate
{
    private UpdateType type;
    private PropertyPanel panel;
    private int position = -1;

    public PropertyUpdate(UpdateType theType, PropertyPanel thePanel)
    {
        type = theType;
        panel = thePanel;
    }

    public PropertyUpdate(UpdateType theType, PropertyPanel thePanel, int thePosition)
    {
        this(theType, thePanel);
        position = thePosition;
    }

    public int getPosition()
    {
        if (position == -1)
        {
            throw new RuntimeException("position unknown");
        }

        return position;
    }

    public UpdateType getType()
    {
        return type;
    }
    
    public PropertyPanel getPanel()
    {
        return panel;
    }
}

enum PropertyTypes
{
    Optional, Multiple;
}

class PropertyPanel
{
    private final JPanel panel;
    private final Properties property;
    
    public PropertyPanel(JPanel thePanel,
            Properties theProperty)
    {
        panel = thePanel;
        property = theProperty;
    }

    public JPanel getPanel()
    {
        return panel;
    }
    
    public Properties getProperty()
    {
        return property;
    }

    public String title()
    {
        return property.getTitle();
    }
}

class MultPropertyPanel extends PropertyPanel
{
    private int index;

    public MultPropertyPanel(JPanel thePanel,
            Properties theProperty,
            int theIndex)
    {
        super(thePanel, theProperty);
        index = theIndex;
    }

    public int getIndex()
    {
        return index;
    }

    public void setIndex(int newIndex)
    {
        index = newIndex;
    }

    @Override
    public String title()
    {
        return super.title() + " " + index;
    }
}

class PropertyPanels extends Observable
{
    private Vector<PropertyPanel> properties = new Vector<PropertyPanel>();

    private EnumMap<Properties, Integer> propertyCounter =
            new EnumMap<Properties, Integer>(Properties.class);

    public PropertyPanels()
    {
        for (Properties property : Properties.values())
        {
            propertyCounter.put(property, 0);
        }
    }

    private int nextIndex(Properties property)
    {
        propertyCounter.put(property, propertyCounter.get(property) + 1);

        return propertyCounter.get(property);
    }

    /**
    public Vector<PropertyPanel> getProperties()
    {
        return (Vector<PropertyPanel>) properties.clone();
    }
    */

    private int add(PropertyPanel panel)
    {
        int position = 0;
        
        for (int i = 0; i < properties.size(); i++)
        {
            if (properties.get(i).title().compareTo(panel.title()) < 0)
            {
                position = i + 1;
            }
        }
        
        properties.add(position, panel);
        
        return position;
    }

    public PropertyPanel addPropertyPanel(Properties property, JPanel panel)
    {
        PropertyPanel propertyPanel = null;

        if (property.getType() == PropertyTypes.Multiple)
        {
            propertyPanel = new MultPropertyPanel(panel, property, nextIndex(property));
            //propertyPanel.addObserver(this);
            int position = add(propertyPanel);
            setChanged();
            notifyObservers(new PropertyUpdate(UpdateType.Add, propertyPanel, position));
            
        }
        else if (property.getType() == PropertyTypes.Optional)
        {
            if (containsProperty(property))
            {
                throw new RuntimeException("Property \"" + property + "\" is already added");
            }
            else
            {
                propertyPanel = new PropertyPanel(panel, property);
                int position = add(propertyPanel);
                //propertyPanel.addObserver(this);
                setChanged();
                notifyObservers(new PropertyUpdate(UpdateType.Add, propertyPanel, position));
            }
        }
        else
        {
            throw new RuntimeException("Property \"" + property + "\" not accounted for");
        }

        return propertyPanel;
    }

    private boolean remove(PropertyPanel panel)
    {
        boolean result = false;

        if ((result = properties.remove(panel)))
        {
            setChanged();
            notifyObservers(new PropertyUpdate(UpdateType.Remove, panel));
        }
        else
        {
            throw new RuntimeException("Attempted to remove panel that did not exist");
        }


        if (panel.getProperty().getType() == PropertyTypes.Multiple)
        {
            Vector<MultPropertyPanel> panelsOfSameType = new Vector<MultPropertyPanel>();
            Vector<MultPropertyPanel> panelsOfGreaterIndex = new Vector<MultPropertyPanel>();

            propertyCounter.put(panel.getProperty(), propertyCounter.get(panel.getProperty()) - 1);
            
            // extract panels of the same property type
            for (PropertyPanel pan : properties)
            {
                if (pan.getProperty() == panel.getProperty())
                {
                    panelsOfSameType.add((MultPropertyPanel) pan);
                }
            }

            // extract panels whose index is greater than the index of the panel
            // being removed
            for (MultPropertyPanel pan : panelsOfSameType)
            {
                if (pan.getIndex() > ((MultPropertyPanel) panel).getIndex())
                {
                    panelsOfGreaterIndex.add(pan);
                }
            }
            
            // decrement the index of each of the remaining panels by one
            for (MultPropertyPanel pan : panelsOfGreaterIndex)
            {
                pan.setIndex(pan.getIndex() - 1);
                setChanged();
                notifyObservers(new PropertyUpdate(UpdateType.TitleChange, pan));
            }
        }
        else if (panel.getProperty().getType() == PropertyTypes.Optional)
        {
            // do nothing
        }
        else
        {
            throw new RuntimeException("PropertyTypes not accounted for");
        }

        return result;
    }

    public PropertyPanel removeProperty(Properties property)
    {
        if (property.getType() == PropertyTypes.Multiple)
        {
            throw new RuntimeException("Attemping to remove a property of multiple type");
        }

        PropertyPanel removed = null;

        for (PropertyPanel panel : properties)
        {
            if (panel.getProperty() == property)
            {
                removed = panel;
            }
        }

        if (removed == null)
        {
            throw new RuntimeException("Could not find panel with property \"" + property + "\"");
        }

        remove(removed);
        
        return removed;
    }

    public PropertyPanel removeProperty(JPanel jPanel)
    {
        PropertyPanel removed = null;

        for (PropertyPanel panel : properties)
        {
            if (panel.getPanel() == jPanel)
            {
                removed = panel;
            }
        }

        if (removed == null)
        {
            throw new RuntimeException("Could not find jPanel");
        }

        remove(removed);

        return removed;
    }

    public PropertyPanel removeProperty(String title)
    {
        PropertyPanel removed = null;

        for (PropertyPanel panel : properties)
        {
            if (panel.title().equals(title))
            {
                if (removed == null)
                {
                    removed = panel;
                }
                else
                {
                    throw new RuntimeException("Attempted to remove a property by title but the title was not unique");
                }
            }
        }

        if (removed == null)
        {
            throw new RuntimeException("Did not find titel \"" + title + "\"");
        }

        remove(removed);

        return removed;        
    }

    public boolean removeProperty(PropertyPanel panel)
    {
        return remove(panel);
    }

    public boolean containsProperty(Properties property)
    {
        boolean contains = false;

        for (PropertyPanel panel : properties)
        {
            if (panel.getProperty() == property)
            {
                contains = true;
            }
        }

        return contains;
    }
}

class PropertyModel extends Observable implements Observer
{

    PropertyPanels properties = new PropertyPanels();
    
    private EnumMap<Properties, Class> classMap =
            new EnumMap<Properties, Class>(Properties.class);

    public PropertyModel()
    {
        classMap.put(Properties.ATMS, GenericEvaluationPanel.class);
        classMap.put(Properties.ActivityLog, GenericEvaluationPanel.class);
        classMap.put(Properties.CAD, GenericEvaluationPanel.class);
        classMap.put(Properties.Facilitator, GenericEvaluationPanel.class);
        classMap.put(Properties.Radio, GenericEvaluationPanel.class);

        classMap.put(Properties.MaintenanceRadio, MaintenanceRadioPanel.class);
        classMap.put(Properties.TMTRadio, TMTRadioPanel.class);
        classMap.put(Properties.CHPRadio, CHPRadioPanel.class);
        classMap.put(Properties.Telephone, TelephonePanel.class);

        classMap.put(Properties.Audio, AudioPanel.class);
        classMap.put(Properties.CADLog, CADLogPanel.class);
        classMap.put(Properties.CCTV, CCTVPanel.class);
        classMap.put(Properties.CMS, CMSEvaluationPanel.class);
        classMap.put(Properties.Paramics, ParamicsPanel.class);
        classMap.put(Properties.Tow, TowPanel.class);
        classMap.put(Properties.Unit, UnitPanel.class);
        classMap.put(Properties.Witness, WitnessPanel.class);

        properties.addObserver(this);
    }

    public void addProperty(Properties property)
    {
        try
        {
            JPanel panel = (JPanel) classMap.get(property).newInstance();

            final PropertyPanel propertyPanel = properties.addPropertyPanel(property, panel);
            
            if (property.getType() == PropertyTypes.Multiple)
            {
                if (panel instanceof RemoveablePanel)
                {
                    ((RemoveablePanel) panel).setRemoveListener(new ActionListener() {
                        public void actionPerformed(ActionEvent evt)
                        {
                            properties.removeProperty(propertyPanel);
                        }
                    });
                }
                else
                {
                    throw new RuntimeException("Property was multiple but panel was not removeable");
                }
            }
        }
        catch(Exception e)
        {
            System.err.println("Could not create panel of type \"" + property + "\"");
        }
    }

    public void removeProperty(Properties property)
    {
        properties.removeProperty(property);
    }

    public void update(Observable o, Object arg) {
        setChanged();
        notifyObservers(arg);
    }

    /*
    public Vector<PropertyPanel> getPropertyPanels()
    {
        return properties.getProperties();
    }
    */
}

public class Editor extends javax.swing.JFrame implements Observer {

    private PropertyModel model = new PropertyModel();

    public PropertyModel getPropertyModel()
    {
        return model;
    }

    public void addProperty(Properties property)
    {
            model.addProperty(property);
    }

    private ActionListener optionalChangeListener = new ActionListener() {
        public void actionPerformed(ActionEvent evt)
        {
            JCheckBoxMenuItem src = (JCheckBoxMenuItem) evt.getSource();
            Properties property = Properties.valueOf(src.getText().replaceAll(" ", ""));
            
            if (src.isSelected())
            {
                model.addProperty(property);
            }
            else
            {
                model.removeProperty(property);
            }
        }
    };

    private ActionListener multipleChangeListener = new ActionListener() {
        public void actionPerformed(ActionEvent evt)
        {
            JMenuItem src = (JMenuItem) evt.getSource();
            model.addProperty(Properties.valueOf(src.getText().replaceAll(" ", "")));
        }
    };

    public Editor() {
        initComponents();

        model.addObserver(this);
        
        // For each menu
        for (int menuCtr = 0; menuCtr < jMenuBar1.getMenuCount(); menuCtr++)
        {
            // for each menu item
            for (java.awt.Component comp : jMenuBar1.getMenu(menuCtr).getMenuComponents())
            {
                JMenuItem item = (JMenuItem) comp;

                String itemName = item.getText().replaceAll(" ", "");

                Properties property = Properties.valueOf(itemName);

                if (property.getType() == PropertyTypes.Multiple)
                {
                    item.addActionListener(multipleChangeListener);
                }
                else if (property.getType() == PropertyTypes.Optional)
                {
                    item.addActionListener(optionalChangeListener);
                }
                else
                {
                    throw new RuntimeException("Property type not accounted for");
                }
            }
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jTabbedPane1 = new javax.swing.JTabbedPane();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        ATMS = new javax.swing.JCheckBoxMenuItem();
        ActivityLog = new javax.swing.JCheckBoxMenuItem();
        CAD = new javax.swing.JCheckBoxMenuItem();
        CMS = new javax.swing.JMenuItem();
        Facilitator = new javax.swing.JCheckBoxMenuItem();
        Radio = new javax.swing.JCheckBoxMenuItem();
        JMenu2 = new javax.swing.JMenu();
        MaintenanceRadio = new javax.swing.JCheckBoxMenuItem();
        TMTRadio = new javax.swing.JCheckBoxMenuItem();
        Telephone = new javax.swing.JCheckBoxMenuItem();
        jMenu3 = new javax.swing.JMenu();
        Audio = new javax.swing.JMenuItem();
        CADLog = new javax.swing.JMenuItem();
        CCTV = new javax.swing.JMenuItem();
        CHPRadio = new javax.swing.JCheckBoxMenuItem();
        Paramics = new javax.swing.JMenuItem();
        Tow = new javax.swing.JMenuItem();
        Unit = new javax.swing.JMenuItem();
        Witness = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Event Editor");

        jMenu1.setText("Evaluations");

        ATMS.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
        ATMS.setText("ATMS");
        ATMS.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/ATMSEval.png"))); // NOI18N
        ATMS.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                multipleChange(evt);
            }
        });
        jMenu1.add(ATMS);

        ActivityLog.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.ALT_MASK));
        ActivityLog.setText("Activity Log");
        ActivityLog.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/ActivityLogEval.png"))); // NOI18N
        ActivityLog.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                multipleChange(evt);
            }
        });
        jMenu1.add(ActivityLog);

        CAD.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.ALT_MASK));
        CAD.setText("CAD");
        CAD.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/CADEval.png"))); // NOI18N
        CAD.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                multipleChange(evt);
            }
        });
        jMenu1.add(CAD);

        CMS.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.ALT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        CMS.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/CMSEval.png"))); // NOI18N
        CMS.setText("CMS");
        CMS.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                multipleChangeListener(evt);
            }
        });
        CMS.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                multipleChange(evt);
            }
        });
        jMenu1.add(CMS);

        Facilitator.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.CTRL_MASK));
        Facilitator.setText("Facilitator");
        Facilitator.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/FacilitatorEval.png"))); // NOI18N
        Facilitator.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                optionalChange(evt);
            }
        });
        jMenu1.add(Facilitator);

        Radio.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, java.awt.event.InputEvent.CTRL_MASK));
        Radio.setText("Radio");
        Radio.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/RadioEval.png"))); // NOI18N
        Radio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                optionalChange(evt);
            }
        });
        jMenu1.add(Radio);

        jMenuBar1.add(jMenu1);

        JMenu2.setText("Instructor Actions");

        MaintenanceRadio.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_M, java.awt.event.InputEvent.CTRL_MASK));
        MaintenanceRadio.setText("Maintenance Radio");
        MaintenanceRadio.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/MaintenanceRadio.png"))); // NOI18N
        MaintenanceRadio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                optionalChange(evt);
            }
        });
        JMenu2.add(MaintenanceRadio);

        TMTRadio.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_T, java.awt.event.InputEvent.ALT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        TMTRadio.setText("TMT Radio");
        TMTRadio.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/TMTRadio.png"))); // NOI18N
        TMTRadio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                optionalChange(evt);
            }
        });
        JMenu2.add(TMTRadio);

        Telephone.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_T, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        Telephone.setText("Telephone");
        Telephone.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/Telephone.png"))); // NOI18N
        Telephone.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                optionalChange(evt);
            }
        });
        JMenu2.add(Telephone);

        jMenuBar1.add(JMenu2);

        jMenu3.setText("Automated Data");

        Audio.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
        Audio.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/Audio.png"))); // NOI18N
        Audio.setText("Audio");
        jMenu3.add(Audio);

        CADLog.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK));
        CADLog.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/CAD.png"))); // NOI18N
        CADLog.setText("CAD Log");
        jMenu3.add(CADLog);

        CCTV.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, java.awt.event.InputEvent.CTRL_MASK));
        CCTV.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/CCTV.png"))); // NOI18N
        CCTV.setText("CCTV");
        jMenu3.add(CCTV);

        CHPRadio.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.ALT_MASK));
        CHPRadio.setText("CHP Radio");
        CHPRadio.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/CHPRadio.png"))); // NOI18N
        CHPRadio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                optionalChange(evt);
            }
        });
        jMenu3.add(CHPRadio);

        Paramics.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, java.awt.event.InputEvent.CTRL_MASK));
        Paramics.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/Paramics.png"))); // NOI18N
        Paramics.setText("Paramics");
        jMenu3.add(Paramics);

        Tow.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_T, java.awt.event.InputEvent.CTRL_MASK));
        Tow.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/Tow.png"))); // NOI18N
        Tow.setText("Tow");
        jMenu3.add(Tow);

        Unit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U, java.awt.event.InputEvent.CTRL_MASK));
        Unit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/Unit.png"))); // NOI18N
        Unit.setText("Unit");
        jMenu3.add(Unit);

        Witness.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, java.awt.event.InputEvent.CTRL_MASK));
        Witness.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/Witness.png"))); // NOI18N
        Witness.setText("Witness");
        jMenu3.add(Witness);

        jMenuBar1.add(jMenu3);

        setJMenuBar(jMenuBar1);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 921, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 580, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void multipleChangeListener(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_multipleChangeListener

    }//GEN-LAST:event_multipleChangeListener

    private void multipleChange(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_multipleChange

    }//GEN-LAST:event_multipleChange

    private void optionalChange(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_optionalChange

    }//GEN-LAST:event_optionalChange

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Editor().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBoxMenuItem ATMS;
    private javax.swing.JCheckBoxMenuItem ActivityLog;
    private javax.swing.JMenuItem Audio;
    private javax.swing.JCheckBoxMenuItem CAD;
    private javax.swing.JMenuItem CADLog;
    private javax.swing.JMenuItem CCTV;
    private javax.swing.JCheckBoxMenuItem CHPRadio;
    private javax.swing.JMenuItem CMS;
    private javax.swing.JCheckBoxMenuItem Facilitator;
    private javax.swing.JMenu JMenu2;
    private javax.swing.JCheckBoxMenuItem MaintenanceRadio;
    private javax.swing.JMenuItem Paramics;
    private javax.swing.JCheckBoxMenuItem Radio;
    private javax.swing.JCheckBoxMenuItem TMTRadio;
    private javax.swing.JCheckBoxMenuItem Telephone;
    private javax.swing.JMenuItem Tow;
    private javax.swing.JMenuItem Unit;
    private javax.swing.JMenuItem Witness;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JTabbedPane jTabbedPane1;
    // End of variables declaration//GEN-END:variables

    public void update(Observable o, Object arg) {

        final PropertyUpdate update = (PropertyUpdate) arg;
        final ImageIcon image = update.getPanel().getProperty().getImage();
        final String caption = update.getPanel().title();

        final JLabel title = new JLabel(caption, image, JLabel.CENTER);

        /*
        final BorderLayout layout = new BorderLayout();
        final JPanel title = new JPanel(layout);
        title.setOpaque(false);
        title.add(new JLabel(image), BorderLayout.WEST);
        title.add(new JLabel(caption), BorderLayout.EAST);
        */
        
        if (update.getType() == UpdateType.Add)
        {
            jTabbedPane1.insertTab(null, null,
                    update.getPanel().getPanel(), null, update.getPosition());
            jTabbedPane1.setTabComponentAt(update.getPosition(), title);
            jTabbedPane1.setSelectedIndex(update.getPosition());
        }
        else if (update.getType() == UpdateType.Remove)
        {
            jTabbedPane1.remove(update.getPanel().getPanel());
        }
        else if (update.getType() == UpdateType.TitleChange)
        {
            final int index = jTabbedPane1.indexOfComponent(
                    update.getPanel().getPanel());

            new Thread(new Runnable() {
                public void run() {
                    Color c = jTabbedPane1.getForegroundAt(index);
                    jTabbedPane1.setForegroundAt(index, Color.blue);
                    try { Thread.sleep(350); } catch(Exception e) { }
                    jTabbedPane1.setTabComponentAt(index, title);
                    try { Thread.sleep(350); } catch(Exception e) { }
                    jTabbedPane1.setForegroundAt(index, c);
                }
            }).start();
        }
        else
        {
            throw new RuntimeException("UpdateType not accounted for");
        }
    }

}
