package de.espend.idea.php.annotation.reference;

import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocTag;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import de.espend.idea.php.annotation.AnnotationPropertyParameter;
import de.espend.idea.php.annotation.PhpAnnotationExtension;
import de.espend.idea.php.annotation.Settings;
import de.espend.idea.php.annotation.pattern.AnnotationPattern;
import de.espend.idea.php.annotation.reference.parameter.ReferencesByElementParameter;
import de.espend.idea.php.annotation.util.AnnotationUtil;
import de.espend.idea.php.annotation.util.PluginUtil;
import de.espend.idea.php.annotation.util.WorkaroundUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;

public class AnnotationPropertyValueReferenceContributor extends PsiReferenceContributor {

    @Override
    public void registerReferenceProviders(PsiReferenceRegistrar psiReferenceRegistrar) {
        if(WorkaroundUtil.isClassFieldName("com.jetbrains.php.lang.documentation.phpdoc.parser.PhpDocElementTypes", "phpDocAttributeList")) {
            psiReferenceRegistrar.registerReferenceProvider(AnnotationPattern.getDefaultPropertyValueString(), new PropertyValueDefaultReferences());
            psiReferenceRegistrar.registerReferenceProvider(AnnotationPattern.getPropertyValueString(), new PropertyValueReferences());
        }
    }

    private class PropertyValueDefaultReferences extends PsiReferenceProvider {

        @NotNull
        @Override
        public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {

            if(!PluginUtil.isEnabled(psiElement)) {
                return new PsiReference[0];
            }

            PhpClass phpClass = getValidAnnotationClass(psiElement);
            if(phpClass == null) {
                return new PsiReference[0];
            }

            AnnotationPropertyParameter annotationPropertyParameter = new AnnotationPropertyParameter(psiElement, phpClass, AnnotationPropertyParameter.Type.DEFAULT);
            return addPsiReferences(psiElement, processingContext, annotationPropertyParameter);

        }
    }

    private class PropertyValueReferences extends PsiReferenceProvider {

        @NotNull
        @Override
        public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {

            if(!PluginUtil.isEnabled(psiElement)) {
                return new PsiReference[0];
            }

            PhpClass phpClass = getValidAnnotationClass(psiElement);
            if(phpClass == null) {
                return new PsiReference[0];
            }

            AnnotationPropertyParameter annotationPropertyParameter = new AnnotationPropertyParameter(psiElement, phpClass, AnnotationPropertyParameter.Type.ARRAY);
            return addPsiReferences(psiElement, processingContext, annotationPropertyParameter);

        }
    }

    @Nullable
    private PhpClass getValidAnnotationClass(PsiElement psiElement) {
        PhpDocTag phpDocTag = PsiTreeUtil.getParentOfType(psiElement, PhpDocTag.class);
        if(phpDocTag == null) {
            return null;
        }

        return AnnotationUtil.getAnnotationReference(phpDocTag);
    }

    private PsiReference[] addPsiReferences(PsiElement psiElement, ProcessingContext processingContext, AnnotationPropertyParameter annotationPropertyParameter) {
        ArrayList<PsiReference> psiReferences = new ArrayList<PsiReference>();

        ReferencesByElementParameter referencesByElementParameter = new ReferencesByElementParameter(psiElement, processingContext);

        for(PhpAnnotationExtension phpAnnotationExtension : AnnotationUtil.getProvider()) {
            Collection<PsiReference> providerReferences = phpAnnotationExtension.getPropertyReferences(annotationPropertyParameter, referencesByElementParameter);
            if(providerReferences != null) {
                psiReferences.addAll(providerReferences);
            }
        }

        return psiReferences.toArray(new PsiReference[psiReferences.size()]);
    }

}

@@ -39,24 +39,71 @@
 reference;%0A%0A
+import com.intellij.patterns.PlatformPatterns;%0A
 import com.i
@@ -203,16 +203,91 @@
 ontext;%0A
+import com.jetbrains.php.lang.documentation.phpdoc.lexer.PhpDocTokenTypes;%0A
 import c
@@ -533,55 +533,8 @@
 on;%0A
-import de.espend.idea.php.annotation.Settings;%0A
 impo
@@ -781,21 +781,26 @@
 n.util.P
-lugin
+hpElements
 Util;%0Aim
@@ -839,26 +839,22 @@
 on.util.
-Workaround
+Plugin
 Util;%0Aim
@@ -1195,154 +1195,8 @@
 ) %7B%0A
-        if(WorkaroundUtil.isClassFieldName(%22com.jetbrains.php.lang.documentation.phpdoc.parser.PhpDocElementTypes%22, %22phpDocAttributeList%22)) %7B%0A    
     
@@ -1337,36 +1337,32 @@
 ces());%0A        
-    
 psiReferenceRegi
@@ -1469,26 +1469,16 @@
 ces());%0A
-        %7D%0A
     %7D%0A%0A 
@@ -2791,32 +2791,288 @@
 %0A            %7D%0A%0A
+            PsiElement propertyName = PhpElementsUtil.getPrevSiblingOfPatternMatch(psiElement, PlatformPatterns.psiElement(PhpDocTokenTypes.DOC_IDENTIFIER));%0A            if(propertyName == null) %7B%0A                return new PsiReference%5B0%5D;%0A            %7D%0A%0A
             Anno
@@ -3170,32 +3170,56 @@
 ement, phpClass,
+ propertyName.getText(),
  AnnotationPrope
@@ -3240,13 +3240,14 @@
 ype.
-ARRAY
+STRING
 );%0A 

remove phpstorm6 workaround and activate phpstorm7 reference property contributor