/*------------------------------------------------------------------------------
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.rwi.enum.*;
import com.togethersoft.openapi.util.function.*;
import com.togethersoft.openapi.ide.window.IdeSelectorDialogType;
import javax.swing.DefaultComboBoxModel;
import com.togethersoft.openapi.util.RwiElementsUtil;
import java.io.*;
import java.util.*;

/**
 * @author TogetherSoft
 */
public class MessageLinkInspector implements IdeStartup, IdeInspectorBuilder {
    public void autorun() {
        IdeInspectorManager manager = IdeInspectorManagerAccess.getInspectorManager();
        manager.addInspectorBuilder(this);
    }

    public static RwiElement getMessageOperationElement(RwiElement in) {
        if (in == null) return null;
        RwiElement messageOperationElement = null;
        String messageOperationName = in.getProperty("$messageOperationName");

        if ((messageOperationName == null) || !(in instanceof RwiLink)) return null;
        String instantiatedClassUniqueName = ((RwiLink)in).getDestination().getProperty("$instantiatedClass");
        RwiElement instantiatedClass = RwiModelAccess.getModel().findElement(instantiatedClassUniqueName);
        if ((instantiatedClass == null) || !(instantiatedClass instanceof RwiNode)) return null;
        RwiMemberEnumeration memberEnumeration = ((RwiNode)instantiatedClass).members();
        while (memberEnumeration.hasMoreElements()) {
            Object current = memberEnumeration.nextElement();

            if ( ((RwiMember)current).getProperty(RwiProperty.SHAPE_TYPE).equals(RwiShapeType.OPERATION) &&
                 (((RwiMember)current).getProperty("$operationDetailedName").equals(messageOperationName)) ) {
                messageOperationElement = (RwiElement)current;
                break;
            }
        }
        return messageOperationElement;
    }

    public IdeInspector buildInspector(IdeContext context, IdeInspector inspector) {
        if (!RwiElementsUtil.checkProperty(context, RwiProperty.SHAPE_TYPE, "MessageLink") &&
            !RwiElementsUtil.checkProperty(context, RwiProperty.SHAPE_TYPE, "Activation"))
            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("Link");
            propertiesPage.setService(UIComponentService.class, new PropertyTableComponentUI(propertiesPage));
            inspector.addComponent(propertiesPage, null, ComponentWeight.PROPERTIES);
        }
        IdeInspectorProperty property;

        boolean isActivation = false;

        if (RwiElementsUtil.checkProperty(context, RwiProperty.SHAPE_TYPE, "Activation")) {

          isActivation = true;
          // Get message link RwiElement from activation
          for (int i = 0; i < rwiElements.length; i++) {
            String activationMessageUniqueName = rwiElements[i].getProperty("activationMessage");
            if (activationMessageUniqueName == null) return inspector;

            rwiElements[i] = RwiModelAccess.getModel().findElement(activationMessageUniqueName);
          }
        }

        if (rwiElements.length == 1 && rwiElements[0] instanceof RwiLink) {
            String sourceName = ((RwiLink)rwiElements[0]).getSource().getProperty(RwiProperty.NAME);
            property = new ReadOnlyProperty(sourceName, String.class);
            property.setName("client");
            propertiesPage.addProperty(property, null);
            String destinationName = ((RwiLink)rwiElements[0]).getDestination().getProperty(RwiProperty.NAME);
            property = new ReadOnlyProperty(destinationName, String.class);
            property.setName("supplier");
            propertiesPage.addProperty(property, null);
            if (((RwiLink)rwiElements[0]).getDestination().hasProperty("$instantiatedClass")) {
                property = new RwiInspectorStringProperty(rwiElements[0], "$messageOperationName");
                property.setName("operation");
                SingleElementChooserEditor secEditor = new
                    SingleElementChooserEditor(rwiElements[0],
                    com.togethersoft.openapi.ide.window.IdeSelectorDialogType.MESSAGE_OPERATION) {
                        protected Object extractValueFromRwiElement(RwiElement rwiElement) {
                            return rwiElement.getProperty("$operationDetailedName");
                        }
                };
                property.setPropertyEditor(secEditor);
                propertiesPage.addProperty(property, null);
            } else if (rwiElements[0].hasProperty("$messageOperationName")) {
                property = new RwiInspectorStringProperty(rwiElements[0], "$messageOperationName");
                property.setName("operation");
                propertiesPage.addProperty(property, null);
            }
        }
        property = new RwiInspectorStringProperty(rwiElements, "label");
        property.setName("label");
        propertiesPage.addProperty(property, null);
        // TO DO : Highlight text symbols in number field
        property = new RwiInspectorStringProperty(rwiElements, "$sequenceNumber");
        property.setName("sequence number");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorBooleanProperty(rwiElements, "$creationMessage");
        property.setName("creation");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorBooleanProperty(rwiElements, "$destructionMessage");
        property.setName("destruction");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "arguments");
        property.setName("arguments");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "return");
        property.setName("return");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorBooleanProperty(rwiElements, "showReturnArrow");
        property.setName("return arrow");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "condition");
        property.setName("condition");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "iteration");
        property.setName("iteration");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "constraint");
        property.setName("constraint");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "$controlFlowType");
        property.setName("synchronization");
        SwingComboBoxEditor editor = new SwingComboBoxEditor(new DefaultComboBoxModel(new String[] {
            "call", "synchronous", "asynchronous", "wait", "nowait"
        }), new String[] {
            "call", "synchronous", "asynchronous", "wait", "nowait"
        }, new String[] {
            "/DropDowns/seq-call.gif", "/DropDowns/seq-synchronus.gif", "/DropDowns/seq-asynchronous.gif",
                "/DropDowns/seq-wait.gif", "/DropDowns/seq-nowait.gif"
        });
        editor.setValueEditable(false);
        property.setPropertyEditor(editor);
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "sendTime");
        property.setName("send time");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorStringProperty(rwiElements, "receiveTime");
        property.setName("receive time");
        propertiesPage.addProperty(property, null);
        property = new RwiInspectorBooleanProperty(rwiElements, "$nonAtomicDelivery");
        property.setName("non-atomic delivery");
        propertiesPage.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);
            if (isActivation) return inspector;
            addOperationPage(context, inspector, rwiElements[0]);
        }
        return inspector;
    }

    private void addOperationPage(IdeContext context, IdeInspector inspector, RwiElement rwiElement) {
        IdeInspectorComponent operationComponent = inspector.findComponent("Operation");
        IdeInspectorPropertySetComponent operationPage = null;
        if (operationComponent == null) {
            operationComponent = new OperationComponent(context, rwiElement);
            if (operationComponent instanceof IdeInspectorPropertySetComponent) {
                operationPage = (IdeInspectorPropertySetComponent)operationComponent;
            }
            final RwiElement finalRwiElement = rwiElement;
            inspector.addComponent(operationPage, new Condition() {
              public boolean execute(IdeContext context) {
                return (((RwiLink)finalRwiElement).getDestination().hasProperty("$instantiatedClass") &&
                    finalRwiElement.hasProperty("$messageOperationName"));
              }
            }, ComponentWeight.MEMBER);
        }
    }
}


class OperationComponent extends IdeInspectorPropertySetComponent {
    public OperationComponent(IdeContext context, RwiElement rwiElement) {
        super(context);
        myRwiElement = 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() {
        if (myRwiElement.getProperty(RwiProperty.SHAPE_TYPE).equals("MessageLink")) {
          myRwiElement = MessageLinkInspector.getMessageOperationElement(myRwiElement);
          if (myRwiElement == null) return;
        }

        IdeInspectorProperty property;

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

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

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

        final RwiElement finalRwiElement = myRwiElement;

        property = new RwiInspectorStringProperty(myRwiElement, RwiProperty.PARAMETERS_TEXT);
        property.setValue(IdeInspectorProperty.MULTI_VALUE_TAG, Boolean.TRUE);
        property.setName("parameters");
        addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return (! finalRwiElement.hasProperty(RwiProperty.DESTRUCTOR));
          }
        });

        property = new RwiInspectorStringProperty(myRwiElement, RwiProperty.RETURN_TYPE);
        property.setName("return value");
        addProperty(property, new Condition() {
          public boolean execute(IdeContext context) {
            return (! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR) &&
                    ! finalRwiElement.hasProperty(RwiProperty.DESTRUCTOR));
          }
        });

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

        if (myRwiElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.JAVA)) {
            property = new RwiInspectorMultipleStringProperty(myRwiElement, RwiProperty.THROW);
            property.setName("throws");
            property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(myRwiElement,
                RwiProperty.THROW, IdeSelectorDialogType.JAVA_THROWS));
            addProperty(property, null);

            property = new RwiInspectorVisibilityProperty(myRwiElement);
            editor = new SwingComboBoxEditor(new DefaultComboBoxModel(new String[] {
              "public", "protected", "package local", "private"
            }));
            property.setPropertyEditor(editor);
            property.setDisplayName("visibility");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return !((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE);
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.STATIC) {
              public boolean canSetValue(Object value) {
                return (! finalRwiElement.hasProperty(RwiProperty.ABSTRACT));
              }
            };
            property.setName("static");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.FINAL) {
              public boolean canSetValue(Object value) {
                return (! finalRwiElement.hasProperty(RwiProperty.ABSTRACT));
              }
            };
            property.setName("final");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.ABSTRACT) {
              public boolean canSetValue(Object value) {
                return (!finalRwiElement.hasProperty(RwiProperty.STATIC) &&
                        !finalRwiElement.hasProperty(RwiProperty.FINAL));
              }
            };
            property.setName("abstract");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.SYNCHRONIZED);
            property.setName("synchronized");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.NATIVE);
            property.setName("native");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });
        } else if (myRwiElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.CPP)) {
            property = new RwiInspectorStringProperty(myRwiElement, RwiProperty.DEFINITION_FILE) {
                public boolean isWritable() {
                    return !((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE);
                }
            };
            property.setPropertyEditor(new ExtendedFileNameEditor("open"));
            property.setName("definition file");
            addProperty(property, null);

            property = new RwiInspectorMultipleStringProperty(myRwiElement, RwiProperty.THROW);
            property.setName("throw");
            property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(myRwiElement,
                RwiProperty.THROW, IdeSelectorDialogType.CPP_THROWS));
            addProperty(property, null);

            property = new RwiInspectorVisibilityProperty(myRwiElement);
            editor = new SwingComboBoxEditor(new DefaultComboBoxModel(new String[] {
                "public", "protected", "private"
            }));
            property.setPropertyEditor(editor);
            property.setDisplayName("visibility");
            addProperty(property, null);

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.STATIC) {
              public boolean canSetValue(Object value) {
                return (! finalRwiElement.hasProperty(RwiProperty.ABSTRACT) &&
                        ! finalRwiElement.hasProperty(RwiProperty.VIRTUAL) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONST) &&
                        ! finalRwiElement.hasProperty(RwiProperty.VOLATILE));
              }
            };
            property.setName("static");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR) &&
                        ! finalRwiElement.hasProperty(RwiProperty.DESTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.VIRTUAL) {
              public boolean canSetValue(Object value) {
                return (! finalRwiElement.hasProperty(RwiProperty.STATIC));
              }
            };
            property.setName("virtual");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.ABSTRACT) {
              public boolean canSetValue(Object value) {
                return (! finalRwiElement.hasProperty(RwiProperty.STATIC) &&
                        ! finalRwiElement.hasProperty(RwiProperty.FINAL));
              }
            };
            property.setName("abstract");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! ((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE) &&
                        ! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.CONST) {
              public boolean canSetValue(Object value) {
                return (! finalRwiElement.hasProperty(RwiProperty.STATIC));
              }
            };
            property.setName("const");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR) &&
                        ! finalRwiElement.hasProperty(RwiProperty.DESTRUCTOR));
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.INLINE);
            property.setName("inline");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return !((RwiMember)finalRwiElement).getContainingNode().hasProperty(RwiProperty.INTERFACE);
              }
            });

            property = new RwiInspectorBooleanProperty(myRwiElement, RwiProperty.VOLATILE) {
                public boolean canSetValue(Object value) {
                    return (! finalRwiElement.hasProperty(RwiProperty.STATIC));
                }
            };
            property.setName("volatile");
            addProperty(property, new Condition() {
              public boolean execute(IdeContext context) {
                return (! finalRwiElement.hasProperty(RwiProperty.CONSTRUCTOR) &&
                        ! finalRwiElement.hasProperty(RwiProperty.DESTRUCTOR));
              }
            });
        } else if (myRwiElement.getProperty(RwiProperty.LANGUAGE).equals(RwiLanguage.IDL)) {
            property = new RwiInspectorMultipleStringProperty(myRwiElement, RwiProperty.THROW);
            property.setName("raises");
            property.setPropertyEditor(new RwiPropertyMultiValueElementChooserEditor(myRwiElement,
                RwiProperty.THROW, IdeSelectorDialogType.IDL_THROWS));
            addProperty(property, null);
        }

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

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

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

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

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

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

    private RwiElement myRwiElement;
}
