package com.chrisfolger.needsmoredojo.core.amd;

import com.chrisfolger.needsmoredojo.core.util.AMDUtil;
import com.chrisfolger.needsmoredojo.core.util.JSUtil;
import com.intellij.lang.javascript.psi.*;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;

import java.util.*;

public class ImportCreator
{
    public static final String[] dojoLibraries = new String[] { "dojo", "dijit", "dojox", "dgrid", "util"};

    private int getScore(String item)
    {
        Map<String, Integer> scores = new HashMap<String, Integer>();
        scores.put("dojo/", 5);
        scores.put("dijit/", 4);
        scores.put("dgrid/", 2);
        scores.put("dojox/", 1);

        for(String key : scores.keySet())
        {
            if(item.indexOf(key) != -1)
            {
                return scores.get(key);
            }
        }

        return 0;
    }

    public String[] getChoicesFromFiles(PsiFile[] filesArray, String[] dojoLibraries, String module)
    {
        List<String> choices = new ArrayList<String>();

        for(int i=0;i<filesArray.length;i++)
        {
            PsiFile file = filesArray[i];

            PsiDirectory directory = file.getContainingDirectory();
            String result = directory.toString();

            // parse dojo libraries only
            int firstIndex = Integer.MAX_VALUE;
            String firstLibrary = null;

            for(String library : dojoLibraries)
            {
                int index = result.indexOf(library);
                if(index > -1 && index < firstIndex)
                {
                    firstIndex = index;
                    firstLibrary = library;
                }
            }

            if(firstLibrary != null)
            {
                result = result.substring(result.indexOf(firstLibrary));
                result = result.replace('\\', '/') + '/' + file.getName().substring(0, file.getName().indexOf('.'));
                choices.add(result);
            }
        }

        Collections.sort(choices, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return getScore(o2) - getScore(o1);
            }
        });

        choices.add(module);
        return choices.toArray(new String[0]);
    }

    public String[] getPossibleDojoImports(PsiFile psiFile, String module)
    {
        PsiFile[] files = null;
        PsiFile[] filesWithUnderscore = null;

        try
        {
            files = FilenameIndex.getFilesByName(psiFile.getProject(), module + ".js", GlobalSearchScope.projectScope(psiFile.getProject()));
            // this will let us search for _TemplatedMixin and friends
            filesWithUnderscore = FilenameIndex.getFilesByName(psiFile.getProject(), "_" + module + ".js", GlobalSearchScope.projectScope(psiFile.getProject()));
        }
        catch(NullPointerException exc)
        {
            return new String[] { module };
        }

        Set<PsiFile> allFiles = new HashSet<PsiFile>();
        for(PsiFile file : files) allFiles.add(file);
        for(PsiFile file : filesWithUnderscore) allFiles.add(file);

        PsiFile[] filesArray = allFiles.toArray(new PsiFile[0]);

        return getChoicesFromFiles(filesArray, dojoLibraries, module);
    }

    protected void createImport(String module, JSArrayLiteralExpression imports, JSParameterList parameters)
    {
        if(imports.getChildren().length == 0)
        {
            Messages.showInfoMessage("Need at least one import already present", "Add new AMD import");
            return;
        }
        else
        {
            JSUtil.addStatementBeforeElement(imports, imports.getChildren()[0], String.format("'%s',", module), "\n");
            JSUtil.addStatementBeforeElement(parameters, parameters.getChildren()[0], AMDUtil.defineToParameter(module) + ",", " ");
        }
    }

    public void addImport(PsiFile file, final String module)
    {
        JSRecursiveElementVisitor visitor = new DeclareFinder().getDefineVisitor(new DeclareFinder.CompletionCallback() {
            @Override
            public void run(Object[] result) {
                JSCallExpression callExpression = (JSCallExpression) result[0];
                JSFunction function = (JSFunction) result[1];

                createImport(module, (JSArrayLiteralExpression) callExpression.getArguments()[0], function.getParameterList());
            }
        });

        file.acceptChildren(visitor);
    }
}

@@ -403,16 +403,65 @@
 chScope;
+%0Aimport com.intellij.psi.search.LocalSearchScope;
 %0A%0Aimport
@@ -1146,32 +1146,65 @@
 s, String module
+, String%5B%5D otherSourceDirectories
 )%0A    %7B%0A        
@@ -2677,21 +2677,938 @@
     
-try%0A        %7B
+String sourceRootToRemove = %22%22;%0A%0A        try%0A        %7B%0A            // first, try to get the directory that contains the dojo sources.%0A            PsiFile%5B%5D dojoSources = FilenameIndex.getFilesByName(psiFile.getProject(), %22dojo.js%22, GlobalSearchScope.projectScope(psiFile.getProject()));%0A            if(dojoSources.length %3E 0)%0A            %7B%0A                PsiFile dojoSourceModule = dojoSources%5B0%5D;%0A                for(int i=0;i%3CdojoSources.length;i++)%0A                %7B%0A                    if(dojoSources%5Bi%5D.getContainingDirectory().getName().contains(%22dojo%22))%0A                    %7B%0A                        dojoSourceModule = dojoSources%5Bi%5D;%0A                        break;%0A                    %7D%0A                %7D%0A%0A                PsiDirectory sourceDirectory = dojoSourceModule.getContainingDirectory().getParentDirectory();%0A                sourceRootToRemove = sourceDirectory.getVirtualFile().getCanonicalPath();%0A            %7D%0A
 %0A   
@@ -4403,24 +4403,30 @@
 ries, module
+, null
 );%0A    %7D%0A%0A  

test resolving modules from other locations