/*------------------------------------------------------------------------------
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 OperationInspector 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.OPERATION))
      return inspector;
    RwiElement[] rwiElements = RwiElementsUtil.getRwiElements(context);
    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);
    }

    property = new RwiInspectorStringProperty(rwiElements, "stereotype");
    SwingComboBoxEditor editor = new SwingComboBoxEditor(
      new DefaultComboBoxModel(
        new String[] {
          "query", "constructor", "update", "external"
        }
      )
    );
    editor.setValueEditable(true);
    property.setPropertyEditor(editor);
    propertiesPage.addProperty(property, null);

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

    if (RwiElementsUtil.checkProperty(context, RwiProperty.DESTRUCTOR, false)) {
      property = new RwiInspectorStringProperty(rwiElements, RwiProperty.PARAMETERS_TEXT);
      property.setValue(IdeInspectorProperty.MULTI_VALUE_TAG, Boolean.TRUE);
      property.setName("parameters");
      propertiesPage.addProperty(property, null);
    }

    if (RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false) && RwiElementsUtil.checkProperty(context, RwiProperty.DESTRUCTOR, false)) {
      property = new RwiInspectorStringProperty(rwiElements, RwiProperty.RETURN_TYPE);
      property.setName("return value");
      propertiesPage.addProperty(property, null);
    }

    property = new RwiInspectorStringProperty(rwiElements[0], RwiProperty.ASSOCIATES);
    property.setName("associates");
    property.setPropertyEditor(new SingleElementChooserEditor(rwiElements[0], IdeSelectorDialogType.ASSOCIATES));
    propertiesPage.addProperty(property, null);

    if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.JAVA)) {
      property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.THROW);
      property.setName("throws");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.THROW, IdeSelectorDialogType.JAVA_THROWS));
      propertiesPage.addProperty(property, null);

      boolean interfaceMember = false;
      for (int i = 0; i < rwiElements.length; i++) {
        if (((RwiMember)rwiElements[i]).getContainingNode().hasProperty(RwiProperty.INTERFACE)) {
          interfaceMember = true;
          break;
        }
      }

      final boolean _interfaceMember = interfaceMember;

      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) {
          return !_interfaceMember;
        }
      });

      if (RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false)) {
        final RwiElement[] finalRwiElements = rwiElements;
        property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.STATIC) {
          public boolean canSetValue(Object value){
            for (int i = 0; i < finalRwiElements.length; i++) {
              if (finalRwiElements[i].hasProperty(RwiProperty.ABSTRACT))
                return false;
            }
            return true;
          }
        };
        property.setName("static");
        propertiesPage.addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return (!_interfaceMember && RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false));
          }
        });

        property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.FINAL) {
          public boolean canSetValue(Object value){
            for (int i = 0; i < finalRwiElements.length; i++) {
              if (finalRwiElements[i].hasProperty(RwiProperty.ABSTRACT))
                return false;
            }
            return true;
          }
        };
        property.setName("final");
        propertiesPage.addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return (!_interfaceMember && RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false));
          }
        });

        property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.ABSTRACT) {
          public boolean canSetValue(Object value){
            for (int i = 0; i < finalRwiElements.length; i++) {
              if (finalRwiElements[i].hasProperty(RwiProperty.STATIC) ||
                  finalRwiElements[i].hasProperty(RwiProperty.FINAL))
                return false;
            }
            return true;
          }
        };
        property.setName("abstract");
        propertiesPage.addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return (!_interfaceMember && RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false));
          }
        });

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

        property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.NATIVE);
        property.setName("native");
        propertiesPage.addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return (!_interfaceMember && RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false));
          }
        });
      }
    } else if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.CPP)) {
      final RwiMember operation = (RwiMember)rwiElements[0];
      property = new RwiInspectorStringProperty(operation, RwiProperty.DEFINITION_FILE){
        public boolean isWritable(){
          return !operation.getContainingNode().hasProperty(RwiProperty.INTERFACE);
        }
      };

      property.setPropertyEditor(new ExtendedFileNameEditor(null, new com.togethersoft.openapi.ide.window.IdeFileFilter(){
        public String getMask() {
            return "*.cpp";
        }
        public boolean accept(java.io.File file) {
            return file.exists() && file.isFile() && file.getName().toLowerCase().endsWith(".cpp");
        }

        public String getDescription() {
            return "C++ definition files";
        }
        }));
      property.setName("definition file");
      propertiesPage.addProperty(property, null);

      property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.THROW);
      property.setName("throw");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.THROW, IdeSelectorDialogType.CPP_THROWS));
      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, null);

      final RwiElement[] finalRwiElements = rwiElements;

      property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.STATIC) {
        public boolean canSetValue(Object value){
          for (int i = 0; i < finalRwiElements.length; i++) {
            if (finalRwiElements[i].hasProperty(RwiProperty.ABSTRACT) ||
                finalRwiElements[i].hasProperty(RwiProperty.VIRTUAL) ||
                finalRwiElements[i].hasProperty(RwiProperty.CONST) ||
                finalRwiElements[i].hasProperty(RwiProperty.VOLATILE))
              return false;
          }
          return true;
        }
      };
      property.setName("static");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return (RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false) &&
                  RwiElementsUtil.checkProperty(context, RwiProperty.DESTRUCTOR, false));
        }
      });

      property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.VIRTUAL) {
        public boolean canSetValue(Object value){
          for (int i = 0; i < finalRwiElements.length; i++) {
            if (finalRwiElements[i].hasProperty(RwiProperty.STATIC))
              return false;
          }
          return true;
        }
      };
      property.setName("virtual");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false);
        }
      });

      property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.ABSTRACT) {
        public boolean canSetValue(Object value){
          for (int i = 0; i < finalRwiElements.length; i++) {
            if (finalRwiElements[i].hasProperty(RwiProperty.STATIC) ||
                finalRwiElements[i].hasProperty(RwiProperty.FINAL))
              return false;
          }
          return true;
        }
      };
      property.setName("abstract");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false);
        }
      });

      property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.CONST) {
        public boolean canSetValue(Object value){
          for (int i = 0; i < finalRwiElements.length; i++) {
            if (finalRwiElements[i].hasProperty(RwiProperty.STATIC))
              return false;
          }
          return true;
        }
      };
      property.setName("const");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return (RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false) &&
                  RwiElementsUtil.checkProperty(context, RwiProperty.DESTRUCTOR, false));
        }
      });

      property = new RwiInspectorBooleanProperty(rwiElements, RwiProperty.INLINE);
      property.setName("inline");
      propertiesPage.addProperty(property, null);

      property = new RwiInspectorBooleanProperty(finalRwiElements, RwiProperty.VOLATILE) {
        public boolean canSetValue(Object value){
          for (int i = 0; i < finalRwiElements.length; i++) {
            if (finalRwiElements[i].hasProperty(RwiProperty.STATIC))
              return false;
          }
          return true;
        }
      };
      property.setName("volatile");
      propertiesPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return (RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false) &&
                  RwiElementsUtil.checkProperty(context, RwiProperty.DESTRUCTOR, false));
        }
      });
    } else if (RwiElementsUtil.checkProperty(context, RwiProperty.LANGUAGE, RwiLanguage.IDL)) {
      property = new RwiInspectorMultipleStringProperty(rwiElements[0], RwiProperty.THROW);
      property.setName("raises");
      property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(rwiElements[0], RwiProperty.THROW, IdeSelectorDialogType.IDL_THROWS));
      propertiesPage.addProperty(property, null);
    }

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

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

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

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

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

    property = new RwiInspectorStringProperty(rwiElements, "semantics");
    property.setDisplayName("semantics");
    property.setPropertyEditor(new ExtendedStringEditor("semantics"));
    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

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

      property = new RwiInspectorStringProperty(rwiElements, "return");
      property.setDisplayName("@return");
      javadocPage.addProperty(property, new Condition() {
        public boolean execute(IdeContext context) {
          return RwiElementsUtil.checkProperty(context, RwiProperty.CONSTRUCTOR, false);
        }
      });

      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 RwiInspectorMultipleStringProperty(rwiElements, "exception");
      property.setDisplayName("@exception");
      javadocPage.addProperty(property, null);
    }

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

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

    return inspector;
  }
}

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

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

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

      String val = "public";
      if (myRwiPropertyMaps[i].hasProperty(RwiProperty.PROTECTED))
        val = "protected";
      if (myRwiPropertyMaps[i].hasProperty(RwiProperty.PACKAGE_LOCAL))
        val = "package local";
      if (myRwiPropertyMaps[i].hasProperty(RwiProperty.PRIVATE))
        val = "private";
      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; }
      String propertyName = RwiProperty.PUBLIC;
      if ( "protected".equals(myValue) ) {
        propertyName = RwiProperty.PROTECTED;
      } else if ( "package local".equals(myValue) ) {
        propertyName = RwiProperty.PACKAGE_LOCAL;
      } else if ( "private".equals(myValue) ) {
        propertyName = RwiProperty.PRIVATE;
      }
      if (myRwiPropertyMaps[i].canSetProperty(propertyName, true)) {
        myRwiPropertyMaps[i].setProperty(propertyName, true);
      }
    }
  }

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