/*------------------------------------------------------------------------------
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;

import java.io.*;

/**
 * @author TogetherSoft
 */
public class GeneralizationLinkInspector 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.GENERALIZATION) &&
        !RwiElementsUtil.checkProperty(context, RwiProperty.SHAPE_TYPE, RwiShapeType.IMPLEMENTATION))
      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 GeneralizationLinkPropertiesComponent(context, rwiElements);
      if (propertiesComponent instanceof IdeInspectorPropertySetComponent) {
        propertiesPage = (IdeInspectorPropertySetComponent)propertiesComponent;
      }
      inspector.addComponent(propertiesPage, null, ComponentWeight.PROPERTIES);
    }

    if (rwiElements.length == 1) {
      // Create class-tab
      RwiElement classElement = ((RwiLink)rwiElements[0]).getSource();
      if (classElement == null) return inspector;

      // generalization link can be drown between classes, actors and usecases
      if (classElement.getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.CLASS)) {
        IdeInspectorComponent classComponent = inspector.findComponent("Class");
        IdeInspectorPropertySetComponent classPage = null;
        if (classComponent == null) {
          classComponent = new ClassComponent(context, rwiElements[0]);
          if (classComponent instanceof IdeInspectorPropertySetComponent) {
            classPage = (IdeInspectorPropertySetComponent)classComponent;
          }
          classPage.setDisplayName("Class");
          inspector.addComponent(classPage, null, ComponentWeight.MEMBER);
        }
      } else if (classElement.getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.ACTOR)) {
        IdeInspectorComponent actorComponent = inspector.findComponent("Actor");
        IdeInspectorPropertySetComponent actorPage = null;
        if (actorComponent == null) {
          actorComponent = new ActorComponent(context, classElement);
          if (actorComponent instanceof IdeInspectorPropertySetComponent) {
            actorPage = (IdeInspectorPropertySetComponent)actorComponent;
          }
          actorPage.setDisplayName("Class");
          inspector.addComponent(actorPage, null, ComponentWeight.MEMBER);
        }
      } else if (classElement.getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.USE_CASE)) {
        IdeInspectorComponent useCaseComponent = inspector.findComponent("UseCase");
        IdeInspectorPropertySetComponent useCasePage = null;
        if (useCaseComponent == null) {
          useCaseComponent = new UseCaseComponent(context, classElement);
          if (useCaseComponent instanceof IdeInspectorPropertySetComponent) {
            useCasePage = (IdeInspectorPropertySetComponent)useCaseComponent;
          }
          useCasePage.setDisplayName("Class");
          inspector.addComponent(useCasePage, null, ComponentWeight.MEMBER);
        }
      } else return inspector;
    }

    return inspector;
  }
}

class GeneralizationLinkPropertiesComponent extends IdeInspectorPropertySetComponent {
  public GeneralizationLinkPropertiesComponent(IdeContext context, RwiElement[] rwiElements) {
    super(context);
    myRwiElements = rwiElements;
    myContext = context;
    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);
    }

    if (RwiElementsUtil.checkProperty(myContext, RwiProperty.LANGUAGE, RwiLanguage.CPP)) {
      property = new RwiInspectorVisibilityProperty(myRwiElements);
      SwingComboBoxEditor editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "public", "protected", "private"
          }
        )
      );
      property.setPropertyEditor(editor);
      property.setDisplayName("visibility");
      addProperty(property, null);

      property = new RwiInspectorBooleanProperty(myRwiElements, RwiProperty.VIRTUAL);
      property.setDisplayName("virtual");
      addProperty(property, null);
    }
  }

  private RwiElement[] myRwiElements;
  private IdeContext myContext;
}

class ClassComponent extends IdeInspectorPropertySetComponent {
  public ClassComponent(IdeContext context, RwiElement rwiElement) {
    super(context);
    classElement = rwiElement;
    setName("Class");
    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() {
    if (classElement instanceof RwiLink) {
      // generalization link
      classElement = ((RwiLink)classElement).getSource();
    }
    if (classElement.getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.OBJECT)) {
      // in case of Object inspector
      String instantiatedClassUniqueName = classElement.getProperty("$instantiatedClass");
      classElement = RwiModelAccess.getModel().findElement(instantiatedClassUniqueName);
      if (classElement == null) return;
    }

    IdeInspectorProperty property;

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

    if (classElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.JAVA)) {
      if (classElement instanceof RwiNode) {
        String packageName = ((RwiNode)classElement).getContainingPackage().getProperty(RwiProperty.FULL_NAME);
        if (packageName.length() == 0) {
          packageName = "<default>";
        }
        property = new ReadOnlyProperty(packageName, String.class);
        property.setName("package");
        addProperty(property, null);
      }
    }

    property = new RwiInspectorStringProperty(classElement, "stereotype");
    SwingComboBoxEditor editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          "role", "container", "moment-interval", "mi-detail", "party", "place",
          "thing", "description", "abstractfactory", "factory", "actor", "metaclass",
          "utility", "visitor", "plug-in point", "thread", "type", "implementationClass",
          "interface", "powertype", "process", "stereotype", "Idl-Interface",
          "struct", "union", "enumeration", "exception", "Boundary", "Entity"
        }
      )
    );
    editor.setValueEditable(true);
    property.setPropertyEditor(editor);
    addProperty(property, null);

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

    property = new FileNameProperty(classElement, RwiProperty.FILE, "file");
    addProperty(property, null);

    if (classElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.CPP)) {
      final IdeInspectorProperty defFileProperty = new FileNameProperty(classElement, RwiProperty.DEFINITION_FILE, "definition file");
      addProperty(defFileProperty, new Condition(){
        public boolean execute(IdeContext context){
          return defFileProperty.getValue() != null;
        }
      });

      property = new RwiInspectorStringProperty(classElement, RwiProperty.NAMESPACE);
      property.setName("namespace");
      addProperty(property, null);

      property = new RwiInspectorMultipleStringProperty(classElement, RwiProperty.EXTENDS);
      property.setName("extends");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(classElement, RwiProperty.EXTENDS, IdeSelectorDialogType.CPP_EXTENDS));
      addProperty(property, null);
    } else if (classElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.IDL)) {
      property = new RwiInspectorStringProperty(classElement, RwiProperty.NAMESPACE);
      property.setName("module");
      addProperty(property, null);

      property = new RwiInspectorMultipleStringProperty(classElement, RwiProperty.EXTENDS);
      property.setName("extends");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(classElement, RwiProperty.EXTENDS, IdeSelectorDialogType.IDL_EXTENDS));
      addProperty(property, null);

      property = new RwiInspectorMultipleStringProperty(classElement, RwiProperty.IMPLEMENTS);
      property.setName("implements");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(classElement, RwiProperty.IMPLEMENTS, IdeSelectorDialogType.IDL_IMPLEMENTS));
      addProperty(property, null);
    }

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

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

      if (RwiElementsUtil.checkProperty(myContext, RwiProperty.INTERFACE, false)) {
        property = new RwiInspectorBooleanProperty(classElement, RwiProperty.FINAL);
        property.setName("final");
        addProperty(property, null);

        property = new RwiInspectorBooleanProperty(classElement, RwiProperty.ABSTRACT);
        property.setName("abstract");
        addProperty(property, null);
      }

      property = new RwiInspectorMultipleStringProperty(classElement, RwiProperty.EXTENDS);
      property.setValue(IdeInspectorProperty.MULTI_VALUE_TAG, Boolean.FALSE); //although it's represented by multivalue property, it takes only one value
      property.setName("extends");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(classElement, RwiProperty.EXTENDS, IdeSelectorDialogType.JAVA_EXTENDS));
      addProperty(property, null);

      if (! classElement.hasProperty(RwiProperty.INTERFACE)) {
        property = new RwiInspectorMultipleStringProperty(classElement, RwiProperty.IMPLEMENTS);
        property.setName("implements");
        property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(classElement, RwiProperty.IMPLEMENTS, IdeSelectorDialogType.JAVA_IMPLEMENTS));
        addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return RwiElementsUtil.checkProperty(context, RwiProperty.INTERFACE, false);
          }
        });
      }

      property = new RwiInspectorBooleanProperty(classElement, RwiProperty.INTERFACE);
      property.setName("interface");
      addProperty(property, null);

      property = new RwiInspectorStringProperty(classElement, "invariants");
      property.setDisplayName("invariants");
      property.setPropertyEditor(new ExtendedStringEditor("invariants"));
      addProperty(property, null);
    }

    property = new RwiInspectorBooleanProperty(classElement, "persistent");
    property.setName("persistent");
    addProperty(property, null);
  }

  private RwiElement classElement;
}

class ActorComponent extends IdeInspectorPropertySetComponent {
  public ActorComponent(IdeContext context, RwiElement rwiElement) {
    super(context);
    classElement = rwiElement;
    setName("Actor");
    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(classElement, RwiProperty.NAME);
    property.setName("name");
    addProperty(property, null);

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

    property = new RwiInspectorStringProperty(classElement, "explanation");
    property.setDisplayName("description");
    property.setPropertyEditor(new ExtendedStringEditor("description"));
    addProperty(property, null);
  }
  private RwiElement classElement;
}

class UseCaseComponent extends IdeInspectorPropertySetComponent {
  public UseCaseComponent(IdeContext context, RwiElement rwiElement) {
    super(context);
    classElement = rwiElement;
    setName("UseCase");
    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(classElement, RwiProperty.NAME);
    property.setName("name");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "stereotype");
    SwingComboBoxEditor editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          "role", "moment-interval", "mi-detail", "party", "place",
          "thing", "description", "abstractfactory", "factory", "actor",
          "metaclass", "utility", "visitor", "plug-in point", "Idl-Interface",
          "thread", "type", "implementationClass"
        }
      )
    );
    editor.setValueEditable(true);
    property.setPropertyEditor(editor);
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "explanation");
    property.setDisplayName("description");
    property.setPropertyEditor(new ExtendedStringEditor("description"));
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "rank");
    property.setName("rank");
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "preconditions");
    property.setDisplayName("pre-conditions");
    property.setPropertyEditor(new ExtendedStringEditor("pre-conditions"));
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "postconditions");
    property.setDisplayName("post-conditions");
    property.setPropertyEditor(new ExtendedStringEditor("post-conditions"));
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "normalFlow");
    property.setDisplayName("normal flow");
    property.setPropertyEditor(new ExtendedStringEditor("normal flow"));
    addProperty(property, null);

    property = new RwiInspectorStringProperty(classElement, "alternateFlow");
    property.setDisplayName("alternate flow");
    property.setPropertyEditor(new ExtendedStringEditor("alternate flow"));
    addProperty(property, null);

    property = new RwiInspectorBooleanProperty(classElement, "abstract");
    property.setName("abstract");
    addProperty(property, null);
  }
  private RwiElement classElement;
}
