package com.intellij.plugin.buck.format;

import com.intellij.plugin.buck.lang.psi.*;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Comparator;

/**
 * A utility class for sorting buck dependencies alphabetically
 */
public class DependenciesOptimizer {

  private static String DEPENDENCIES_KEYWORD = "deps";

  public static void optimzeDeps(@NotNull PsiFile file) {
    final PropertyVisitor visitor = new PropertyVisitor();
    file.accept(new BuckVisitor() {
      @Override
      public void visitElement(PsiElement node) {
        node.acceptChildren(this);
        node.accept(visitor);
      }
    });

    // Commit modifications
    final PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject());
    manager.doPostponedOperationsAndUnblockDocument(manager.getDocument(file));
  }

  private static class PropertyVisitor extends BuckVisitor {
    @Override
    public void visitProperty(@NotNull BuckProperty property) {
      BuckPropertyLvalue lValue = property.getPropertyLvalue();
      if (lValue == null || !lValue.getText().equals(DEPENDENCIES_KEYWORD)) {
        return;
      }
      BuckValueArray array = property.getValue().getValueArray();
      if (array == null) {
        return;
      }

      BuckArrayElements arrayElements = array.getArrayElements();
      PsiElement[] arrayValues = arrayElements.getChildren();
      Arrays.sort(arrayValues, new Comparator<PsiElement>() {
            @Override
            public int compare(PsiElement e1, PsiElement e2) {
              return e1.getText().compareTo(e2.getText());
            }
          }
      );
      PsiElement[] oldValues = new PsiElement[arrayValues.length];
      for (int i = 0; i < arrayValues.length; ++i) {
        oldValues[i] = arrayValues[i].copy();
      }

      for (int i = 0; i < arrayValues.length; ++i) {
        arrayElements.getChildren()[i].replace(oldValues[i]);
      }
    }
  }
}

@@ -1654,24 +1654,331 @@
 ement e2) %7B%0A
+              // 'deps' should be sorted with local referenes ':' preceding any cross-repo references '@'%0A              // e.g :inner, //world:empty, //world/asia:jp, //world/eruope:uk, @mars, @moon%0A              // the ascii code '!'(33), ':'(58), '/'(47), '@'(64). Replace ':' by '!' make the rule works.%0A
             
@@ -1999,16 +1999,34 @@
 tText().
+replace(':', '!').
 compareT
@@ -2039,16 +2039,34 @@
 etText()
+.replace(':', '!')
 );%0A     

modify buck dependency sort rule