/*----------------------------------------------------------------------------
Copyright (c)2000 TogetherSoft Corporation. Patents pending. All rights reserved.
----------------------------------------------------------------------------*/

package com.togethersoft.modules.inspector;

import com.togethersoft.openapi.ide.IdeStartup;
import com.togethersoft.openapi.ide.IdeContext;
import com.togethersoft.openapi.ide.inspector.*;
import com.togethersoft.openapi.ide.inspector.util.*;
import com.togethersoft.openapi.ide.inspector.util.property.*;
import com.togethersoft.openapi.ide.inspector.util.table.*;
import com.togethersoft.openapi.ide.inspector.util.editors.*;
import com.togethersoft.openapi.ide.util.*;
import com.togethersoft.openapi.rwi.*;

import com.togethersoft.openapi.ide.window.IdeSelectorDialogType;
import javax.swing.DefaultComboBoxModel;
import com.togethersoft.openapi.util.RwiElementsUtil;

/**
 * @author TogetherSoft
 */
public class AssociationLinkInspector implements IdeStartup, IdeInspectorBuilder {
  public void autorun(){
    IdeInspectorManager manager = IdeInspectorManagerAccess.getInspectorManager();
    manager.addInspectorBuilder(this);
  }
  public IdeInspector buildInspector(IdeContext context, IdeInspector inspector) {
    if (!RwiElementsUtil.checkProperty(context, RwiProperty.SHAPE_TYPE, RwiShapeType.ASSOCIATION))
      return inspector;
    RwiElement[] rwiElements = RwiElementsUtil.getRwiElements(context);
    RwiReference[] rwiReferences = RwiElementsUtil.getRwiReferences(context);

    IdeInspectorComponent propertiesComponent = inspector.findComponent("Link");
    IdeInspectorPropertySetComponent propertiesPage = null;
    if (propertiesComponent == null) {
      propertiesComponent = new AssociationLinkPropertiesComponent(context, rwiElements);
      if (propertiesComponent instanceof IdeInspectorPropertySetComponent) {
        propertiesPage = (IdeInspectorPropertySetComponent)propertiesComponent;
      }
      inspector.addComponent(propertiesPage, null, ComponentWeight.PROPERTIES);
    }

    if (rwiElements.length == 1) {
      InspectorUtils.createDescriptionPage (context, inspector, rwiElements);
      inspector.addComponent(new DocComponent(rwiElements[0]), null, ComponentWeight.HTMLDOC);
      InspectorUtils.createReqPage (context, inspector, rwiElements);

      // Create Member-tab.
      if (rwiElements[0] instanceof RwiLink) {
        String memberProperty = ((RwiLink)rwiElements[0]).getProperty(RwiProperty.LINK_MEMBER);
        if (memberProperty != null) {
          RwiElement memberElement = RwiModelAccess.getModel().findElement(memberProperty);

          if (memberElement.getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.ATTRIBUTE)) {
            IdeInspectorComponent attributeComponent = inspector.findComponent("Member");
            IdeInspectorPropertySetComponent attributePage = null;
            if (attributeComponent == null) {
              attributeComponent = new AttributeComponent(context, memberElement);
              if (attributeComponent instanceof IdeInspectorPropertySetComponent) {
                attributePage = (IdeInspectorPropertySetComponent)attributeComponent;
              }
              attributePage.setDisplayName("Member");
              inspector.addComponent(attributePage, null, ComponentWeight.MEMBER);
            }
          } else if (memberElement.getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.OPERATION)) {
            IdeInspectorComponent operationComponent = inspector.findComponent("Member");
            IdeInspectorPropertySetComponent operationPage = null;
            if (operationComponent == null) {
              operationComponent = new OperationComponent(context, memberElement);
              if (operationComponent instanceof IdeInspectorPropertySetComponent) {
                operationPage = (IdeInspectorPropertySetComponent)operationComponent;
              }
              operationPage.setDisplayName("Member");
              inspector.addComponent(operationPage, null, ComponentWeight.MEMBER);
            }
          }
          else return inspector;
        }
      }
    }

    return inspector;
  }
}

class AssociationLinkPropertiesComponent extends IdeInspectorPropertySetComponent {
  public AssociationLinkPropertiesComponent(IdeContext context, RwiElement[] rwiElements) {
    super(context);
    myRwiElements = rwiElements;
    setName("Link");
    setService(UIComponentService.class, new PropertyTableComponentUI(this));
  }

  public void update() {
    IdeInspectorProperty[] properties = getProperties();
    for (int i = 0; i < properties.length; i++) {
      removeProperty(properties[i]);
    }
    refill();
    super.update();
  }

  private void refill() {
    IdeInspectorProperty property;

    if (myRwiElements.length == 1 && myRwiElements[0] instanceof RwiLink) {
      String sourceName = ((RwiLink)myRwiElements[0]).getSource().getProperty(RwiProperty.NAME);
      property = new ReadOnlyProperty(sourceName, String.class);
      property.setName("client");
      addProperty(property, null);

      String destinationName = ((RwiLink)myRwiElements[0]).getDestination().getProperty(RwiProperty.NAME);
      property = new ReadOnlyProperty(destinationName, String.class);
      property.setName("supplier");
      addProperty(property, null);
    }

    property = new RwiInspectorStringProperty(myRwiElements, "label");
    property.setName("label");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "associationAsClass");
    property.setName("association class");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "clientRole");
    property.setName("client role");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "clientCardinality");
    SwingComboBoxEditor editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          "0..1", "1", "*", "1..*"
        }
      )
    );
    editor.setValueEditable(true);
    property.setPropertyEditor(editor);
    property.setName("client cardinality");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "clientQualifier");
    property.setName("client qualifier");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "supplierRole");
    property.setName("supplier role");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "supplierCardinality");
    editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          "0..1", "1", "*", "1..*"
        }
      )
    );
    editor.setValueEditable(true);
    property.setPropertyEditor(editor);
    property.setName("supplier cardinality");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(myRwiElements, "supplierQualifier");
    property.setName("supplier qualifier");
    addProperty(property, null);

    property = new RwiInspectorDirectedProperty(myRwiElements);
    editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          "automatic", "directed", "undirected"
        }
      ),
      new String[] {
        "Automatic", "Directed", "Undirected"
      },
      new String[] {
        null, null, null
      }
    );
    property.setPropertyEditor(editor);
    property.setDisplayName("directed");
    addProperty(property, null);

    property = new RwiInspectorAssociationProperty(myRwiElements);
    editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          RwiInspectorAssociationProperty.ASSOCIATION, RwiInspectorAssociationProperty.AGGREGATION, RwiInspectorAssociationProperty.COMPOSITION
        }
      ), null, null
    );
    editor.setValueEditable(false);
    property.setPropertyEditor(editor);
    property.setName("type");
    addProperty(property, null);
  }

  private RwiElement[] myRwiElements;
}

class AttributeComponent extends IdeInspectorPropertySetComponent {
  public AttributeComponent(IdeContext context, RwiElement rwiElement) {
    super(context);
    memberElement = rwiElement;
    setName("Operation");
    setService(UIComponentService.class, new PropertyTableComponentUI(this));
  }

  public void update() {
    IdeInspectorProperty[] properties = getProperties();
    for (int i = 0; i < properties.length; i++) {
      removeProperty(properties[i]);
    }
    refill();
    super.update();
  }

  private void refill() {
    IdeInspectorProperty property;

    property = new RwiInspectorStringProperty(memberElement, RwiProperty.NAME);
    property.setName("name");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(memberElement, "stereotype");
    SwingComboBoxEditor editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
        }
      )
    );
    editor.setValueEditable(true);
    property.setPropertyEditor(editor);
    addProperty(property, null);

    property = new RwiInspectorStringProperty(memberElement, "alias");
    property.setName("alias");
    addProperty(property, null);

    if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.JAVA)) {
      property = new RwiInspectorStringProperty(memberElement, RwiProperty.TYPE);
      editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "boolean", "byte", "char", "double", "float", "int", "long",
            "short", "String", "java.util.Vector", "java.util.Hashtable"
          }
        )
      );
      editor.setValueEditable(true);
      property.setDisplayName("type");
      property.setPropertyEditor(editor);
      addProperty(property, null);
    } else if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.CPP)) {
      property = new RwiInspectorStringProperty(memberElement, RwiProperty.DEFINITION_FILE);
      property.setDisplayName("definition file");
      property.setPropertyEditor(new ExtendedFileNameEditor("open"));
      final RwiElement finalMemberElement = memberElement;
      addProperty(property, new Condition(){
        public boolean execute(IdeContext context){
          return finalMemberElement.hasProperty(RwiProperty.STATIC);
        }
      });

      property = new RwiInspectorStringProperty(memberElement, RwiProperty.TYPE) {
        public boolean canSetValue(Object value){
          if ( "void".equals(String.valueOf(value)) ) return false;
          return super.canSetValue(value);
        }
      };
      editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "bool", "char", "double", "float", "int", "long", "long double",
            "short", "unsigned", "unsigned long", "unsigned short", "string"
          }
        )
      );
      editor.setValueEditable(true);
      property.setDisplayName("type");
      property.setPropertyEditor(editor);
      addProperty(property, null);
    } else if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.IDL)) {
      property = new RwiInspectorStringProperty(memberElement, RwiProperty.TYPE);
      editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "float", "double", "long double", "long", "long long", "short",
            "unsigned long", "unsigned long long", "unsigned short", "char",
            "wchar", "boolean", "octet", "any"
          }
        )
      );
      editor.setValueEditable(true);
      property.setDisplayName("type");
      property.setPropertyEditor(editor);
      addProperty(property, null);
    }

    property = new RwiInspectorStringProperty(memberElement, RwiProperty.ASSOCIATES);
    property.setName("associates");
    property.setPropertyEditor(new SingleElementChooserEditor(memberElement, IdeSelectorDialogType.ASSOCIATES));
    addProperty(property, null);

    if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.CPP)) {
      property = new RwiInspectorStringProperty(memberElement, RwiProperty.INITIAL_VALUE);
      property.setName("initial value");
      final RwiElement finalMemberElement = memberElement;
      addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return finalMemberElement.hasProperty(RwiProperty.STATIC);
        }
      });
    } else if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.JAVA)) {
      final RwiElement finalRwiElement = memberElement;
      property = new RwiInspectorStringProperty(finalRwiElement, RwiProperty.INITIAL_VALUE) {
        public boolean canSetValue(Object value) {
          RwiMember attribute = (RwiMember)finalRwiElement;
          RwiNode containingNode = attribute.getContainingNode();
          if ( containingNode == null || !containingNode.hasProperty(RwiProperty.INTERFACE) ) return super.canSetValue(value);
          if ( value instanceof String && "".equals(((String)value).trim()) ) {
            return false;
          } else {
            return super.canSetValue(value);
          }
        }
      };
      property.setName("initial value");
      addProperty(property, null);
    } else {
      property = new RwiInspectorStringProperty(memberElement, RwiProperty.INITIAL_VALUE);
      property.setName("initial value");
      addProperty(property, null);
    }

    if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.IDL)) {
      property = new RwiInspectorBooleanProperty(memberElement, RwiProperty.CONST);
      property.setName("readonly");
      addProperty(property, null);
    }

    if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.JAVA)) {
      if (!((RwiMember)memberElement).getContainingNode().hasProperty(RwiProperty.INTERFACE)) {
        property = new RwiInspectorVisibilityProperty(memberElement);
        editor = new SwingComboBoxEditor(
          new DefaultComboBoxModel(
            new String[] {
              "public", "protected", "package local", "private"
            }
          )
        );
        property.setPropertyEditor(editor);
        property.setDisplayName("visibility");
        addProperty(property, null);

        property = new RwiInspectorBooleanProperty(memberElement, RwiProperty.STATIC);
        property.setName("static");
        addProperty(property, null);

        property = new RwiInspectorBooleanProperty(memberElement, RwiProperty.FINAL);
        property.setName("final");
        addProperty(property, null);

        property = new RwiInspectorBooleanProperty(memberElement, RwiProperty.TRANSIENT);
        property.setName("transient");
        addProperty(property, null);

        property = new RwiInspectorBooleanProperty(memberElement, RwiProperty.VOLATILE);
        property.setName("volatile");
        addProperty(property, null);
      }
    } else if (memberElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.CPP)) {
      property = new RwiInspectorVisibilityProperty(memberElement);
      editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "public", "protected", "private"
          }
        )
      );
      property.setPropertyEditor(editor);
      property.setDisplayName("visibility");
      addProperty(property, null);

      property = new RwiInspectorBooleanProperty(memberElement, RwiProperty.STATIC);
      property.setName("static");
      addProperty(property, null);
    }
  }

  private RwiElement memberElement;
}

class RwiInspectorDirectedProperty extends RwiInspectorProperty {
  public RwiInspectorDirectedProperty(RwiPropertyMap[] rwiPropertyMaps) {
    super(rwiPropertyMaps, "", String.class);
  }

  public RwiInspectorDirectedProperty(RwiPropertyMap rwiPropertyMap) {
    super(new RwiPropertyMap[] { rwiPropertyMap }, "", String.class);
  }

  protected void loadValue() {
    myReadableFlag = true;
    myWritableFlag = true;
    Object value = "Automatic";
    for (int i = 0; i < myRwiPropertyMaps.length; i++) {
      if (isDeleted(myRwiPropertyMaps[i])) {
        value = UNDEFINED_VALUE;
        myReadableFlag = false;
        myWritableFlag = false;
        break;
      }

      String val = "Automatic";
      if (myRwiPropertyMaps[i].hasProperty("directed"))
        val = "Directed";
      else if (myRwiPropertyMaps[i].hasProperty("undirected"))
        val = "Undirected";
      if (i == 0) {
        value = val;
      } else {
        if (val != value) {
          value = val;
          break;
        }
      }
    }
    Object oldValue = myValue;
    myValue = value;
    firePropertyChange(PROP_VALUE, oldValue, myValue);
  }

  protected void storeValue() {
    for (int i = 0; i < myRwiPropertyMaps.length; i++) {
      if (isDeleted(myRwiPropertyMaps[i])) { continue; }
      if ( "directed".equals(myValue) ) {
        myRwiPropertyMaps[i].setProperty("directed", true);
        myRwiPropertyMaps[i].setProperty("undirected", false);
      } else if ( "undirected".equals(myValue) ) {
        myRwiPropertyMaps[i].setProperty("undirected", true);
        myRwiPropertyMaps[i].setProperty("directed", false);
      } else {
        myRwiPropertyMaps[i].setProperty("undirected", false);
        myRwiPropertyMaps[i].setProperty("directed", false);
      }
    }
  }

  public boolean canSetValue(Object value) {
    return true;
  }
}

class RwiInspectorAssociationProperty extends RwiInspectorProperty {
  public RwiInspectorAssociationProperty(RwiPropertyMap[] rwiPropertyMaps) {
    super(rwiPropertyMaps, "", String.class);
  }

  public RwiInspectorAssociationProperty(RwiPropertyMap rwiPropertyMap) {
    super(new RwiPropertyMap[] { rwiPropertyMap }, "", String.class);
  }

  protected void loadValue() {
    myReadableFlag = true;
    myWritableFlag = true;
    Object value = ASSOCIATION;
    for (int i = 0; i < myRwiPropertyMaps.length; i++) {
      if (isDeleted(myRwiPropertyMaps[i]) || !RwiShapeType.ASSOCIATION.equals(myRwiPropertyMaps[i].getProperty(RwiProperty.SHAPE_TYPE)) ) {
        value = UNDEFINED_VALUE;
        myReadableFlag = false;
        myWritableFlag = false;
        break;
      }

      String val = ASSOCIATION;
      if (myRwiPropertyMaps[i].hasProperty(RwiProperty.BY_VALUE))
        val = COMPOSITION;
      else if (myRwiPropertyMaps[i].hasProperty(RwiProperty.AGGREGATION))
        val = AGGREGATION;
      if (i == 0) {
        value = val;
      } else {
        if (val != value) {
          value = val;
          break;
        }
      }
    }
    Object oldValue = myValue;
    myValue = value;
    firePropertyChange(PROP_VALUE, oldValue, myValue);
  }

  protected void storeValue() {
    for (int i = 0; i < myRwiPropertyMaps.length; i++) {
      if (isDeleted(myRwiPropertyMaps[i])) { continue; }
      if ( COMPOSITION.equals(myValue) ) {
        myRwiPropertyMaps[i].setProperty(RwiProperty.BY_VALUE, true);
        myRwiPropertyMaps[i].setProperty(RwiProperty.AGGREGATION, true);
      } else if ( AGGREGATION.equals(myValue) ) {
        myRwiPropertyMaps[i].setProperty(RwiProperty.BY_VALUE, false);
        myRwiPropertyMaps[i].setProperty(RwiProperty.AGGREGATION, true);
      } else {
        myRwiPropertyMaps[i].setProperty(RwiProperty.BY_VALUE, false);
        myRwiPropertyMaps[i].setProperty(RwiProperty.AGGREGATION, false);
      }
    }
  }

  public boolean canSetValue(Object value) {
    return true;
  }

  public static final String ASSOCIATION = "Association";
  public static final String COMPOSITION = "Composition";
  public static final String AGGREGATION = "Aggregation";
}
