package org.jetbrains.plugins.clojure.psi;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.PsiComment;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.extapi.psi.StubBasedPsiElementBase;
import com.intellij.lang.ASTNode;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.clojure.psi.api.ClQuotedForm;
import org.jetbrains.plugins.clojure.psi.api.symbols.ClSymbol;
import java.util.List;
/**
* @author ilyas
*/
public abstract class ClojureBaseElementImpl <T extends StubElement> extends StubBasedPsiElementBase<T> implements ClojurePsiElement {
protected boolean isWrongElement(PsiElement element) {
return element == null ||
(element instanceof LeafPsiElement || element instanceof PsiWhiteSpace || element instanceof PsiComment);
}
public PsiElement getFirstNonLeafElement() {
PsiElement first = getFirstChild();
while (first != null && isWrongElement(first)) {
first = first.getNextSibling();
}
return first;
}
public PsiElement getNonLeafElement(int k) {
final List<PsiElement> elements = ContainerUtil.filter(getChildren(), new Condition<PsiElement>() {
public boolean value(PsiElement psiElement) {
return !isWrongElement(psiElement);
}
});
if (k - 1 >= elements.size()) return null;
return elements.get(k-1);
}
public PsiElement getLastNonLeafElement() {
PsiElement lastChild = getLastChild();
while (lastChild != null && isWrongElement(lastChild)) {
lastChild = lastChild.getPrevSibling();
}
return lastChild;
}
public <T> T findFirstChildByClass(Class<T> aClass) {
PsiElement element = getFirstChild();
while (element != null && !aClass.isInstance(element)) {
element = element.getNextSibling();
}
return (T)element;
}
public ClojureBaseElementImpl(T stub, @NotNull IStubElementType nodeType) {
super(stub, nodeType);
}
public ClojureBaseElementImpl(ASTNode node) {
super(node);
}
protected void commitDocument() {
final Project project = getProject();
final Document document = PsiDocumentManager.getInstance(project).getDocument(getContainingFile());
if (document != null) {
PsiDocumentManager.getInstance(project).commitDocument(document);
}
}
public ClSymbol[] getAllSymbols() {
return findChildrenByClass(ClSymbol.class);
}
public ClSymbol[] getAllQuotedSymbols() {
final ClQuotedForm[] quoteds = findChildrenByClass(ClQuotedForm.class);
final List<ClQuotedForm> quotedSymbols = ContainerUtil.filter(quoteds, new Condition<ClQuotedForm>() {
public boolean value(ClQuotedForm clQuotedForm) {
final ClojurePsiElement element = clQuotedForm.getQuotedElement();
return element instanceof ClSymbol;
}
});
return ContainerUtil.map(quotedSymbols, new Function<ClQuotedForm, Object>() {
public Object fun(ClQuotedForm clQuotedForm) {
return ((ClSymbol) clQuotedForm.getQuotedElement());
}
}).toArray(new ClSymbol[0]);
}
}