package com.github.sommeri.less4j.core.ast; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; 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 SimpleSelector extends SelectorPart implements Cloneable { private InterpolableName elementName; private boolean isStar; //*.warning and .warning are equivalent http://www.w3.org/TR/css3-selectors/#universal-selector //relevant only if the selector is a star private boolean isEmptyForm = false; private List<ElementSubsequent> subsequent = new ArrayList<ElementSubsequent>(); public SimpleSelector(HiddenTokenAwareTree token, SelectorCombinator leadingCombinator, InterpolableName elementName, boolean isStar) { super(token, leadingCombinator); this.elementName = elementName; this.isStar = isStar; } @Override public boolean isEmpty() { if (hasSubsequent()) return false; return (!isStar() || isEmptyForm()) && !hasElement(); } @Override public boolean isClassesAndIdsOnlySelector() { return isLimitedPurposeSelector(ASTCssNodeType.CSS_CLASS, ASTCssNodeType.ID_SELECTOR); } private boolean isLimitedPurposeSelector(ASTCssNodeType... purposes) { if (elementName != null || !isEmptyForm() || subsequent == null) return false; Set<ASTCssNodeType> purposesSet = new HashSet<ASTCssNodeType>(Arrays.asList(purposes)); for (ElementSubsequent es : subsequent) { if (!purposesSet.contains(es.getType())) return false; if (es.isInterpolated()) return false; } return true; } public InterpolableName getElementName() { return elementName; } public boolean isStar() { return isStar; } public boolean isEmptyForm() { return isEmptyForm; } public void setEmptyForm(boolean isEmptyForm) { this.isEmptyForm = isEmptyForm; } public void setElementName(InterpolableName elementName) { this.elementName = elementName; } public void setStar(boolean isStar) { this.isStar = isStar; } public boolean hasElement() { return null != getElementName(); } public List<ElementSubsequent> getSubsequent() { return subsequent; } public void addSubsequent(ElementSubsequent subsequent) { this.subsequent.add(subsequent); } public void removeSubsequent(ElementSubsequent subsequent) { this.subsequent.remove(subsequent); } public void addSubsequent(List<ElementSubsequent> subsequent) { this.subsequent.addAll(subsequent); } @Override @NotAstProperty public List<ASTCssNode> getChilds() { List<ASTCssNode> result = super.getChilds(); ArraysUtils.addIfNonNull(result, elementName); result.addAll(subsequent); return result; } public ASTCssNodeType getType() { return ASTCssNodeType.SIMPLE_SELECTOR; } @Override public SimpleSelector clone() { SimpleSelector clone = (SimpleSelector) super.clone(); clone.subsequent = ArraysUtils.deeplyClonedList(getSubsequent()); clone.elementName = elementName==null? null : elementName.clone(); clone.configureParentToAllChilds(); return clone; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(isStar ? "*" : getElementName()); builder.append(subsequent); return builder.toString(); } public void extendName(String extension, HiddenTokenAwareTree underlyingStructureOfExtension) { if (isStar) { isStar=false; } if (hasElement()) { getElementName().extendName(extension); } else { setElementName(new InterpolableName(underlyingStructureOfExtension, new FixedNamePart(getUnderlyingStructure(), extension))); } } }