package com.github.sommeri.less4j.core.ast;
import java.util.ArrayList;
import java.util.List;
import com.github.sommeri.less4j.LessSource;
import com.github.sommeri.less4j.core.ast.annotations.NotAstProperty;
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
import com.github.sommeri.less4j.utils.PubliclyCloneable;
public abstract class ASTCssNode implements PubliclyCloneable {
private ASTCssNode parent;
private Visibility visibility = Visibility.DEFAULT;
private int visibilityBlocks = 0;
// I'm using underlying structure as identified in cycle detector. If it stops
// to be identifying,
// cycle detector must be modified. !
private HiddenTokenAwareTree underlyingStructure;
private List<Comment> openingComments = new ArrayList<Comment>();
private List<Comment> orphanComments = new ArrayList<Comment>();
private List<Comment> trailingComments = new ArrayList<Comment>();
public ASTCssNode(HiddenTokenAwareTree underlyingStructure) {
this.underlyingStructure = underlyingStructure;
if (underlyingStructure == null)
throw new IllegalArgumentException("Underlying can not be null. It is used for error reporting, so place there the closest token possible.");
}
@NotAstProperty
public Visibility getVisibility() {
return visibility;
}
@NotAstProperty
public void setVisibility(Visibility isVisible) {
this.visibility = isVisible;
}
@NotAstProperty
public int getVisibilityBlocks() {
return visibilityBlocks;
}
public boolean hasVisibilityBlock() {
return visibilityBlocks != 0;
}
@NotAstProperty
public void setVisibilityBlocks(int visibilityBlocks) {
this.visibilityBlocks = visibilityBlocks;
}
public void addVisibilityBlocks(int blocks) {
this.visibilityBlocks += blocks;
}
/**
* WARNING: it is up to the programmer to keep parent and childs getters and
* setters consistent. Members of this hierarchy are not responsible for that.
*/
@NotAstProperty
public abstract List<? extends ASTCssNode> getChilds();
/**
* WARNING: it is up to the programmer to keep parent and childs getters and
* setters consistent. Members of this hierarchy are not responsible for that.
*/
public ASTCssNode getParent() {
return parent;
}
public boolean hasParent() {
return getParent() != null;
}
/**
* WARNING: it is up to the programmer to keep parent and childs getters and
* setters consistent. Members of this hierarchy are not responsible for that.
*/
public void setParent(ASTCssNode parent) {
this.parent = parent;
}
public HiddenTokenAwareTree getUnderlyingStructure() {
return underlyingStructure;
}
public void setUnderlyingStructure(HiddenTokenAwareTree underlyingStructure) {
this.underlyingStructure = underlyingStructure;
}
@NotAstProperty
public List<Comment> getTrailingComments() {
return trailingComments;
}
public void setTrailingComments(List<Comment> trailingComments) {
this.trailingComments = trailingComments;
}
public void addTrailingComments(List<Comment> comments) {
this.trailingComments.addAll(comments);
}
public void addTrailingComment(Comment comment) {
this.trailingComments.add(comment);
}
@NotAstProperty
public List<Comment> getOpeningComments() {
return openingComments;
}
public void setOpeningComments(List<Comment> openingComments) {
this.openingComments = openingComments;
}
public void addOpeningComments(List<Comment> openingComments) {
this.openingComments.addAll(openingComments);
}
@NotAstProperty
public List<Comment> getOrphanComments() {
return orphanComments;
}
public void setOrphanComments(List<Comment> orphanComments) {
this.orphanComments = orphanComments;
}
public abstract ASTCssNodeType getType();
public boolean isFaulty() {
return false;
}
public LessSource getSource() {
return getUnderlyingStructure() == null ? null : getUnderlyingStructure().getSource();
}
public int getSourceLine() {
return getUnderlyingStructure() == null ? -1 : getUnderlyingStructure().getLine();
}
public int getSourceColumn() {
return getUnderlyingStructure() == null ? -1 : getUnderlyingStructure().getCharPositionInLine() + 1;
}
@Override
public ASTCssNode clone() {
try {
ASTCssNode clone = (ASTCssNode) super.clone();
clone.setOpeningComments(new ArrayList<Comment>(getOpeningComments()));
clone.setOrphanComments(new ArrayList<Comment>(getOrphanComments()));
clone.setTrailingComments(new ArrayList<Comment>(getTrailingComments()));
clone.setParent(null);
return clone;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("This is a bug - please submit issue with this stack trace and an input.");
}
}
public void configureParentToAllChilds() {
List<? extends ASTCssNode> childs = getChilds();
for (ASTCssNode kid : childs) {
kid.setParent(this);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(this.getClass().getSimpleName()).append(" (");
builder.append(getSourceLine()).append(":").append(getSourceColumn());
builder.append(")");
return builder.toString();
}
public enum Visibility {
DEFAULT,
VISIBLE
}
}