/*******************************************************************************
* Copyright 2012-present Pixate, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.pixate.freestyle.styling;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.pixate.freestyle.parsing.PXSourceWriter;
import com.pixate.freestyle.styling.combinators.PXCombinator;
import com.pixate.freestyle.styling.selectors.PXSelector;
import com.pixate.freestyle.styling.selectors.PXSpecificity;
import com.pixate.freestyle.styling.selectors.PXTypeSelector;
import com.pixate.freestyle.styling.selectors.PXSpecificity.PXSpecificityType;
import com.pixate.freestyle.util.CollectionUtil;
public class PXRuleSet extends PXDeclarationContainer {
private PXSpecificity specificity;
private List<PXSelector> selectors;
public PXRuleSet() {
specificity = new PXSpecificity();
}
public void addSelector(PXSelector selector) {
if (selector != null) {
if (selectors == null) {
selectors = new ArrayList<PXSelector>(3);
}
selectors.add(selector);
selector.incrementSpecificity(specificity);
}
}
public List<PXSelector> getSelectors() {
return selectors == null ? Collections.<PXSelector>emptyList() : new ArrayList<PXSelector>(selectors);
}
public PXTypeSelector getTargetTypeSelector() {
PXTypeSelector result = null;
if (!CollectionUtil.isEmpty(selectors)) {
PXSelector candidate = selectors.get(0);
if (candidate != null) {
if (candidate instanceof PXCombinator) {
PXCombinator combinator = (PXCombinator) candidate;
// NOTE: PXStylesheetParser grows expressions down and to
// the left. This guarantees that the top-most nodes
// RHS will be a type selector, and will be the last in the
// expression
result = (PXTypeSelector) combinator.getRhs();
} else if (candidate instanceof PXTypeSelector) {
result = (PXTypeSelector) candidate;
}
}
}
return result;
}
public boolean matches(Object element) {
if (!CollectionUtil.isEmpty(selectors)) {
for (PXSelector selector : selectors) {
if (!selector.matches(element)) {
return false;
}
}
return true;
}
return false;
}
public void setSpecificity(PXSpecificityType specificity, int value) {
this.specificity.setSpecificity(specificity, value);
}
@Override
public String toString() {
PXSourceWriter writer = new PXSourceWriter();
if (selectors != null) {
for (PXSelector selector : selectors) {
writer.print(selector);
writer.print(' ');
}
}
writer.println('{');
writer.increaseIndent();
writer.printIndent();
writer.print("// specificity = ");
writer.println(specificity.toString());
if (declarations != null) {
for (PXDeclaration declaration : declarations) {
writer.printIndent();
writer.print(declaration.toString());
}
}
writer.decreaseIndent();
writer.println('}');
return writer.toString();
}
public static PXRuleSet mergeRuleSets(List<PXRuleSet> ruleSets) {
PXRuleSet result = new PXRuleSet();
if (!CollectionUtil.isEmpty(ruleSets)) {
// Sort rules by specificity
Collections.sort(ruleSets, new Comparator<PXRuleSet>() {
public int compare(PXRuleSet lhs, PXRuleSet rhs) {
if (lhs.specificity == null) {
return (rhs.specificity == null) ? 0 : -1;
} else {
return (rhs.specificity == null) ? 1 : lhs.specificity
.compareTo(rhs.specificity);
}
}
});
for (int i = ruleSets.size() - 1; i >= 0; i--) {
// add selectors
PXRuleSet ruleSet = ruleSets.get(i);
for (PXSelector selector : ruleSet.getSelectors()) {
result.addSelector(selector);
}
// add declarations
for (PXDeclaration declaration : ruleSet.getDeclarations()) {
if (result.hasDeclarationForName(declaration.getName())) {
if (declaration.isImportant()) {
PXDeclaration addedDeclaration = result
.getDeclarationForName(declaration.getName());
if (!addedDeclaration.isImportant()) {
// replace old with this !important one
result.removeDeclaration(addedDeclaration);
result.addDeclaration(declaration);
}
}
} else {
result.addDeclaration(declaration);
}
}
}
}
return result;
}
}