package com.github.sommeri.less4j.core.ast; import java.util.ArrayList; import java.util.Collections; 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.core.problems.BugHappened; import com.github.sommeri.less4j.utils.ArraysUtils; public class RuleSet extends ASTCssNode implements BodyOwner<GeneralBody> { private List<Selector> selectors = new ArrayList<Selector>(); private List<Guard> guards = new ArrayList<Guard>(); private GeneralBody body; public RuleSet(HiddenTokenAwareTree token) { super(token); } public RuleSet(HiddenTokenAwareTree token, GeneralBody body, List<Selector> selectors) { super(token); this.body = body; addSelectors(selectors); configureParentToAllChilds(); } public List<Selector> getSelectors() { return selectors; } public void setSelectors(List<Selector> selectors) { this.selectors = selectors; } public GeneralBody getBody() { return body; } public boolean hasEmptyBody() { return body==null? true : body.isEmpty(); } public void setBody(GeneralBody body) { this.body = body; } public boolean isUsableAsReusableStructure() { for (Selector selector : selectors) { if (selector.isReusableSelector()) return true; } return false; } /** * Behavior of this method is undefined if it is not mixin. * @return */ public ReusableStructure convertToReusableStructure() { if (!isUsableAsReusableStructure()) throw new BugHappened("Caller is supposed to check for this.", this); List<ReusableStructureName> reusableNames = new ArrayList<ReusableStructureName>(); for (Selector selector : selectors) if (selector.isReusableSelector()) { ReusableStructureName reusableStructureName = selector.toReusableStructureName(); reusableNames.add(reusableStructureName); } ReusableStructure reusable = new ReusableStructure(getUnderlyingStructure(), reusableNames, true); reusable.setBody(getBody().clone()); reusable.addGuards(ArraysUtils.deeplyClonedList(getGuards())); //(getBody().clone()); reusable.configureParentToAllChilds(); return reusable; } /** * Behavior of this method is undefined if it is not a namespace. * @return */ public List<String> extractReusableStructureNames() { List<String> result = new ArrayList<String>(); for (Selector selector : selectors) { if (selector.isReusableSelector()) { ReusableStructureName reusableStructureName = selector.toReusableStructureName(); result.add(reusableStructureName.asString()); } } if (result.isEmpty()) { throw new BugHappened("Not convertible to resusable structure - caller was supposed to check for this.", this); } return result; } @Override @NotAstProperty public List<? extends ASTCssNode> getChilds() { List<ASTCssNode> result = ArraysUtils.asNonNullList((ASTCssNode)body); result.addAll(0, guards); result.addAll(0, selectors); return result; } public void addSelectors(List<Selector> selectors) { this.selectors.addAll(selectors); } public void addSelector(Selector selector) { this.selectors.add(selector); } public void addGuards(List<Guard> guards) { this.guards.addAll(guards); } public void addGuards(Guard guard) { this.guards.add(guard); } public void removeGuards() { for (Guard guard : guards) { guard.setParent(null); } guards.clear(); } public void replaceSelector(Selector oldSelector, Selector newSelector) { oldSelector.setParent(null); newSelector.setParent(this); Collections.replaceAll(this.selectors, oldSelector, newSelector); } public void replaceSelectors(List<Selector> result) { for (Selector oldSelector : selectors) { oldSelector.setParent(null); } selectors = new ArrayList<Selector>(); selectors.addAll(result); } @Override public RuleSet clone() { RuleSet result = (RuleSet) super.clone(); result.body = body==null?null:body.clone(); result.selectors = ArraysUtils.deeplyClonedList(selectors); result.guards = ArraysUtils.deeplyClonedList(guards); result.configureParentToAllChilds(); return result; } public ASTCssNodeType getType() { return ASTCssNodeType.RULE_SET; } public List<Guard> getGuards() { return guards; } }