package pers.fw.tplugin.router;

import pers.fw.tplugin.beans.ArrayKeyVisitor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.VoidDataExternalizer;
import com.jetbrains.php.lang.PhpFileType;
import com.jetbrains.php.lang.psi.PhpFile;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;

import java.util.Map;


public class RouteValStubIndex extends FileBasedIndexExtension<String, Void> {

    public static final ID<String, Void> KEY = ID.create("fw.router.index");
    private final KeyDescriptor<String> myKeyDescriptor = new EnumeratorStringDescriptor();

    @NotNull
    @Override
    public ID<String, Void> getName() {
        return KEY;
    }

    //收集数据 索引进程, 数据文件被修改不会立即触发该方法, 只有当动作(例如代码补全)发生才会触发该方法
    @NotNull
    @Override
    public DataIndexer<String, Void, FileContent> getIndexer() {
        return new DataIndexer<String, Void, FileContent>() {
            @NotNull
            @Override
            public Map<String, Void> map(@NotNull FileContent fileContent) {   //fileContent, 被修改的文件,controller文件
                final Map<String, Void> map = new THashMap<>(); //创建结果容器
                PsiFile psiFile = fileContent.getPsiFile();     //获取Psi
                if (!(psiFile instanceof PhpFile)) {    //过滤非php文件
                    return map;
                }
                //匹配文件
                RouteUtil.ControllerFileMatchResult controllerFileMatchResult = RouteUtil.matchControllerFile(fileContent.getProject(), fileContent.getFile());
                if (controllerFileMatchResult.matches()) {    //是controller文件
                    String keyPrefix = controllerFileMatchResult.getKeyPrefix();
                    if (keyPrefix != null)
                        map.put(keyPrefix, null);
                    psiFile.acceptChildren(new PhpControllerVisitor(keyPrefix, new ArrayKeyVisitor() {
                        @Override
                        public void visit(String key, PsiElement psiKey, boolean isRootElement) {
                            map.put(key, null);
                        }
                    }));
                }
                return map;
            }
        };
    }

    @NotNull
    @Override
    public KeyDescriptor<String> getKeyDescriptor() {
        return myKeyDescriptor;
    }

    @NotNull
    @Override
    public DataExternalizer<Void> getValueExternalizer() {
        return VoidDataExternalizer.INSTANCE;
    }

    @Override
    public int getVersion() {
        return 1;
    }

    @NotNull
    @Override
    public FileBasedIndex.InputFilter getInputFilter() {
        return file -> file.getFileType() == PhpFileType.INSTANCE;
    }

    @Override
    public boolean dependsOnFileContent() {
        return true;
    }
}