package org.intellij.ibatis.provider;

import com.intellij.codeInsight.lookup.LookupValueFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider;
import com.intellij.psi.search.GlobalSearchScope;
import org.intellij.ibatis.IbatisManager;
import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
 * class reference provider  for ibatis, including internal shortcuts and typealias
 */
public class IbatisClassShortcutsReferenceProvider extends WrappedReferenceProvider {
    private static Map<String, String> classShortcuts = new HashMap<String, String>();

    static {
        classShortcuts.put("boolean", "java.lang.Boolean");
        classShortcuts.put("byte", "java.lang.Byte");
        classShortcuts.put("short", "java.lang.Short");
        classShortcuts.put("int", "java.lang.Integer");
        classShortcuts.put("long", "java.lang.Long");
        classShortcuts.put("float", "java.lang.Float");
        classShortcuts.put("double", "java.lang.Double");
        classShortcuts.put("string", "java.lang.String");
        classShortcuts.put("date", "java.util.Date");
        classShortcuts.put("decimal", "java.math.BigDecimal");
        classShortcuts.put("map", "java.util.Map");
    }

    public IbatisClassShortcutsReferenceProvider() {
        super(new JavaClassReferenceProvider());
    }

    private static Map<String, PsiClass> getTypeAlias(PsiElement psiElement) {
        IbatisManager manager = IbatisManager.getInstance();
        return manager.getAllTypeAlias(psiElement);
    }

    @NotNull public PsiReference[] getReferencesByElement(PsiElement psiElement) {
        PsiReference[] references = myProvider.getReferencesByElement(psiElement);
        if (references.length < 1) return references;
        return new PsiReference[]{new WrappedPsiReference(references[references.length - 1]) {
            public PsiElement resolve() {
                String className = getCanonicalText();
                if (classShortcuts.containsKey(className) || getTypeAlias(getElement()).containsKey(className)) {
                    return getPsiClass(getElement(), className);
                }
                return super.resolve();
            }

            public Object[] getVariants() {
                List<Object> classNames = Arrays.asList(super.getVariants());
                Set<String> shortcuts = classShortcuts.keySet();
                Set<String> typeAlias = getTypeAlias(getElement()).keySet();
                List<Object> variants = new ArrayList<Object>();
                variants.addAll(classNames);
                for (String shortcut : shortcuts) {
                    variants.add(LookupValueFactory.createLookupValue(shortcut, IconLoader.findIcon("/icons/internal_class.png")));
                }
                for (String alias : typeAlias) {
                    variants.add(LookupValueFactory.createLookupValue(alias, IconLoader.findIcon("/icons/typealias.png")));
                }
                return variants.toArray();
            }

            public boolean isSoft() {
                return false;
            }
        }};
    }

    /**
     * find PsiClass according to class full name
     *
     * @param project   project object
     * @param className any name of shortcut, type alias or java class
     * @return PsiClass object
     */
    public static PsiClass getPsiClass(PsiElement psiElement, String className) {
        Project project = psiElement.getProject();
        PsiManager psiManager = PsiManager.getInstance(project);
        //short cut
        if (classShortcuts.containsKey(className)) {
            return psiManager.findClass(classShortcuts.get(className), GlobalSearchScope.allScope(project));
        }
        //type alias
        Map<String, PsiClass> typeAlias = getTypeAlias(psiElement);
        if (typeAlias.containsKey(className)) {
            return typeAlias.get(className);
        }
        return psiManager.findClass(className, GlobalSearchScope.allScope(project));
    }
}

@@ -522,24 +522,74 @@
 isManager;%0D%0A
+import org.intellij.ibatis.util.IbatisConstants;%0D%0A
 import org.j
@@ -3082,55 +3082,37 @@
 t, I
-conLoader.findIcon(%22/icons/internal_class.png%22)
+batisConstants.INTERNAL_CLASS
 ));%0D
@@ -3263,50 +3263,33 @@
 s, I
-conLoader.findIcon(%22/icons/typealias.png%22)
+batisConstants.TYPE_ALIAS
 ));%0D

change icon found to constant