package com.github.sommeri.less4j.core.ast;
import java.util.ArrayList;
import java.util.List;
import com.github.sommeri.less4j.core.ast.annotations.NotAstProperty;
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
import com.github.sommeri.less4j.utils.ArraysUtils;
public class ReusableStructure extends ASTCssNode implements BodyOwner<GeneralBody> {
//TODO: This is needed for simple cycle cutting. Having proper solution would be nicer,
//this feels like a hack
private final boolean isAlsoRuleset;
private List<ReusableStructureName> names = new ArrayList<ReusableStructureName>();
//Allows: variable, argument declaration, pattern
private List<ASTCssNode> parameters = new ArrayList<ASTCssNode>();
private List<Guard> guards = new ArrayList<Guard>();
private GeneralBody body;
public ReusableStructure(HiddenTokenAwareTree token) {
this(token, false);
}
public ReusableStructure(HiddenTokenAwareTree token, boolean isAlsoRuleset) {
super(token);
this.isAlsoRuleset = isAlsoRuleset;
}
public ReusableStructure(HiddenTokenAwareTree token, List<ReusableStructureName> names, boolean isAlsoRuleset) {
this(token, isAlsoRuleset);
this.names=names;
}
public void addName(ReusableStructureName name) {
names.add(name);
}
public List<ReusableStructureName> getNames() {
return names;
}
public List<String> getNamesAsStrings() {
List<String> result = new ArrayList<String>();
for (ReusableStructureName name : getNames()) {
result.add(name.asString());
}
return result;
}
public boolean hasName(String name) {
return getNamesAsStrings().contains(name);
}
public void setNames(List<ReusableStructureName> names) {
this.names = names;
}
public GeneralBody getBody() {
return body;
}
public boolean hasEmptyBody() {
return body==null? true : body.isEmpty();
}
public void setBody(GeneralBody body) {
this.body = body;
}
public List<ASTCssNode> getParameters() {
return parameters;
}
public boolean hasParameters() {
return !getParameters().isEmpty();
}
public boolean hasCollectorParameter() {
if (parameters==null || parameters.isEmpty())
return false;
ASTCssNode last = parameters.get(parameters.size()-1);
if (last.getType()!=ASTCssNodeType.ARGUMENT_DECLARATION)
return false;
return ((ArgumentDeclaration) last).isCollector();
}
public List<ASTCssNode> getMandatoryParameters() {
List<ASTCssNode> result = new ArrayList<ASTCssNode>();
for (ASTCssNode param : getParameters()) {
if (param.getType()==ASTCssNodeType.ARGUMENT_DECLARATION) {
ArgumentDeclaration declaration = (ArgumentDeclaration) param;
if (declaration.isMandatory())
result.add(declaration);
}
}
return result;
}
public boolean hasMandatoryParameters() {
return !getMandatoryParameters().isEmpty();
}
public void addParameter(ASTCssNode parameter) {
if (parameter.getType()!=ASTCssNodeType.ARGUMENT_DECLARATION && !(parameter instanceof Expression))
throw new IllegalArgumentException("The node can not be used as a mixin parameter: " + parameter);
this.parameters.add(parameter);
}
public List<Guard> getGuards() {
return guards;
}
public void addGuard(Guard guard) {
this.guards.add(guard);
}
public void addGuards(List<Guard> guards) {
this.guards.addAll(guards);
}
@Override
@NotAstProperty
public List<? extends ASTCssNode> getChilds() {
List<ASTCssNode> result = ArraysUtils.asNonNullList((ASTCssNode)body);
result.addAll(names);
result.addAll(parameters);
return result;
}
public ASTCssNodeType getType() {
return ASTCssNodeType.REUSABLE_STRUCTURE;
}
public boolean isAlsoRuleset() {
return isAlsoRuleset;
}
@Override
public ReusableStructure clone() {
ReusableStructure result = (ReusableStructure) super.clone();
result.names = ArraysUtils.deeplyClonedList(names);
result.parameters = ArraysUtils.deeplyClonedList(parameters);
result.guards = ArraysUtils.deeplyClonedList(guards);
result.body = body==null?null:body.clone();
result.configureParentToAllChilds();
return result;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ReusableStructure [");
builder.append(names);
builder.append("]");
return builder.toString();
}
}