/*--------------------------------------------------------------*
  Copyright (C) 2006-2015 OpenSim Ltd.

  This file is distributed WITHOUT ANY WARRANTY. See the file
  'License' for details on this and other legal matters.
*--------------------------------------------------------------*/

package org.omnetpp.ned.editor.graph.properties.util;

import java.util.EnumSet;

import org.eclipse.core.resources.IProject;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;
import org.omnetpp.common.properties.ColorPropertyDescriptor;
import org.omnetpp.common.properties.EnumComboboxPropertyDescriptor;
import org.omnetpp.common.properties.ImagePropertyDescriptor;
import org.omnetpp.common.util.StringUtils;
import org.omnetpp.ned.model.DisplayString;
import org.omnetpp.ned.model.interfaces.IHasDisplayString;

/**
 * Base display string property source. Common behavior to all display string property sources
 *
 * @author rhornig
 */
//TODO implement number cell editor
abstract public class DisplayPropertySource extends NedBasePropertySource {
    // the project of the NED element; used when searching images
    protected final IProject project;
    // property descriptor for the sheet (could be static if pushed upper)
    protected IPropertyDescriptor[] propertyDescArray = null;
    // by default supports all possible properties defined in DisplayString
    protected EnumSet<DisplayString.Prop> supportedProperties = EnumSet.noneOf(DisplayString.Prop.class);

    public DisplayPropertySource(IHasDisplayString model) {
        super(model);
        project = model.getSelfOrEnclosingTypeElement().getNedTypeInfo().getProject();
        // by default we provide only  the single line display property editor
        supportedProperties.add(DisplayString.Prop.DISPLAY);
    }

    /**
     * Creates and returns a property descriptor for the given display string property.
     */
    public IPropertyDescriptor getPropertyDescriptor(DisplayString.Prop prop) {
        PropertyDescriptor pdesc;
        if (prop.getEnumSpec() != null)
            pdesc = new EnumComboboxPropertyDescriptor(prop, prop.getName(), prop.getEnumSpec());
        else if (prop.getType() == DisplayString.PropType.STRING)
            pdesc = new TextPropertyDescriptor(prop, prop.getName());
        else if (prop.getType() == DisplayString.PropType.DISTANCE)
            pdesc = new TextPropertyDescriptor(prop, prop.getName());
        else if (prop.getType() == DisplayString.PropType.COORDINATE)
            pdesc = new TextPropertyDescriptor(prop, prop.getName());
        else if (prop.getType() == DisplayString.PropType.INTEGER)
            pdesc = new TextPropertyDescriptor(prop, prop.getName());
        else if (prop.getType() == DisplayString.PropType.IMAGE)
            pdesc = new ImagePropertyDescriptor(prop, prop.getName(), project);
        else if (prop.getType() == DisplayString.PropType.COLOR)
            pdesc = new ColorPropertyDescriptor(prop, prop.getName());
        else
            pdesc = new PropertyDescriptor(prop, prop.getName());  // read-only editor

        // set the other parameters
        pdesc.setCategory(prop.getGroup().name());
        String enumDesc = prop.getEnumDesc();
        String defaultValue = prop.getDefaultDesc();
        String desc = (prop.getTag()!=null) ? prop.getTag()+"["+prop.getPos()+"] - "+prop.getName()+": " : "";
        desc += prop.getShortDesc() + (StringUtils.isNotEmpty(enumDesc) ?  ". Values: " + enumDesc : "");
        desc += (StringUtils.isNotEmpty(defaultValue) ? ". Default: "+defaultValue : "");
        pdesc.setDescription(desc);
        // the one line display string descriptor should be always incompatible, so selecting
        // two or more items will automatically hide this composite property
        if (prop == DisplayString.Prop.DISPLAY)
            pdesc.setAlwaysIncompatible(true);

        return pdesc;
    }

    protected void createPropertyDescriptors() {
        int i = 0;
        propertyDescArray = new IPropertyDescriptor[supportedProperties.size()];
        // put all supported properties into the descriptor array
        for (DisplayString.Prop prop : supportedProperties) {
            propertyDescArray[i] = getPropertyDescriptor(prop);
            i++;
        }
    }

    @Override
    public IPropertyDescriptor[] getPropertyDescriptors() {
        if (propertyDescArray == null)
            createPropertyDescriptors();

        return propertyDescArray;
    }

    public DisplayString getDisplayString() {
        return ((IHasDisplayString)getModel()).getDisplayString();
    }

    @Override
    public Object getEditableValue() {
        return toString();
    }

    // property request for property sheet
    @Override
    public Object getPropertyValue(Object propObj) {
        if (!(propObj instanceof DisplayString.Prop))
            return null;

        // check if we requested the "single line" DISPLAY property
        if (propObj == DisplayString.Prop.DISPLAY)
            return getEditableValue();

        DisplayString.Prop prop = (DisplayString.Prop)propObj;

        // otherwise look for a single tag/attribute
        String value = getDisplayString().getAsStringLocal(prop);

        // if the property does not exists yet, return default empty value
        return value == null ? "" : value;
    }

    @Override
    public void setPropertyValue(Object propObj, Object value) {
        if (!(propObj instanceof DisplayString.Prop))
            return;

        // check if we requested the "single line" DISPLAY property
        if (propObj == DisplayString.Prop.DISPLAY) {
            getDisplayString().set((String)value);
            return;
        }

        // otherwise set a single attribute
        DisplayString.Prop prop = (DisplayString.Prop)propObj;

        if (value != null)
            getDisplayString().set(prop, value.toString());
        else
            getDisplayString().set(prop, null);

    }

    @Override
    public void resetPropertyValue(Object prop) {
        if (!(prop instanceof DisplayString.Prop))
            return;

        // check if we requested the "single line" DISPLAY property, reset the whole display string
        if (prop == DisplayString.Prop.DISPLAY) {
            getDisplayString().set(null);
            return;
        }

        // set only a single attribute
        getDisplayString().set((DisplayString.Prop)prop, null);
    }

    @Override
    public boolean isPropertySet(Object prop) {
        if (!(prop instanceof DisplayString.Prop))
            return false;

        // check if we requested the "single line" DISPLAY property
        if (prop == DisplayString.Prop.DISPLAY)
            return StringUtils.isNotEmpty(getDisplayString().toString());

        // otherwise check a single attribute
        return StringUtils.isNotEmpty(getDisplayString().getAsStringLocal((DisplayString.Prop)prop));
    }

    @Override
    public String toString() {
        return getDisplayString().toString();
    }

    @Override
    public boolean isPropertyResettable(Object id) {
        return true;
    }

}
