package event.editor.frame;

import java.util.EnumMap;
import java.util.Observable;
import java.util.Vector;
import javax.swing.JPanel;

/**
 *
 * @author Bryan McGuffin
 */
public 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;
    }
}
