/*******************************************************************************
* Copyright (c) 2008, 2015 Innoopract Informationssysteme GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.rap.rwt.internal.theme.css;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.rap.rwt.internal.theme.CssValue;
import org.w3c.css.sac.Selector;
import org.w3c.css.sac.SelectorList;
/**
* Instances of this class represent a parsed CSS stylesheet.
*/
public final class StyleSheet {
private static final SelectorWrapperComparator COMPARATOR = new SelectorWrapperComparator();
private final StyleRule[] styleRules;
private SelectorWrapper[] selectorWrappers;
public StyleSheet( StyleRule[] styleRules ) {
this.styleRules = styleRules.clone();
createSelectorWrappers();
}
public StyleRule[] getStyleRules() {
return styleRules.clone();
}
public ConditionalValue[] getValues( String elementName, String propertyName ) {
List<ConditionalValue> buffer = new ArrayList<>();
for( SelectorWrapper selectorWrapper : selectorWrappers ) {
String selectorElement = ( ( SelectorExt )selectorWrapper.selector ).getElementName();
if( selectorElement == null || selectorElement.equals( elementName ) ) {
CssValue value = selectorWrapper.propertyMap.getValue( propertyName );
if( value != null ) {
String[] constraints = ( ( SelectorExt )selectorWrapper.selector ).getConstraints();
Arrays.sort( constraints );
if( !containsConstraintsAlready( buffer, constraints ) ) {
buffer.add( new ConditionalValue( value, constraints ) );
}
}
}
}
return buffer.toArray( new ConditionalValue[ buffer.size() ] );
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
StyleRule[] styleRules = getStyleRules();
for( int i = 0; i < styleRules.length; i++ ) {
StyleRule styleRule = styleRules[ i ];
SelectorList selectors = styleRule.getSelectors();
int length = selectors.getLength();
for( int j = 0; j < length; j++ ) {
if( j > 0 ) {
buffer.append( "," );
}
if( i > 0 ) {
buffer.append( "\n" );
}
buffer.append( selectors.item( j ) );
}
buffer.append( "\n" );
buffer.append( styleRule.getProperties() );
buffer.append( "\n" );
}
return buffer.toString();
}
private static boolean containsConstraintsAlready( List<ConditionalValue> conditionalValuesList,
String[] constraints )
{
for( ConditionalValue condValue : conditionalValuesList ) {
if( Arrays.equals( condValue.constraints, constraints ) ) {
return true;
}
}
return false;
}
private void createSelectorWrappers() {
List<SelectorWrapper> selectorWrappersList = new LinkedList<>();
for( int pos = 0; pos < styleRules.length; pos++ ) {
StyleRule styleRule = styleRules[ pos ];
SelectorList selectors = styleRule.getSelectors();
StylePropertyMap properties = styleRule.getProperties();
int length = selectors.getLength();
for( int i = 0; i < length; i++ ) {
Selector selector = selectors.item( i );
SelectorWrapper selectorWrapper = new SelectorWrapper( selector, properties, pos );
selectorWrappersList.add( selectorWrapper );
}
}
Collections.sort( selectorWrappersList, COMPARATOR );
Collections.reverse( selectorWrappersList );
selectorWrappers = new SelectorWrapper[ selectorWrappersList.size() ];
selectorWrappersList.toArray( selectorWrappers );
}
static class SelectorWrapper {
public final Selector selector;
public final StylePropertyMap propertyMap;
public final int position;
public SelectorWrapper( Selector selector, StylePropertyMap propertyMap, int position ) {
this.selector = selector;
this.propertyMap = propertyMap;
this.position = position;
}
}
private static class SelectorWrapperComparator implements Comparator<SelectorWrapper> {
@Override
public int compare( SelectorWrapper selectorWrapper1, SelectorWrapper selectorWrapper2 ) {
int result = 0;
int specificity1 = ( ( Specific )selectorWrapper1.selector ).getSpecificity();
int specificity2 = ( ( Specific )selectorWrapper2.selector ).getSpecificity();
if( specificity1 > specificity2 ) {
result = 1;
} else if( specificity1 < specificity2 ) {
result = -1;
} else if( selectorWrapper1.position > selectorWrapper2.position ) {
result = 1;
} else if( selectorWrapper1.position < selectorWrapper2.position ) {
result = -1;
}
return result;
}
}
}