package org.jetbrains.plugins.clojure.psi.impl.ns;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.clojure.psi.api.ClList;
import org.jetbrains.plugins.clojure.psi.api.ClListLike;
import org.jetbrains.plugins.clojure.psi.api.ns.ClNs;
import org.jetbrains.plugins.clojure.psi.api.symbols.ClSymbol;
import org.jetbrains.plugins.clojure.psi.impl.ImportOwner;
import org.jetbrains.plugins.clojure.psi.impl.list.ClListBaseImpl;
import org.jetbrains.plugins.clojure.psi.stubs.api.ClNsStub;
import org.jetbrains.plugins.clojure.psi.util.ClojureKeywords;
import org.jetbrains.plugins.clojure.psi.util.ClojurePsiFactory;
import org.jetbrains.plugins.clojure.psi.util.ClojurePsiUtil;
/**
* @author ilyas
*/
public class ClNsImpl extends ClListBaseImpl<ClNsStub> implements ClNs, StubBasedPsiElement<ClNsStub> {
public ClNsImpl(ClNsStub stub, @NotNull IStubElementType nodeType) {
super(stub, nodeType);
}
public ClNsImpl(ASTNode node) {
super(node);
}
@Override
public String toString() {
return "ClNs";
}
@Override
@Nullable
public String getName() {
ClNsStub stub = getStub();
if (stub != null) {
return stub.getName();
}
return getDefinedName();
}
/**
* @return Name of string symbol defined
*/
@Nullable
public ClSymbol getNameSymbol() {
PsiElement element = getSecondNonLeafElement();
while (element != null && !(element instanceof ClSymbol)) {
element = element.getNextSibling();
}
if (element != null) {
return (ClSymbol) element;
}
return null;
}
public String getDefinedName() {
ClSymbol sym = getNameSymbol();
if (sym != null) {
String name = sym.getText();
assert name != null;
return name;
}
return "";
}
public PsiElement setName(@NonNls String name) throws IncorrectOperationException {
//todo implement me
return this;
}
@Override
public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
return ImportOwner.processDeclarations(this, processor, place);
}
@Override
public int getTextOffset() {
ClNsStub stub = getStub();
if (stub != null) {
return stub.getTextOffset();
}
final ClSymbol symbol = getNameSymbol();
if (symbol != null) {
return symbol.getTextRange().getStartOffset();
}
return super.getTextOffset();
}
public ClList findImportClause(@Nullable final PsiElement place) {
final PsiElement element = ContainerUtil.find(getChildren(), new Condition<PsiElement>() {
public boolean value(PsiElement psiElement) {
return psiElement instanceof ClList &&
(place == null || ClojurePsiUtil.isStrictlyBefore(psiElement, place)) &&
ClojureKeywords.IMPORT.equals(((ClList) psiElement).getHeadText());
}
});
return (ClList) element;
}
@NotNull
public ClList findOrCreateImportClause(@Nullable PsiElement place) {
final ClList imports = findImportClause(place);
if (imports != null) return imports;
return addFreshImportClause();
}
public ClList findImportClause() {
return findImportClause(null);
}
@NotNull
public ClList findOrCreateImportClause() {
return findOrCreateImportClause(null);
}
public ClListLike addImportForClass(PsiElement place, PsiClass clazz) {
commitDocument();
final ClojurePsiFactory factory = ClojurePsiFactory.getInstance(getProject());
final ClList importClause = findOrCreateImportClause(place);
return factory.findOrCreateJavaImportForClass(clazz, importClause);
}
@NotNull
protected ClList addFreshImportClause() {
commitDocument();
final ClSymbol first = getFirstSymbol();
final ClSymbol nsSymbol = getNameSymbol();
final PsiElement preamble = findGenClassPreamble();
final PsiElement anchor = (preamble != null ? preamble :
nsSymbol != null ? nsSymbol : first);
assert first != null;
final ClojurePsiFactory factory = ClojurePsiFactory.getInstance(getProject());
final ClList list = factory.createListFromText(":import ");
return (ClList) addAfter(list, anchor);
}
protected PsiElement findGenClassPreamble() {
return ContainerUtil.find(getChildren(), new Condition<PsiElement>() {
public boolean value(PsiElement psiElement) {
return (psiElement instanceof ClList) &&
(ClojureKeywords.GEN_CLASS.equals(((ClList) psiElement).getHeadText()));
}
});
}
}