package fr.adrienbrault.idea.symfony2plugin.dic;

import com.intellij.openapi.project.DumbService;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.lang.parser.PhpElementTypes;
import com.jetbrains.php.lang.psi.elements.MethodReference;
import com.jetbrains.php.lang.psi.resolve.types.PhpType;
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider;
import fr.adrienbrault.idea.symfony2plugin.Symfony2CachedInterfacesUtil;
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import org.jetbrains.annotations.Nullable;

/**
 * @author Adrien Brault <adrien.brault@gmail.com>
 */
public class SymfonyContainerTypeProvider implements PhpTypeProvider {

    private Symfony2CachedInterfacesUtil cachedInterfacesUtil;

    private int depth = 0;

    @Nullable
    @Override
    public PhpType getType(PsiElement e) {
        if (DumbService.getInstance(e.getProject()).isDumb()) {
            return null;
        }

        // filter out method calls without parameter
        // $this->get('service_name')
        if(!PlatformPatterns.psiElement(PhpElementTypes.METHOD_REFERENCE).withChild(
                PlatformPatterns.psiElement(PhpElementTypes.PARAMETER_LIST).withFirstChild(
                        PlatformPatterns.psiElement(PhpElementTypes.STRING))).accepts(e)) {

            return null;
        }

        // container calls are only on "get" methods
        // cant we move it up to PlatformPatterns? withName condition dont looks working
        String methodRefName = ((MethodReference) e).getName();
        if(methodRefName == null || !methodRefName.equals("get")) {
            return null;
        }

        depth++;
        if (depth > 2) {
            // Try to avoid too much recursive things ...
            // Who would chain more than 2 ContainerInterface::get calls ? ie : $container->get('service_container')->get('service_container')->get('service_container')
            depth--;
            return null;
        }

        boolean shouldUnsetCachedInterfaceUtil = false;

        if (null == cachedInterfacesUtil) {
            cachedInterfacesUtil = new Symfony2CachedInterfacesUtil();
            shouldUnsetCachedInterfaceUtil = true;
        }

        boolean isContainerGetCall = cachedInterfacesUtil.isContainerGetCall(e);

        if (shouldUnsetCachedInterfaceUtil) {
            cachedInterfacesUtil = null;
        }

        if (!isContainerGetCall) {
            depth--;
            return null;
        }

        String serviceId = Symfony2InterfacesUtil.getFirstArgumentStringValue((MethodReference) e);
        if (null == serviceId) {
            depth--;
            return null;
        }

        Symfony2ProjectComponent symfony2ProjectComponent = e.getProject().getComponent(Symfony2ProjectComponent.class);
        ServiceMap serviceMap = symfony2ProjectComponent.getServicesMap();
        if (null == serviceMap) {
            depth--;
            return null;
        }
        String serviceClass = serviceMap.getMap().get(serviceId);

        depth--;

        if (null == serviceClass) {
            return null;
        }

        return new PhpType().add(serviceClass);
    }

}

@@ -863,36 +863,8 @@
 l;%0A%0A
-    private int depth = 0;%0A%0A
     
@@ -873,16 +873,16 @@
 ullable%0A
+
     @Ove
@@ -1741,334 +1741,8 @@
  %7D%0A%0A
-        depth++;%0A        if (depth %3E 2) %7B%0A            // Try to avoid too much recursive things ...%0A            // Who would chain more than 2 ContainerInterface::get calls ? ie : $container-%3Eget('service_container')-%3Eget('service_container')-%3Eget('service_container')%0A            depth--;%0A            return null;%0A        %7D%0A%0A
     
@@ -2186,37 +2186,16 @@
 Call) %7B%0A
-            depth--;%0A
         
@@ -2355,37 +2355,16 @@
 ceId) %7B%0A
-            depth--;%0A
         
@@ -2625,29 +2625,8 @@
 ) %7B%0A
-            depth--;%0A
     
@@ -2656,16 +2656,16 @@
       %7D%0A
+
         
@@ -2727,26 +2727,8 @@
 );%0A%0A
-        depth--;%0A%0A
     

Remove SymfonyContainerTypeProvider deep hack