package com.siberika.idea.pascal.lang.parser;
import com.intellij.psi.PsiElement;
import com.siberika.idea.pascal.lang.psi.PasRefNamedIdent;
import com.siberika.idea.pascal.lang.psi.PasSubIdent;
import com.siberika.idea.pascal.lang.psi.PascalQualifiedIdent;
import com.siberika.idea.pascal.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
/**
* Author: George Bakhtadze
* Date: 12/08/2013
*/
public class NamespaceRec {
private final String[] levels;
private final PsiElement parentIdent;
private final int target;
private int current;
private static final String[] EMPTY_LEVELS = {};
private boolean nested = false;
private boolean ignoreVisibility = false;
// Levels should be w/o "&"
private NamespaceRec(@NotNull String[] levels, @NotNull PsiElement parentIdent, int target) {
this.levels = levels;
this.parentIdent = parentIdent;
this.target = target;
this.current = 0;
}
private NamespaceRec(@NotNull PsiElement context) {
this(EMPTY_LEVELS, context, 0);
}
private NamespaceRec(@NotNull PasSubIdent subIdent) {
this(getParent(subIdent), subIdent);
}
private NamespaceRec(@NotNull PasRefNamedIdent element) {
this(new String[] {!element.getName().startsWith("&") ? element.getName() : element.getName().substring(1)},
element.getParent() != null ? element.getParent() : element, 0);
}
/**
* Creates instance from qualified ident with specified target subident
*/
private NamespaceRec(@NotNull PascalQualifiedIdent qualifiedIdent, @Nullable PasSubIdent targetIdent) {
assert (targetIdent == null) || (targetIdent.getParent() == qualifiedIdent);
int targetInd = -1;
List<PasSubIdent> idents = qualifiedIdent.getSubIdentList();
levels = new String[idents.size()];
parentIdent = qualifiedIdent;
for (int i = 0; i < idents.size(); i++) {
if (idents.get(i) == targetIdent) {
targetInd = i;
}
levels[i] = idents.get(i).getName();//.replace(PasField.DUMMY_IDENTIFIER, ""));
}
if (-1 == targetInd) {
targetInd = levels.length - 1;
}
target = targetInd;
current = 0;
}
private static PascalQualifiedIdent getParent(PasSubIdent subIdent) {
return subIdent.getParent() instanceof PascalQualifiedIdent ? (PascalQualifiedIdent) subIdent.getParent() : null;
}
/*public PascalNamedElement getCurrent() {
return levels.get(current);
}*/
public void next() {
current++;
}
public void prev() {
current--;
}
public boolean isEmpty() {
return levels.length == 0;
}
public boolean isFirst() {
return !nested && (current == 0);
}
public int getRestLevels() {
return target - current;
}
public boolean isTarget() {
return current == target;
}
public boolean isBeforeTarget() {
return current < target;
}
public boolean isComplete() {
return current > target;
}
@NotNull
public PsiElement getParentIdent() {
return parentIdent;
}
@NotNull
public static NamespaceRec fromElement(@NotNull PsiElement element) {
if (element instanceof PasSubIdent) {
return new NamespaceRec((PascalQualifiedIdent) element.getParent(), (PasSubIdent) element);
} else if (element instanceof PascalQualifiedIdent) {
return new NamespaceRec((PascalQualifiedIdent) element, null);
} else if (element instanceof PasRefNamedIdent) {
return new NamespaceRec((PasRefNamedIdent) element);
}
NamespaceRec namespace;
if (PsiUtil.isIdent(element)) {
namespace = new NamespaceRec((PasSubIdent) element);
} else {
namespace = new NamespaceRec(element);
}
return namespace;
}
public static NamespaceRec fromFQN(@NotNull PsiElement context, @NotNull String fqn) {
String[] lvls = fqn.split("\\.", 100);
for (int i = 0, lvlsLength = lvls.length; i < lvlsLength; i++) {
String lvl = lvls[i];
if (lvl.startsWith("&")) {
lvls[i] = lvl.substring(1);
}
}
/*if ((lvls.length > 0) && (lvls[lvls.length - 1].endsWith(PasField.DUMMY_IDENTIFIER))) {
lvls[lvls.length - 1] = lvls[lvls.length - 1].replace(PasField.DUMMY_IDENTIFIER, "");
}*/
return new NamespaceRec(lvls, context, lvls.length-1);
}
public String getCurrentName() {
return current < levels.length ? levels[current] : null;
}
public String getLastName() {
return levels[levels.length-1];
}
public void clearTarget() {
if ((target >= 0) && (levels.length > target)) {
levels[target] = "";
}
}
public void setNested(boolean nested) {
this.nested = nested;
}
public boolean isIgnoreVisibility() {
return ignoreVisibility;
}
public void setIgnoreVisibility(boolean ignoreVisibility) {
this.ignoreVisibility = ignoreVisibility;
}
public boolean advance(String fqn) {
String[] lvls = fqn.split("\\.");
int i = current;
while (((i - current) < lvls.length) && (current + i < levels.length)
&& (lvls[i - current].equalsIgnoreCase(levels[i]))) {
i++;
}
if ((i - current) >= lvls.length) {
current = i;
return true;
}
return false;
}
@Override
public String toString() {
return String.format("%s (%d/%d) %s for: %s", Arrays.toString(levels), current, target, nested ? "nested" : "", parentIdent);
}
}