package de.espend.idea.android.utils;


import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import de.espend.idea.android.AndroidView;
import de.espend.idea.android.annotator.InflateViewAnnotator;
import icons.AndroidIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class AndroidViewUtil {
    
    private AndroidViewUtil() {
    }

    public static Icon getCoreIconWithExtends(AndroidView view, PsiClass psiClass) {

        Field[] declaredFields = AndroidIcons.Views.class.getDeclaredFields();

        // direct class
        if(view.getName().equals(psiClass.getQualifiedName())) {
            String viewName = view.getName();
            Icon icon = getCoreIconName(declaredFields, viewName);
            if(icon != null) {
                return icon;
            }
        }

        // extended
        for(PsiClassType classType : PsiClassImplUtil.getExtendsListTypes(psiClass)) {
            PsiClass resolve = classType.resolve();
            if(resolve != null) {
                String viewName = resolve.getQualifiedName();
                Icon icon = getCoreIconName(declaredFields, viewName);
                if(icon != null) {
                    return icon;
                }
            }
        }

        return null;
    }

    @Nullable
    private static Icon getCoreIconName(Field[] declaredFields, String viewName) {

        if(viewName.contains(".")) {
            viewName = viewName.substring(viewName.lastIndexOf(".") +1 );
            for(Field field: declaredFields) {
                if(field.getName().equalsIgnoreCase(viewName) && java.lang.reflect.Modifier.isStatic(field.getModifiers()) && field.getType() == Icon.class) {
                    try {
                        return (Icon) field.get(null);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return null;
    }

    @Nullable
    public static AndroidView getAndroidView(PsiMethodCallExpression psiMethodCallExpression) {

        PsiExpression[] psiExpressions = psiMethodCallExpression.getArgumentList().getExpressions();
        if(psiExpressions.length > 0) {
            String viewId = psiExpressions[0].getText();

            PsiMethod psiMethod = psiMethodCallExpression.resolveMethod();
            if(psiMethod != null && psiMethod.getName().equals("findViewById")) {

                // methodExpression direct catch!?
                PsiElement methodExpression = psiMethodCallExpression.getFirstChild();
                if(methodExpression instanceof PsiReferenceExpression) {
                    PsiExpression psiExpression = ((PsiReferenceExpression) methodExpression).getQualifierExpression();
                    if(psiExpression != null) {
                        PsiReference psiLocalVariableReference = psiExpression.getReference();
                        if(psiLocalVariableReference != null) {
                            PsiElement psiLocalVariable = psiLocalVariableReference.resolve();
                            if(psiLocalVariable instanceof PsiLocalVariable) {
                                InflateViewAnnotator.InflateContainer inflateContainer = InflateViewAnnotator.matchInflate((PsiLocalVariable) psiLocalVariable);
                                if(inflateContainer != null) {
                                    PsiFile psiFile = inflateContainer.getXmlFile();
                                    return AndroidUtils.getViewType(psiFile, viewId);
                                }
                            }
                        }
                    }
                }
            }
        }

        return  null;


    }

    public static List<PsiFile> findLayoutFilesInsideMethod(PsiMethod psiMethod) {
        final List<PsiFile> xmlFiles = new ArrayList<PsiFile>();

        PsiTreeUtil.processElements(psiMethod, new PsiElementProcessor() {

            @Override
            public boolean execute(@NotNull PsiElement element) {

                if (element instanceof PsiMethodCallExpression) {
                    PsiMethod psiMethodResolved = ((PsiMethodCallExpression) element).resolveMethod();
                    if (psiMethodResolved != null) {
                        String methodName = psiMethodResolved.getName();
                        // @TODO: implement instance check
                        if ("setContentView".equals(methodName)) {
                            PsiExpression[] expressions = ((PsiMethodCallExpression) element).getArgumentList().getExpressions();
                            if (expressions.length > 0 && expressions[0] instanceof PsiReferenceExpression) {
                                PsiFile xmlFile = AndroidUtils.findXmlResource((PsiReferenceExpression) expressions[0]);
                                if (xmlFile != null) {
                                    xmlFiles.add(xmlFile);
                                }
                            }

                        }

                    }

                }

                return true;
            }
        });


        return xmlFiles;
    }

    @NotNull
    public static Icon getViewIcon(Project project, AndroidView androidView) {
        JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
        PsiClass psiClass = psiFacade.findClass(androidView.getName(), GlobalSearchScope.allScope(project));
        if(psiClass == null) {
            return AndroidIcons.Views.View;
        }

        Icon icon = AndroidViewUtil.getCoreIconWithExtends(androidView, psiClass);

        return icon != null ? icon : AndroidIcons.Views.View;
    }

}