/*
 * Copyright 2017 Niklas Persson
 *
 * 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.equadon.intellij.mips.completion;

import com.equadon.intellij.mips.icons.MipsIcons;
import com.equadon.intellij.mips.lang.psi.MipsFile;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.util.ProcessingContext;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;

import mars.Globals;
import mars.assembler.Directives;
import mars.mips.instructions.Instruction;

import static com.intellij.patterns.PlatformPatterns.psiElement;

public class MipsCompletionContributor extends CompletionContributor {
  public MipsCompletionContributor() {
    extend(CompletionType.BASIC, psiElement().withParent(MipsFile.class), new CompletionProvider<CompletionParameters>() {
      @Override
      protected void addCompletions(@NotNull CompletionParameters params, ProcessingContext context, @NotNull CompletionResultSet result) {
        suggestDirectives(result);
        suggestInstructions(result);
      }
    });
  }

  private void suggestDirectives(CompletionResultSet result) {
    ArrayList directives = Directives.getDirectiveList();
    for (Object o : directives) {
      Directives directive = (Directives) o;
      result.addElement(LookupElementBuilder.create(directive.getName())
          .withTailText(" " + directive.getDescription(), true)
          .withTypeText("Directive", false)
          .withInsertHandler(new MipsInsertHandler())
          .withBoldness(true)
          .withIcon(MipsIcons.DIRECTIVE)
      );
    }
  }

  private void suggestInstructions(CompletionResultSet result) {
    for (Object i : Globals.instructionSet.getInstructionList()) {
      Instruction instruction = (Instruction) i;
      result.addElement(LookupElementBuilder.create(instruction.getName())
          .withTailText(" " + instruction.getDescription(), true)
          .withTypeText("Instruction")
          .withInsertHandler(new MipsInsertHandler())
          .withBoldness(true)
          .withIcon(MipsIcons.INSTRUCTION)
      );
    }
  }

  private class MipsInsertHandler implements InsertHandler<LookupElement> {
    @Override
    public void handleInsert(InsertionContext context, LookupElement element) {
      Editor editor = context.getEditor();
      Document document = editor.getDocument();

      int start = context.getStartOffset();
      int tail = context.getTailOffset();

      String text = document.getText().substring(start, context.getTailOffset());

      if (text.startsWith(".")) {
        document.replaceString(start, tail, text.substring(1));
      }
    }
  }
}

@@ -1491,16 +1491,80 @@
 rayList;
+%0Aimport java.util.regex.Matcher;%0Aimport java.util.regex.Pattern;
 %0A%0Aimport
@@ -1793,16 +1793,104 @@
 butor %7B%0A
+  private static final Pattern INSTRUCTION_ID = Pattern.compile(%22%5E(%5B%5E%5C%5Cd%5D+)%5C%5Cd%7B3%7D $%22);%0A%0A
   public
@@ -2879,24 +2879,39 @@
 t result) %7B%0A
+    int n = 1;%0A
     for (Obj
@@ -3014,16 +3014,91 @@
 ion) i;%0A
+      String name = String.format(%22%25s%2503d %22, instruction.getName(), n++);%0A%0A
       re
@@ -3141,37 +3141,20 @@
 .create(
-instruction.getN
+n
 ame
-()
 )%0A      
@@ -3328,32 +3328,95 @@
 hBoldness(true)%0A
+          .withPresentableText(instruction.getExampleFormat())%0A
           .withI
@@ -3924,24 +3924,24 @@
 ith(%22.%22)) %7B%0A
-
         docu
@@ -3992,16 +3992,177 @@
 ng(1));%0A
+      %7D else %7B%0A        Matcher m = INSTRUCTION_ID.matcher(text);%0A%0A        if (m.matches()) %7B%0A          document.replaceString(tail - 4, tail - 1, %22%22);%0A        %7D%0A
       %7D%0A

Add all variants of the same instruction.