package fr.adrienbrault.idea.symfony2plugin.dic;

import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.MethodReference;
import com.jetbrains.php.lang.psi.elements.PhpNamedElement;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import com.jetbrains.php.lang.psi.resolve.types.PhpTypeProvider2;
import fr.adrienbrault.idea.symfony2plugin.Settings;
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import fr.adrienbrault.idea.symfony2plugin.util.service.ServiceXmlParserFactory;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Collections;

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

    @Override
    public char getKey() {
        return 'X';
    }

    @Nullable
    @Override
    public String getType(PsiElement e) {

        if (DumbService.getInstance(e.getProject()).isDumb() || !Settings.getInstance(e.getProject()).pluginEnabled || !Settings.getInstance(e.getProject()).symfonyContainerTypeProvider) {
            return null;
        }

        // container calls are only on "get" methods
        if(!(e instanceof MethodReference) || !PhpElementsUtil.isMethodWithFirstString(e, "get")) {
            return null;
        }

        String refSignature = ((MethodReference)e).getSignature();
        if(StringUtil.isEmpty(refSignature)) {
            return null;
        }

        // we need the param key on getBySignature(), since we are already in the resolved method there attach it to signature
        // param can have dotted values split with \
        PsiElement[] parameters = ((MethodReference)e).getParameters();
        if (parameters.length > 0) {
            PsiElement parameter = parameters[0];
            if ((parameter instanceof StringLiteralExpression)) {
                String param = ((StringLiteralExpression)parameter).getContents();
                if (StringUtil.isNotEmpty(param)) return "#X" + refSignature + "\\" + param;
            }
        }

        return null;
    }

    @Override
    public Collection<? extends PhpNamedElement> getBySignature(String expression, Project project) {

        // i think we dont need this, but doesnt hurt
        if(!expression.startsWith("#X")) {
            return Collections.emptySet();
        }

        // get back our original call
        String orignalSignaturCall = expression.substring(2, expression.lastIndexOf("\\"));
        String parameter = expression.substring(expression.lastIndexOf("\\") + 1);

        // search for called method
        PhpIndex phpIndex = PhpIndex.getInstance(project);
        Collection<? extends PhpNamedElement> phpNamedElementCollections = phpIndex.getBySignature(orignalSignaturCall, null, 0);
        if(phpNamedElementCollections.size() == 0) {
            return Collections.emptySet();
        }

        // get first matched item
        PhpNamedElement phpNamedElement = phpNamedElementCollections.iterator().next();
        if(!(phpNamedElement instanceof Method)) {
            return Collections.emptySet();
        }

        // finally search the classes
        if(new Symfony2InterfacesUtil().isContainerGetCall((Method) phpNamedElement)) {
            ServiceMap serviceMap = ServiceXmlParserFactory.getInstance(project, XmlServiceParser.class).getServiceMap();
            String serviceClass = serviceMap.getMap().get(parameter);
            if(serviceClass != null) {
                return PhpIndex.getInstance(project).getAnyByFQN(serviceClass);
            }
        }

        return Collections.emptySet();
    }

}

@@ -988,16 +988,71 @@
 il.com%3E%0A
+ * @author Daniel Espendiller %3Cdaniel@espendiller.net%3E%0A
  */%0Apubl
@@ -1116,24 +1116,68 @@
 rovider2 %7B%0A%0A
+    final static char TRIM_KEY = '%5Cu0180';%0A%0A
     @Overrid
@@ -1221,17 +1221,22 @@
 return '
-X
+%5Cu0150
 ';%0A    %7D
@@ -2158,11 +2158,12 @@
 gth 
-%3E 0
+== 1
 ) %7B%0A
@@ -2421,15 +2421,8 @@
 turn
- %22#X%22 +
  ref
@@ -2433,20 +2433,24 @@
 ature + 
-%22%5C%5C%22
+TRIM_KEY
  + param
@@ -2625,159 +2625,8 @@
  %7B%0A%0A
-        // i think we dont need this, but doesnt hurt%0A        if(!expression.startsWith(%22#X%22)) %7B%0A            return Collections.emptySet();%0A        %7D%0A%0A
     
@@ -2674,24 +2674,25 @@
  String orig
+i
 nalSignaturC
@@ -2690,20 +2690,17 @@
 Signatur
-Call
+e
  = expre
@@ -2715,17 +2715,17 @@
 bstring(
-2
+0
 , expres
@@ -2741,20 +2741,24 @@
 IndexOf(
-%22%5C%5C%22
+TRIM_KEY
 ));%0A    
@@ -2828,12 +2828,16 @@
 xOf(
-%22%5C%5C%22
+TRIM_KEY
 ) + 
@@ -3039,16 +3039,17 @@
 ure(orig
+i
 nalSigna
@@ -3051,20 +3051,17 @@
 Signatur
-Call
+e
 , null, 

use unicode chars on signature and remove duplicate prefix