package fr.adrienbrault.idea.symfony2plugin.translation.parser;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.php.lang.psi.elements.*;
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Daniel Espendiller <daniel@espendiller.net>
 */
public class TranslationPsiParser {

    private Project project;
    private TranslationStringMap translationStringMap;

    public TranslationPsiParser(Project project) {
        this.project = project;
        this.translationStringMap = new TranslationStringMap();
    }

    public TranslationStringMap parsePathMatcher(String path) {

        File file = new File(path);
        File[] files = file.listFiles();

        if(null == files) {
            return this.translationStringMap;
        }

        for (final File fileEntry : files) {
            if (!fileEntry.isDirectory()) {
                String fileName = fileEntry.getName();
                if(fileName.startsWith("catalogue") && fileName.endsWith("php")) {
                    this.parse(fileEntry);
                }
            }
        }

        return this.translationStringMap;
    }

    public void parse(File file) {

        VirtualFile virtualFile = VfsUtil.findFileByIoFile(file, true);
        if(virtualFile == null) {
            Symfony2ProjectComponent.getLogger().info("VfsUtil missing translation: " + file.getPath());
            return;
        }

        PsiFile psiFile = PsiManager.getInstance(this.project).findFile(virtualFile);
        if(psiFile == null) {
            Symfony2ProjectComponent.getLogger().info("PsiManager missing translation: " + file.getPath());
            return;
        }

        Symfony2ProjectComponent.getLogger().info("update translations: " + file.getPath());
        Symfony2InterfacesUtil symfony2InterfacesUtil = new Symfony2InterfacesUtil();

        Collection<NewExpression> messageCatalogues = PsiTreeUtil.collectElementsOfType(psiFile, NewExpression.class);
        for(NewExpression newExpression: messageCatalogues) {
            ClassReference classReference = newExpression.getClassReference();
            if(classReference != null) {
                PsiElement constructorMethod = classReference.resolve();
                if(constructorMethod instanceof Method) {
                    PhpClass phpClass = ((Method) constructorMethod).getContainingClass();
                    if(phpClass != null && symfony2InterfacesUtil.isInstanceOf(phpClass, "\\Symfony\\Component\\Translation\\MessageCatalogueInterface")) {
                        this.getTranslationMessages(newExpression);
                    }

                }

            }

        }

    }

    private void getTranslationMessages(NewExpression newExpression) {

        // first parameter hold our huge translation arrays
        PsiElement[] parameters = newExpression.getParameters();
        if(parameters.length < 2 || !(parameters[1] instanceof ArrayCreationExpression)) {
            return;
        }

        Collection<ArrayHashElement> domainArrays = PsiTreeUtil.getChildrenOfTypeAsList(parameters[1], ArrayHashElement.class);
        for(ArrayHashElement arrayHashElement: domainArrays) {
            PhpPsiElement arrayKey = arrayHashElement.getKey();
            if(arrayKey instanceof StringLiteralExpression) {
                String transDomain = ((StringLiteralExpression) arrayKey).getContents();
                this.translationStringMap.addDomain(transDomain);

                // parse translation keys
                PhpPsiElement arrayValue = arrayHashElement.getValue();
                if(arrayValue instanceof ArrayCreationExpression) {
                    getTransKeys(transDomain, (ArrayCreationExpression) arrayValue);
                }

            }

        }

    }

    private void getTransKeys(String domain, ArrayCreationExpression translationArray) {
        Collection<ArrayHashElement> test = PsiTreeUtil.getChildrenOfTypeAsList(translationArray, ArrayHashElement.class);
        for(ArrayHashElement arrayHashElement: test) {
            PhpPsiElement translationKey = arrayHashElement.getKey();
            if(translationKey instanceof StringLiteralExpression) {
                String transKey = ((StringLiteralExpression) translationKey).getContents();
                this.translationStringMap.addString(domain, transKey);
            }
        }

    }

}

@@ -103,16 +103,64 @@
 roject;%0A
+import com.intellij.openapi.util.io.StreamUtil;%0A
 import c
@@ -310,44 +310,8 @@
 le;%0A
-import com.intellij.psi.PsiManager;%0A
 impo
@@ -344,24 +344,80 @@
 siTreeUtil;%0A
+import com.jetbrains.php.lang.psi.PhpPsiElementFactory;%0A
 import com.j
@@ -590,82 +590,8 @@
 nt;%0A
-import org.jetbrains.annotations.Nullable;%0A%0Aimport java.io.BufferedReader;
 %0Aimp
@@ -612,35 +612,8 @@
 le;%0A
-import java.io.FileReader;%0A
 impo
@@ -668,72 +668,8 @@
 ion;
-%0Aimport java.util.regex.Matcher;%0Aimport java.util.regex.Pattern;
 %0A%0A/*
@@ -1900,208 +1900,258 @@
 File
- = PsiManager.getInstance(this.project).findFile(virtualFile);%0A        if(psiFile == null) %7B%0A            Symfony2ProjectComponent.getLogger().info(%22PsiManager missing translation: %22 + file.getPath());
+;%0A        try %7B%0A            psiFile = PhpPsiElementFactory.createPsiFileFromText(this.project, StreamUtil.readText(virtualFile.getInputStream(), %22UTF-8%22));%0A        %7D catch (IOException e) %7B%0A            return;%0A        %7D%0A%0A        if(psiFile == null) %7B
 %0A   

use custom psifle creation for translations because ignored files and non project files may not change its content #262