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

import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.OffsetMap;
import com.intellij.codeInsight.completion.PrioritizedLookupElement;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.template.TemplateLookupSelectionHandler;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;

import java.util.List;

/**
* @author peter
*/
class TemplateExpressionLookupElement extends LookupElementDecorator<LookupElement> {
  private final TemplateState myState;

  public TemplateExpressionLookupElement(final TemplateState state, LookupElement element, int index) {
    super(PrioritizedLookupElement.withPriority(element, Integer.MAX_VALUE - 10 - index));
    myState = state;
  }

  private static InsertionContext createInsertionContext(LookupElement item,
                                                         PsiFile psiFile,
                                                         List<? extends LookupElement> elements,
                                                         Editor editor, final char completionChar) {
    final OffsetMap offsetMap = new OffsetMap(editor.getDocument());
    final InsertionContext context = new InsertionContext(offsetMap, completionChar, elements.toArray(new LookupElement[elements.size()]), psiFile, editor, false);
    context.setTailOffset(editor.getCaretModel().getOffset());
    offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, context.getTailOffset() - item.getLookupString().length());
    offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, context.getTailOffset());
    offsetMap.addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, context.getTailOffset());
    return context;
  }

  void handleTemplateInsert(List<? extends LookupElement> elements, final char completionChar) {
    final InsertionContext context = createInsertionContext(this, myState.getPsiFile(), elements, myState.getEditor(), completionChar);
    WriteAction.run(() -> doHandleInsert(context));
    Disposer.dispose(context.getOffsetMap());

    if (handleCompletionChar(context) && !myState.isFinished()) {
      myState.calcResults(true);
      myState.considerNextTabOnLookupItemSelected(getDelegate());
    }
  }

  @Override
  public void handleInsert(final InsertionContext context) {
    doHandleInsert(context);
    handleCompletionChar(context);
  }

  private void doHandleInsert(InsertionContext context) {
    LookupElement item = getDelegate();
    PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();

    TextRange range = myState.getCurrentVariableRange();
    final TemplateLookupSelectionHandler handler = item.getUserData(TemplateLookupSelectionHandler.KEY_IN_LOOKUP_ITEM);
    if (handler != null && range != null) {
      handler.itemSelected(item, context.getFile(), context.getDocument(), range.getStartOffset(), range.getEndOffset());
    }
    else {
      super.handleInsert(context);
    }
  }

  private static boolean handleCompletionChar(InsertionContext context) {
    if (context.getCompletionChar() == '.') {
      WriteAction.run(() -> EditorModificationUtil.insertStringAtCaret(context.getEditor(), "."));
      AutoPopupController.getInstance(context.getProject()).autoPopupMemberLookup(context.getEditor(), null);
      return false;
    }
    return true;
  }
}
