/*
 * Copyright 2000-2014 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.codeInsight.completion;

import com.intellij.codeInsight.*;
import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.util.Key;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PatternCondition;
import com.intellij.patterns.PsiElementPattern;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.psi.*;
import com.intellij.psi.filters.ElementExtractorFilter;
import com.intellij.psi.filters.ElementFilter;
import com.intellij.psi.filters.GeneratorFilter;
import com.intellij.psi.filters.OrFilter;
import com.intellij.psi.filters.getters.*;
import com.intellij.psi.filters.types.AssignableFromFilter;
import com.intellij.psi.filters.types.AssignableGroupFilter;
import com.intellij.psi.filters.types.AssignableToFilter;
import com.intellij.psi.impl.source.PsiLabelReference;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

import static com.intellij.patterns.PlatformPatterns.psiElement;
import static com.intellij.patterns.PsiJavaPatterns.psiMethod;
import static com.intellij.patterns.StandardPatterns.*;

/**
 * @author peter
 */
public class JavaSmartCompletionContributor extends CompletionContributor {
  private static final TObjectHashingStrategy<ExpectedTypeInfo> EXPECTED_TYPE_INFO_STRATEGY = new TObjectHashingStrategy<ExpectedTypeInfo>() {
    @Override
    public int computeHashCode(final ExpectedTypeInfo object) {
      return object.getType().hashCode();
    }

    @Override
    public boolean equals(final ExpectedTypeInfo o1, final ExpectedTypeInfo o2) {
      return o1.getType().equals(o2.getType());
    }
  };

  private static final ElementExtractorFilter THROWABLES_FILTER = new ElementExtractorFilter(new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE));
  @NonNls private static final String EXCEPTION_TAG = "exception";
  public static final ElementPattern<PsiElement> AFTER_NEW =
      psiElement().afterLeaf(
          psiElement().withText(PsiKeyword.NEW).andNot(
              psiElement().afterLeaf(
                  psiElement().withText(PsiKeyword.THROW))));
  static final ElementPattern<PsiElement> AFTER_THROW_NEW = psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW).afterLeaf(PsiKeyword.THROW));
  private static final OrFilter THROWABLE_TYPE_FILTER = new OrFilter(
      new GeneratorFilter(AssignableGroupFilter.class, new ThrowsListGetter()),
      new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE));
  public static final ElementPattern<PsiElement> INSIDE_EXPRESSION = or(
        psiElement().withParent(PsiExpression.class).andNot(psiElement().withParent(PsiLiteralExpression.class)).andNot(psiElement().withParent(PsiMethodReferenceExpression.class)),
        psiElement().inside(PsiClassObjectAccessExpression.class),
        psiElement().inside(PsiThisExpression.class),
        psiElement().inside(PsiSuperExpression.class)
        );
  static final ElementPattern<PsiElement> INSIDE_TYPECAST_EXPRESSION = psiElement().withParent(
    psiElement(PsiReferenceExpression.class).afterLeaf(
      psiElement().withText(")").withParent(PsiTypeCastExpression.class)));
  static final PsiElementPattern.Capture<PsiElement> IN_TYPE_ARGS =
    psiElement().inside(psiElement(PsiReferenceParameterList.class));
  static final PsiElementPattern.Capture<PsiElement> LAMBDA = psiElement().with(new PatternCondition<PsiElement>("LAMBDA_CONTEXT") {
    @Override
    public boolean accepts(@NotNull PsiElement element, ProcessingContext context) {
      final PsiElement rulezzRef = element.getParent();
      return rulezzRef != null &&
             rulezzRef instanceof PsiReferenceExpression &&
             ((PsiReferenceExpression)rulezzRef).getQualifier() == null &&
             LambdaUtil.isValidLambdaContext(rulezzRef.getParent());
    }});

  static final PsiElementPattern.Capture<PsiElement> METHOD_REFERENCE = psiElement().with(new PatternCondition<PsiElement>("METHOD_REFERENCE_CONTEXT") {
    @Override
    public boolean accepts(@NotNull PsiElement element, ProcessingContext context) {
      final PsiElement rulezzRef = element.getParent();
      return rulezzRef != null &&
             LambdaUtil.isValidLambdaContext(rulezzRef.getParent());
    }});

  @Nullable
  private static ElementFilter getReferenceFilter(PsiElement element) {
    //throw new foo
    if (AFTER_THROW_NEW.accepts(element)) {
      return new ElementExtractorFilter(THROWABLE_TYPE_FILTER);
    }

    //new xxx.yyy
    if (psiElement().afterLeaf(psiElement().withText(".")).withSuperParent(2, psiElement(PsiNewExpression.class)).accepts(element)) {
      if (((PsiNewExpression)element.getParent().getParent()).getClassReference() == element.getParent()) {
        return new GeneratorFilter(AssignableGroupFilter.class, new ExpectedTypesGetter());
      }
    }

    return null;
  }



  public JavaSmartCompletionContributor() {
    extend(CompletionType.SMART, SmartCastProvider.INSIDE_TYPECAST_TYPE, new SmartCastProvider());

    extend(CompletionType.SMART, SameSignatureCallParametersProvider.IN_CALL_ARGUMENT, new SameSignatureCallParametersProvider());

    extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.INSTANCEOF), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
        final PsiElement position = parameters.getPosition();
        final PsiType[] leftTypes = InstanceOfLeftPartTypeGetter.getLeftTypes(position);
        final Set<PsiClassType> expectedClassTypes = new LinkedHashSet<PsiClassType>();
        final Set<PsiClass> parameterizedTypes = new THashSet<PsiClass>();
        for (final PsiType type : leftTypes) {
          if (type instanceof PsiClassType) {
            final PsiClassType classType = (PsiClassType)type;
            if (!classType.isRaw()) {
              ContainerUtil.addIfNotNull(classType.resolve(), parameterizedTypes);
            }

            expectedClassTypes.add(classType.rawType());
          }
        }

        JavaInheritorsGetter
          .processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer<PsiType>() {
            @Override
            public void consume(PsiType type) {
              final PsiClass psiClass = PsiUtil.resolveClassInType(type);
              if (psiClass == null || psiClass instanceof PsiTypeParameter) return;

              //noinspection SuspiciousMethodCalls
              if (expectedClassTypes.contains(type)) return;

              result.addElement(createInstanceofLookupElement(psiClass, parameterizedTypes));
            }
          });
      }
    });

    extend(CompletionType.SMART, psiElement(), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
        final PsiElement element = parameters.getPosition();
        final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset());
        if (reference != null) {
          final ElementFilter filter = getReferenceFilter(element);
          if (filter != null) {
            final List<ExpectedTypeInfo> infos = Arrays.asList(getExpectedTypes(parameters));
            for (final LookupElement item : completeReference(element, reference, filter, true, false, parameters, result.getPrefixMatcher())) {
              if (item.getObject() instanceof PsiClass) {
                result.addElement(decorate(LookupElementDecorator.withInsertHandler((LookupItem)item, ConstructorInsertHandler.SMART_INSTANCE), infos));
              }
            }
          }
          else if (INSIDE_TYPECAST_EXPRESSION.accepts(element)) {
            for (final LookupElement item : completeReference(element, reference, new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()), false, true, parameters,
                                                              result.getPrefixMatcher())) {
              result.addElement(item);
            }
          }

        }
      }
    });

    //method throws clause
    extend(CompletionType.SMART, psiElement().inside(
      psiElement(PsiReferenceList.class).save("refList").withParent(
        psiMethod().withThrowsList(get("refList")))), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull CompletionParameters parameters,
                                    ProcessingContext context,
                                    @NotNull CompletionResultSet result) {
        final PsiElement element = parameters.getPosition();
        final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset());
        assert reference != null;
        for (final LookupElement item : completeReference(element, reference, THROWABLES_FILTER, true, false, parameters, result.getPrefixMatcher())) {
          result.addElement(item);
        }
      }
    });

    extend(CompletionType.SMART, INSIDE_EXPRESSION, new ExpectedTypeBasedCompletionProvider() {
      @Override
      protected void addCompletions(final CompletionParameters params, final CompletionResultSet result, final Collection<ExpectedTypeInfo> _infos) {
        Consumer<LookupElement> noTypeCheck = new Consumer<LookupElement>() {
          @Override
          public void consume(final LookupElement lookupElement) {
            result.addElement(decorate(lookupElement, _infos));
          }
        };

        THashSet<ExpectedTypeInfo> mergedInfos = new THashSet<ExpectedTypeInfo>(_infos, EXPECTED_TYPE_INFO_STRATEGY);
        List<Runnable> chainedEtc = new ArrayList<Runnable>();
        for (final ExpectedTypeInfo info : mergedInfos) {
          Runnable slowContinuation =
            ReferenceExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(params, info), noTypeCheck);
          ContainerUtil.addIfNotNull(chainedEtc, slowContinuation);
        }
        addExpectedTypeMembers(params, mergedInfos, true, noTypeCheck);

        for (final ExpectedTypeInfo info : mergedInfos) {
          BasicExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(params, info), new Consumer<LookupElement>() {
            @Override
            public void consume(LookupElement lookupElement) {
              final TypedLookupItem typed = lookupElement.as(TypedLookupItem.CLASS_CONDITION_KEY);
              if (typed != null) {
                final PsiType psiType = typed.getType();
                if (psiType != null && info.getType().isAssignableFrom(psiType)) {
                  result.addElement(decorate(lookupElement, _infos));
                }
              }
            }
          }, result.getPrefixMatcher());
          
        }

        for (Runnable runnable : chainedEtc) {
          runnable.run();
        }


        final boolean searchInheritors = params.getInvocationCount() > 1;
        if (searchInheritors) {
          addExpectedTypeMembers(params, mergedInfos, false, noTypeCheck);
        }
      }
    });

    extend(CompletionType.SMART, or(
      PsiJavaPatterns.psiElement().withParent(PsiNameValuePair.class),
      PsiJavaPatterns.psiElement().withSuperParent(2, PsiNameValuePair.class)), new CompletionProvider<CompletionParameters>() {
      @Override
      public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
        final PsiElement element = parameters.getPosition();
        final ElementPattern<? extends PsiElement> leftNeighbor = JavaCompletionData.AFTER_DOT;
        final boolean needQualify = leftNeighbor.accepts(element);

        for (final PsiType type : ExpectedTypesGetter.getExpectedTypes(element, false)) {
          final PsiClass psiClass = PsiUtil.resolveClassInType(type);
          if (psiClass != null && psiClass.isAnnotationType()) {
            final LookupItem item = AllClassesGetter.createLookupItem(psiClass, AnnotationInsertHandler.INSTANCE);
            if (needQualify) JavaCompletionUtil.qualify(item);
            result.addElement(item);
          }
        }

      }
    });

    extend(CompletionType.SMART, psiElement().inside(
      psiElement(PsiDocTag.class).withName(
        string().oneOf(PsiKeyword.THROWS, EXCEPTION_TAG))), new CompletionProvider<CompletionParameters>() {
      @Override
      public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
        final PsiElement element = parameters.getPosition();
        final Set<PsiClass> throwsSet = new HashSet<PsiClass>();
        final PsiMethod method = PsiTreeUtil.getContextOfType(element, PsiMethod.class, true);
        if(method != null){
          for (PsiClassType ref : method.getThrowsList().getReferencedTypes()) {
            final PsiClass exception = ref.resolve();
            if (exception != null && throwsSet.add(exception)) {
              result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception), TailType.HUMBLE_SPACE_BEFORE_WORD));
            }
          }
        }

      }
    });

    final Key<PsiTryStatement> tryKey = Key.create("try");
    extend(CompletionType.SMART, psiElement().insideStarting(
      psiElement(PsiTypeElement.class).withParent(
        psiElement(PsiCatchSection.class).withParent(
          psiElement(PsiTryStatement.class).save(tryKey)))), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
        final PsiCodeBlock tryBlock = context.get(tryKey).getTryBlock();
        if (tryBlock == null) return;

        for (final PsiClassType type : ExceptionUtil.getThrownExceptions(tryBlock.getStatements())) {
          result.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock).setInsertHandler(new DefaultInsertHandler()), TailType.HUMBLE_SPACE_BEFORE_WORD));
        }
      }
    });

    extend(CompletionType.SMART, IN_TYPE_ARGS, new TypeArgumentCompletionProvider(true, null));


    extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE));

    extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.BREAK, PsiKeyword.CONTINUE), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull CompletionParameters parameters,
                                    ProcessingContext context,
                                    @NotNull CompletionResultSet result) {
        PsiReference ref = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
        if (ref instanceof PsiLabelReference) {
          JavaCompletionContributor.processLabelReference(result, (PsiLabelReference)ref);
        }
      }
    });

    extend(CompletionType.SMART, LAMBDA, new LambdaCompletionProvider());
    extend(CompletionType.SMART, METHOD_REFERENCE, new MethodReferenceCompletionProvider());
  }

  private static void addExpectedTypeMembers(CompletionParameters params,
                                             THashSet<ExpectedTypeInfo> mergedInfos,
                                             boolean quick,
                                             Consumer<LookupElement> consumer) {
    PsiElement position = params.getPosition();
    if (!JavaCompletionData.AFTER_DOT.accepts(position)) {
      for (ExpectedTypeInfo info : mergedInfos) {
        new JavaMembersGetter(info.getType(), params).addMembers(!quick, consumer);
        if (!info.getDefaultType().equals(info.getType())) {
          new JavaMembersGetter(info.getDefaultType(), params).addMembers(!quick, consumer);
        }
      }
    }
  }

  @Override
  public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
    super.fillCompletionVariants(parameters, JavaCompletionSorting.addJavaSorting(parameters, result));
  }

  public static SmartCompletionDecorator decorate(LookupElement lookupElement, Collection<ExpectedTypeInfo> infos) {
    LookupItem item = lookupElement.as(LookupItem.CLASS_CONDITION_KEY);
    if (item != null && item.getInsertHandler() == null) {
      item.setInsertHandler(DefaultInsertHandler.NO_TAIL_HANDLER);
    }

    return new SmartCompletionDecorator(lookupElement, infos);
  }

  private static LookupElement createInstanceofLookupElement(PsiClass psiClass, Set<PsiClass> toWildcardInheritors) {
    final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
    if (typeParameters.length > 0) {
      for (final PsiClass parameterizedType : toWildcardInheritors) {
        if (psiClass.isInheritor(parameterizedType, true)) {
          PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
          final PsiWildcardType wildcard = PsiWildcardType.createUnbounded(psiClass.getManager());
          for (final PsiTypeParameter typeParameter : typeParameters) {
            substitutor = substitutor.put(typeParameter, wildcard);
          }
          final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject());
          return PsiTypeLookupItem.createLookupItem(factory.createType(psiClass, substitutor), psiClass);
        }
      }
    }


    return new JavaPsiClassReferenceElement(psiClass);
  }


  @NotNull
  public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) {
    return getExpectedTypes(parameters, parameters.getCompletionType() == CompletionType.SMART);
  }

  @NotNull
  public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters, boolean voidable) {
    final PsiElement position = parameters.getPosition();
    if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) {
      final PsiElementFactory factory = JavaPsiFacade.getInstance(position.getProject()).getElementFactory();
      final PsiClassType classType = factory
          .createTypeByFQClassName(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, position.getResolveScope());
      final List<ExpectedTypeInfo> result = new SmartList<ExpectedTypeInfo>();
      result.add(new ExpectedTypeInfoImpl(classType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, classType, TailType.SEMICOLON, null, ExpectedTypeInfoImpl.NULL));
      final PsiMethod method = PsiTreeUtil.getContextOfType(position, PsiMethod.class, true);
      if (method != null) {
        for (final PsiClassType type : method.getThrowsList().getReferencedTypes()) {
          result.add(new ExpectedTypeInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.SEMICOLON, null, ExpectedTypeInfoImpl.NULL));
        }
      }
      return result.toArray(new ExpectedTypeInfo[result.size()]);
    }

    PsiExpression expression = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true);
    if (expression == null) return ExpectedTypeInfo.EMPTY_ARRAY;

    return ExpectedTypesProvider.getExpectedTypes(expression, true, voidable, false);
  }

  static Set<LookupElement> completeReference(final PsiElement element,
                                              PsiReference reference,
                                              final ElementFilter filter,
                                              final boolean acceptClasses,
                                              final boolean acceptMembers,
                                              CompletionParameters parameters, final PrefixMatcher matcher) {
    if (reference instanceof PsiMultiReference) {
      reference = ContainerUtil.findInstance(((PsiMultiReference) reference).getReferences(), PsiJavaReference.class);
    }

    if (reference instanceof PsiJavaReference) {
      final PsiJavaReference javaReference = (PsiJavaReference)reference;

      ElementFilter checkClass = new ElementFilter() {
        @Override
        public boolean isAcceptable(Object element, PsiElement context) {
          return filter.isAcceptable(element, context);
        }

        @Override
        public boolean isClassAcceptable(Class hintClass) {
          if (ReflectionUtil.isAssignable(PsiClass.class, hintClass)) {
            return acceptClasses;
          }

          if (ReflectionUtil.isAssignable(PsiVariable.class, hintClass) ||
              ReflectionUtil.isAssignable(PsiMethod.class, hintClass) ||
              ReflectionUtil.isAssignable(CandidateInfo.class, hintClass)) {
            return acceptMembers;
          }
          return false;
        }
      };
      JavaCompletionProcessor.Options options =
        JavaCompletionProcessor.Options.DEFAULT_OPTIONS.withFilterStaticAfterInstance(parameters.getInvocationCount() <= 1);
      return JavaCompletionUtil.processJavaReference(element, javaReference, checkClass, options, matcher, parameters);
    }

    return Collections.emptySet();
  }

  @Override
  public void beforeCompletion(@NotNull CompletionInitializationContext context) {
    if (context.getCompletionType() != CompletionType.SMART) {
      return;
    }

    if (!context.getEditor().getSelectionModel().hasSelection()) {
      final PsiFile file = context.getFile();
      PsiElement element = file.findElementAt(context.getStartOffset());
      if (element instanceof PsiIdentifier) {
        element = element.getParent();
        while (element instanceof PsiJavaCodeReferenceElement || element instanceof PsiCall ||
               element instanceof PsiThisExpression || element instanceof PsiSuperExpression ||
               element instanceof PsiTypeElement ||
               element instanceof PsiClassObjectAccessExpression) {
          int newEnd = element.getTextRange().getEndOffset();
          if (element instanceof PsiMethodCallExpression) {
            newEnd = ((PsiMethodCallExpression)element).getMethodExpression().getTextRange().getEndOffset();
          }
          else if (element instanceof PsiNewExpression) {
            final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)element).getClassReference();
            if (classReference != null) {
              newEnd = classReference.getTextRange().getEndOffset();
            }
          }
          context.setReplacementOffset(newEnd);
          element = element.getParent();
        }
      }
    }

    PsiElement lastElement = context.getFile().findElementAt(context.getStartOffset() - 1);
    if (lastElement != null && lastElement.getText().equals("(")) {
      final PsiElement parent = lastElement.getParent();
      if (parent instanceof PsiTypeCastExpression) {
        context.setDummyIdentifier("");
        return;
      }
      if (parent instanceof PsiParenthesizedExpression) {
        context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED + ")" + CompletionUtil.DUMMY_IDENTIFIER_TRIMMED + " "); // to handle type cast
        return;
      }
    }
    context.setDummyIdentifier(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED);
  }
}
