package fr.adrienbrault.idea.symfony2plugin.routing.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import fr.adrienbrault.idea.symfony2plugin.codeInspection.InspectionUtil;
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper;
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.yaml.psi.YAMLFile;
import org.jetbrains.yaml.psi.YAMLKeyValue;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class ControllerMethodInspection extends LocalInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) {
if(!Symfony2ProjectComponent.isEnabled(holder.getProject())) {
return super.buildVisitor(holder, isOnTheFly);
}
return new PsiElementVisitor() {
@Override
public void visitFile(PsiFile psiFile) {
if(psiFile instanceof YAMLFile) {
visitYaml(holder, psiFile);
}
if(psiFile instanceof XmlFile) {
visitXml(holder, psiFile);
}
super.visitFile(psiFile);
}
};
}
private void visitYaml(final ProblemsHolder holder, PsiFile psiFile) {
psiFile.acceptChildren(new PsiRecursiveElementWalkingVisitor() {
@Override
public void visitElement(PsiElement element) {
if(YamlElementPatternHelper.getSingleLineScalarKey("_controller").accepts(element)) {
String text = PsiElementUtils.trimQuote(element.getText());
if(StringUtils.isNotBlank(text)) {
InspectionUtil.inspectController(element, text, holder, new YamlLazyRouteName(element));
}
}
super.visitElement(element);
}
});
}
private void visitXml(final ProblemsHolder holder, PsiFile psiFile) {
psiFile.acceptChildren(new PsiRecursiveElementWalkingVisitor() {
@Override
public void visitElement(PsiElement element) {
if(XmlHelper.getRouteDefaultWithKeyAttributePattern("_controller").accepts(element)) {
String text = PsiElementUtils.trimQuote(element.getText());
if(StringUtils.isNotBlank(text)) {
InspectionUtil.inspectController(element, text, holder, new XmlLazyRouteName(element));
}
}
super.visitElement(element);
}
});
}
public class YamlLazyRouteName implements InspectionUtil.LazyControllerNameResolve {
private final PsiElement psiElement;
public YamlLazyRouteName(PsiElement psiElement) {
this.psiElement = psiElement;
}
@Nullable
@Override
public String getRouteName() {
YAMLKeyValue defaultKeyValue = PsiTreeUtil.getParentOfType(this.psiElement.getParent(), YAMLKeyValue.class);
if(defaultKeyValue == null) {
return null;
}
YAMLKeyValue def = PsiTreeUtil.getParentOfType(defaultKeyValue, YAMLKeyValue.class);
if(def == null) {
return null;
}
return YamlHelper.getYamlKeyName(def);
}
}
public class XmlLazyRouteName implements InspectionUtil.LazyControllerNameResolve {
private final PsiElement psiElement;
public XmlLazyRouteName(PsiElement psiElement) {
this.psiElement = psiElement;
}
@Nullable
@Override
public String getRouteName() {
XmlTag defaultTag = PsiTreeUtil.getParentOfType(this.psiElement, XmlTag.class);
if(defaultTag != null) {
XmlTag routeTag = PsiTreeUtil.getParentOfType(defaultTag, XmlTag.class);
if(routeTag != null) {
XmlAttribute id = routeTag.getAttribute("id");
if(id != null) {
return id.getValue();
}
}
}
return null;
}
}
}