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

package com.togethersoft.modules.inspector;

import java.io.*;

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 ClassInspector 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.CLASS))
      return inspector;
    final RwiElement[] rwiElements = RwiElementsUtil.getRwiElements(context);
    final RwiReference[] rwiReferences = RwiElementsUtil.getRwiReferences(context);

    IdeInspectorComponent propertiesComponent = inspector.findComponent("Properties");
    IdeInspectorPropertySetComponent propertiesPage;
    if (propertiesComponent instanceof IdeInspectorPropertySetComponent) {
      propertiesPage = (IdeInspectorPropertySetComponent)propertiesComponent;
    }
    else {
      propertiesPage = new IdeInspectorPropertySetComponent(context);
      propertiesPage.setName("Properties");
      propertiesPage.setService(UIComponentService.class, new PropertyTableComponentUI(propertiesPage));
      inspector.addComponent(propertiesPage, null, ComponentWeight.PROPERTIES);
    }

    IdeInspectorProperty property;

    if (rwiElements.length == 1) {
      property = new RwiInspectorStringProperty(rwiElements, RwiProperty.NAME);
      property.setName("name");
      propertiesPage.addProperty(property, null);
    }

    if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.JAVA)) {
      if (rwiElements.length == 1 && rwiElements[0] instanceof RwiNode) {
        String packageName = ((RwiNode)rwiElements[0]).getContainingPackage().getProperty(RwiProperty.FULL_NAME);
        if (packageName.length() == 0) {
          packageName = "<default>";
        }
//        property = new RwiInspectorStringProperty(rwiElements, packageName);
        property = new ReadOnlyProperty(packageName, String.class);
        property.setName("package");
        propertiesPage.addProperty(property, null);
      }
    }

    property = new RwiInspectorStringProperty(rwiElements, "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);
    propertiesPage.addProperty(property, null);

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

    if (rwiElements.length == 1) {
      property = new FileNameProperty(rwiElements, RwiProperty.FILE, "file");
      propertiesPage.addProperty(property, null);
    }

    // if classes and interfaces are selected simultaneously, some fields should not be displayed
    boolean classesAndInterfacesSelected = false;
    boolean classes = false;
    boolean interfaces = false;
    if (rwiElements.length > 1) {
      for (int i = 0; i < rwiElements.length; i++) {
        if (rwiElements[i].hasProperty(RwiProperty.INTERFACE))
          interfaces = true;
        else
          classes = true;

        if (classes && interfaces) {
          classesAndInterfacesSelected = true;
          break;
        }
      }
    }

    final boolean _classesAndInterfacesSelected = classesAndInterfacesSelected;

    if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.CPP)) {
      if (rwiElements.length == 1) {
        final IdeInspectorProperty defFileProperty = new FileNameProperty(rwiElements, RwiProperty.DEFINITION_FILE, "definition file");
        propertiesPage.addProperty(defFileProperty, new Condition(){
          public boolean execute(IdeContext context){
            return defFileProperty.getValue() != null;
          }
        });
      }

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

      if (!classesAndInterfacesSelected) {
        property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.EXTENDS);
        property.setName("extends");
        property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.EXTENDS, IdeSelectorDialogType.CPP_EXTENDS));
        propertiesPage.addProperty(property, null);
      }

      property = new RwiInspectorVisibilityProperty(rwiElements);
      editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "public", "protected", "private"
          }
        )
      );
      property.setPropertyEditor(editor);
      property.setDisplayName("visibility");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          boolean allTopLevel = true;
          for (int i = 0; i < rwiElements.length; i++) {
            if (((RwiNode)rwiElements[i]).getContainingNode() == null) {
              return false;
            } else {
              if (RwiShapeType.CLASS.equals(((RwiNode)rwiElements[i]).getContainingNode().getProperty(RwiProperty.SHAPE_TYPE)))
                allTopLevel = false;
            }
          }
          return (!allTopLevel);
        }
      });

    }
    else if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.IDL)) {
      property = new RwiInspectorStringProperty(rwiElements, RwiProperty.NAMESPACE);
      property.setName("module");
      propertiesPage.addProperty(property, null);

      if (!classesAndInterfacesSelected) {
        boolean allValueTypes = true;
        for (int i=0; i<rwiElements.length; i++)
          if (!rwiElements[i].hasProperty(RwiProperty.VALUETYPE))
            allValueTypes = false;

        boolean allInterfaces = true;
        for (int i=0; i<rwiElements.length; i++)
          if (!rwiElements[i].hasProperty(RwiProperty.INTERFACE))
            allInterfaces = false;

        final boolean _allValueTypes = allValueTypes;
        final boolean _allInterfaces = allInterfaces;

        property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.EXTENDS);
        property.setName("extends");
        property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.EXTENDS, IdeSelectorDialogType.IDL_EXTENDS));
        propertiesPage.addProperty(property, new Condition() {
          public boolean execute(IdeContext context){
            return _allValueTypes;
          }
        });

        property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.IMPLEMENTS);
        if (allValueTypes) property.setName("supports");
        if (allInterfaces) property.setName("extends");
        property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.IMPLEMENTS, IdeSelectorDialogType.IDL_IMPLEMENTS));
        propertiesPage.addProperty(property, new Condition() {
          public boolean execute(IdeContext context){
            return (_allValueTypes || _allInterfaces);
          }
        });
      }
    }

    if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.JAVA)) {
      property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.PUBLIC);
      property.setName("public");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          for (int i = 0; i < rwiElements.length; i++) {
            if (((RwiNode)rwiElements[i]).getContainingNode() == null) {
              if (rwiElements[i].hasProperty(RwiProperty.INTERFACE)) return false;
            } else return false;
          }
          return true;
        }
      });

      property = new RwiInspectorVisibilityProperty(rwiElements);
      editor = new SwingComboBoxEditor(
        new DefaultComboBoxModel(
          new String[] {
            "public", "protected", "package local", "private"
          }
        )
      );
      property.setPropertyEditor(editor);
      property.setDisplayName("visibility");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          boolean allTopLevel = true;
          for (int i = 0; i < rwiElements.length; i++) {
            if (((RwiNode)rwiElements[i]).getContainingNode() == null) {
              if (rwiElements[i].hasProperty(RwiProperty.INTERFACE)) break;
              return false;
            } else {
              allTopLevel = false;
            }
          }
          return (!allTopLevel);
        }
      });

      property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.STATIC);
      property.setName("static");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          boolean allTopLevel = true;
          for (int i = 0; i < rwiElements.length; i++) {
            if (((RwiNode)rwiElements[i]).getContainingNode() == null) {
              if (rwiElements[i].hasProperty(RwiProperty.INTERFACE)) break;
              return false;
            } else {
              allTopLevel = false;
            }
          }
          return (!allTopLevel);
        }
      });

      property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.FINAL);
      property.setName("final");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return RwiElementsUtil.checkProperty(context, RwiProperty.INTERFACE, false);
        }
      });

      property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.ABSTRACT);
      property.setName("abstract");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return RwiElementsUtil.checkProperty(context, RwiProperty.INTERFACE, false);
        }
      });

      property = new RwiInspectorMultipleStringProperty(rwiElements[0], 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(rwiElements[0], RwiProperty.EXTENDS, IdeSelectorDialogType.JAVA_EXTENDS));
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return !_classesAndInterfacesSelected;
        }
      });

      property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.IMPLEMENTS);
      property.setName("implements");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.IMPLEMENTS, IdeSelectorDialogType.JAVA_IMPLEMENTS));
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context){
          if (_classesAndInterfacesSelected) return false;
          return RwiElementsUtil.checkProperty(context, RwiProperty.INTERFACE, false);
        }
      });

      property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.INTERFACE);
      property.setName("interface");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context){
          return !_classesAndInterfacesSelected;
        }
      });

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

    property = new RwiInspectorBooleanProperty(rwiElements, "persistent");
    property.setName("persistent");
    propertiesPage.addProperty(property, null);

    IdeInspectorComponent javadocComponent = inspector.findComponent("Javadoc");
    IdeInspectorPropertySetComponent javadocPage;
    if (javadocComponent instanceof IdeInspectorPropertySetComponent) {
      javadocPage = (IdeInspectorPropertySetComponent)javadocComponent;
    } else {
      javadocPage = new IdeInspectorPropertySetComponent(context);
      javadocPage.setName("Javadoc");
      javadocPage.setService(UIComponentService.class, new PropertyTableComponentUI(javadocPage));
      inspector.addComponent(javadocPage, null, ComponentWeight.JAVADOC);
    }

    // JavaDoc tags

    property = new RwiInspectorMultipleStringProperty(rwiElements, "author");
    property.setDisplayName("@author");
    javadocPage.addProperty(property, null);

    property = new RwiInspectorStringProperty(rwiElements, "version");
    property.setDisplayName("@version");
    javadocPage.addProperty(property, null);

    if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.JAVA)) {
      property = new RwiInspectorStringProperty(rwiElements, "deprecated");
      property.setDisplayName("@deprecated");
      javadocPage.addProperty(property, null);

      property = new RwiInspectorMultipleStringProperty(rwiElements, "see");
      property.setDisplayName("@see");
      javadocPage.addProperty(property, null);
    }

    property = new RwiInspectorStringProperty(rwiElements, "since");
    property.setDisplayName("@since");
    javadocPage.addProperty(property, null);

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

    return inspector;
  }
}

/**
 * A read-only decorator IdeInspectorProperty for RwiProperty.FILE or RwiProperty.DEFINITION_FILE property
 */
class FileNameProperty extends RwiInspectorStringProperty {
  public FileNameProperty(RwiPropertyMap[] map, String propertyName, String visibleName){
    super(map, propertyName);
    setName(visibleName);
  }
  public FileNameProperty(RwiPropertyMap single, String propertyName, String visibleName){
    this(new RwiPropertyMap[] {single}, propertyName, visibleName);
  }
  public Object getValue(){
    String fileName = (String)super.getValue();
    if ( fileName == null ) return null;
    int ind = fileName.lastIndexOf(File.separator);
    if (ind != -1) fileName = fileName.substring(ind + 1);
    return fileName;
  }
  public boolean isWritable(){
    return false;
  }
}

