/*
 * Copyright 2000-2011 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.impl;

import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nullable;

/**
 * @author Maxim.Medvedev
 */
public class JavaEditorTextProviderImpl implements EditorTextProvider {
  private static final Logger LOG = Logger.getInstance(JavaEditorTextProviderImpl.class);

  @Override
  public TextWithImports getEditorText(PsiElement elementAtCaret) {
    String result = null;
    PsiElement element = findExpression(elementAtCaret);
    if (element != null) {
      if (element instanceof PsiReferenceExpression) {
        final PsiReferenceExpression reference = (PsiReferenceExpression)element;
        if (reference.getQualifier() == null) {
          final PsiElement resolved = reference.resolve();
          if (resolved instanceof PsiEnumConstant) {
            final PsiEnumConstant enumConstant = (PsiEnumConstant)resolved;
            final PsiClass enumClass = enumConstant.getContainingClass();
            if (enumClass != null) {
              result = enumClass.getName() + "." + enumConstant.getName();
            }
          }
        }
      }
      if (result == null) {
        result = element.getText();
      }
    }
    return result != null? new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, result) : null;
  }

  @Nullable
  private static PsiElement findExpression(PsiElement element) {
    if (!(element instanceof PsiIdentifier || element instanceof PsiKeyword)) {
      return null;
    }
    PsiElement parent = element.getParent();
    if (parent instanceof PsiVariable) {
      return element;
    }
    if (parent instanceof PsiReferenceExpression) {
      if (parent.getParent() instanceof PsiCallExpression) return parent.getParent();
      return parent;
    }
    if (parent instanceof PsiThisExpression) {
      return parent;
    }
    return null;
  }

  @Nullable
  public Pair<PsiElement, TextRange> findExpression(PsiElement element, boolean allowMethodCalls) {
    if (!(element instanceof PsiIdentifier || element instanceof PsiKeyword)) {
      return null;
    }

    PsiElement expression = null;
    PsiElement parent = element.getParent();
    if (parent instanceof PsiVariable) {
      expression = element;
    }
    else if (parent instanceof PsiReferenceExpression) {
      final PsiElement pparent = parent.getParent();
      if (pparent instanceof PsiCallExpression) {
        parent = pparent;
      }
      if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
        expression = parent;
      }
    }
    else if (parent instanceof PsiThisExpression) {
      expression = parent;
    }

    if (expression != null) {
      try {
        PsiElement context = element;
        if(parent instanceof PsiParameter) {
          try {
            context = ((PsiMethod)((PsiParameter)parent).getDeclarationScope()).getBody();
          }
          catch (Throwable ignored) {
          }
        }
        else {
          while(context != null  && !(context instanceof PsiStatement) && !(context instanceof PsiClass)) {
            context = context.getParent();
          }
        }
        TextRange textRange = expression.getTextRange();
        PsiElement psiExpression = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory().createExpressionFromText(expression.getText(), context);
        return Pair.create(psiExpression, textRange);
      }
      catch (IncorrectOperationException e) {
        LOG.debug(e);
      }
    }
    return null;
  }

}

@@ -1036,16 +1036,58 @@
 .psi.*;%0A
+import com.intellij.psi.util.PsiTreeUtil;%0A
 import c
@@ -2430,57 +2430,110 @@
     
-if (!(element instanceof PsiIdentifier %7C%7C element
+PsiElement e = PsiTreeUtil.getParentOfType(element, PsiVariable.class, PsiExpression.class);%0A    if (e
  ins
@@ -2539,32 +2539,32 @@
 stanceof Psi
-Keyword)
+Variable
 ) %7B%0A      re
@@ -2565,80 +2565,118 @@
     
-return null;%0A    %7D%0A    PsiElement parent = element.getParent();%0A
+e = ((PsiVariable)e).getNameIdentifier();%0A    %7D%0A    else if (e instanceof PsiReferenceExpression) %7B%0A  
     if (
 pare
@@ -2663,38 +2663,45 @@
 on) %7B%0A      if (
-p
+e.getP
 arent
+()
  instanceof PsiV
@@ -2703,42 +2703,55 @@
  Psi
-Variable) %7B%0A      return element;%0A
+CallExpression) %7B%0A        e = e.getParent();%0A  
     
@@ -2752,34 +2752,48 @@
       %7D%0A    
+  
-if (p
+else if (e.getP
 arent
+()
  instanceof 
@@ -2828,74 +2828,197 @@
     
-if (parent.getParent() instanceof PsiCallExpression) return parent
+  // %3Ccaret%3ESystem.out case should not return plain class name%0A        PsiElement resolve = ((PsiReferenceExpression)e).resolve();%0A        if (resolve instanceof PsiClass) %7B%0A          e = e
 .get
@@ -3029,38 +3029,35 @@
 nt();%0A      
-return parent;
+  %7D%0A      %7D
 %0A    %7D%0A    i
@@ -3051,38 +3051,33 @@
 %7D%0A    %7D%0A    if (
-parent
+e
  instanceof PsiT
@@ -3067,36 +3067,35 @@
 e instanceof Psi
-This
+New
 Expression) %7B%0A  
@@ -3102,21 +3102,111 @@
     
-return parent
+// skip new Runnable() %7B ... %7D%0A      if (((PsiNewExpression)e).getAnonymousClass() != null) return null
 ;%0A  
@@ -3216,28 +3216,25 @@
 %0A    return 
-null
+e
 ;%0A  %7D%0A%0A  @Nu

improve Alt-F8 behaviour: instanceof expressions, constructors & etc.