/*
 * Copyright 2000-2016 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.debugger.ui.tree.render;

import com.intellij.debugger.engine.JavaValue;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.ui.impl.watch.UserExpressionDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.frame.XValueNode;
import com.intellij.xdebugger.frame.XValuePlace;
import com.intellij.xdebugger.impl.XDebuggerUtilImpl;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeInplaceEditor;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeRestorer;
import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.sun.jdi.Type;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.tree.TreePath;
import java.util.List;

/**
 * @author egor
 */
public class CustomFieldInplaceEditor extends XDebuggerTreeInplaceEditor {
  private final UserExpressionDescriptorImpl myDescriptor;
  private final EnumerationChildrenRenderer myRenderer;

  public CustomFieldInplaceEditor(@NotNull XDebuggerTreeNode node,
                                  @Nullable UserExpressionDescriptorImpl descriptor,
                                  @Nullable EnumerationChildrenRenderer renderer) {
    super(node, "customField");
    myDescriptor = descriptor;
    myRenderer = renderer;
    myExpressionEditor.setExpression(descriptor != null ? TextWithImportsImpl.toXExpression(descriptor.getEvaluationText()) : null);
  }

  public static void editNew(@NotNull XValueNodeImpl parentNode) {
    ValueDescriptorImpl descriptor = ((JavaValue)parentNode.getValueContainer()).getDescriptor();
    EnumerationChildrenRenderer renderer = EnumerationChildrenRenderer.getCurrent(descriptor);
    XDebuggerTreeNode newNode = parentNode.addTemporaryEditorNode();
    DebuggerUIUtil.invokeLater(() -> new CustomFieldInplaceEditor(newNode, null, renderer) {
      @Override
      public void cancelEditing() {
        super.cancelEditing();
        parentNode.removeTemporaryEditorNode(newNode);
      }

      @Override
      protected List<Pair<String, TextWithImports>> getRendererChildren() {
        if (renderer != null) {
          return renderer.getChildren();
        }
        else {
          Type type = descriptor.getType();
          String name = type != null ? type.name() : null;
          EnumerationChildrenRenderer enumerationChildrenRenderer = new EnumerationChildrenRenderer();
          enumerationChildrenRenderer.setAppendDefaultChildren(true);
          NodeRenderer renderer =
            NodeRendererSettings.getInstance().createCompoundTypeRenderer(name, name, null, enumerationChildrenRenderer);
          renderer.setEnabled(true);
          NodeRendererSettings.getInstance().getCustomRenderers().addRenderer(renderer);
          NodeRendererSettings.getInstance().fireRenderersChanged();
          return enumerationChildrenRenderer.getChildren();
        }
      }
    }.show());
  }

  protected List<Pair<String, TextWithImports>> getRendererChildren() {
    return myRenderer.getChildren();
  }

  @Override
  public void doOKAction() {
    List<Pair<String, TextWithImports>> children = getRendererChildren();
    TextWithImports newText = TextWithImportsImpl.fromXExpression(myExpressionEditor.getExpression());
    if (myDescriptor == null) {
      children.add(0, Pair.create("", newText));
    }
    else {
      Integer index = myDescriptor.getUserData(UserExpressionDescriptorImpl.ENUMERATION_INDEX);
      children.set(index, Pair.create(children.get(index).first, newText));
    }

    myTree.putClientProperty(XDebuggerTreeRestorer.SELECTION_PATH_PROPERTY,
                             createDummySelectionTreePath(newText.getText(), (XDebuggerTreeNode)myNode.getParent()));

    XDebuggerUtilImpl.rebuildTreeAndViews(myTree);

    super.doOKAction();
  }

  private static TreePath createDummySelectionTreePath(String name, XDebuggerTreeNode parentNode) {
    return new XValueNodeImpl(parentNode.getTree(), parentNode, name, new XValue() {
      @Override
      public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) {
      }
    }).getPath();
  }
}

@@ -816,24 +816,77 @@
 mportsImpl;%0A
+import com.intellij.debugger.impl.DebuggerUtilsImpl;%0A
 import com.i
@@ -933,16 +933,16 @@
 ttings;%0A
-
 import c
@@ -1109,16 +1109,83 @@
 l.Pair;%0A
+import com.intellij.psi.PsiClass;%0Aimport com.intellij.psi.PsiType;%0A
 import c
@@ -1367,24 +1367,80 @@
 erUtilImpl;%0A
+import com.intellij.xdebugger.impl.XSourcePositionImpl;%0A
 import com.i
@@ -1682,24 +1682,94 @@
 erTreeNode;%0A
+import com.intellij.xdebugger.impl.ui.tree.nodes.XValueContainerNode;%0A
 import com.i
@@ -2663,16 +2663,444 @@
 : null);
+%0A%0A    ValueDescriptorImpl parentDescriptor = ((JavaValue)((XValueContainerNode)node.getParent()).getValueContainer()).getDescriptor();%0A    Pair%3CPsiClass, PsiType%3E pair = DebuggerUtilsImpl.getPsiClassAndType(getTypeName(parentDescriptor), getProject());%0A    if (pair.first != null) %7B%0A      XSourcePositionImpl position = XSourcePositionImpl.createByElement(pair.first);%0A      myExpressionEditor.setSourcePosition(position);%0A    %7D
 %0A  %7D%0A%0A  
@@ -3860,52 +3860,8 @@
 e %7B%0A
-          Type type = descriptor.getType();%0A
     
@@ -3884,41 +3884,31 @@
 e = 
-type != null ? type.n
+getTypeN
 ame(
-) : null
+descriptor)
 ;%0A  
@@ -4503,24 +4503,24 @@
   %7D%0A      %7D%0A
-
     %7D.show()
@@ -4523,24 +4523,195 @@
 ow());%0A  %7D%0A%0A
+  @Nullable%0A  private static String getTypeName(ValueDescriptorImpl descriptor) %7B%0A    Type type = descriptor.getType();%0A    return type != null ? type.name() : null;%0A  %7D%0A%0A
   protected 

correct context for class level watch editor