All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cz.vutbr.web.domassign.decode.Decoder Maven / Gradle / Ivy

/**
 * 
 */
package cz.vutbr.web.domassign.decode;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cz.vutbr.web.css.CSSFactory;
import cz.vutbr.web.css.CSSProperty;
import cz.vutbr.web.css.Declaration;
import cz.vutbr.web.css.RuleFactory;
import cz.vutbr.web.css.Term;
import cz.vutbr.web.css.Term.Operator;
import cz.vutbr.web.css.TermColor;
import cz.vutbr.web.css.TermFactory;
import cz.vutbr.web.css.TermFloatValue;
import cz.vutbr.web.css.TermIdent;
import cz.vutbr.web.css.TermInteger;
import cz.vutbr.web.css.TermLength;
import cz.vutbr.web.css.TermList;
import cz.vutbr.web.css.TermNumber;
import cz.vutbr.web.css.TermPercent;
import cz.vutbr.web.css.TermTime;

/**
 * A base class for repeaters and variators.
 * 
 * @author burgetr
 */
public class Decoder
{

    /**
     * A hint about the allowed value range when processing numeric values. 
     */
    public enum ValueRange {
        /** Allow all values */
        ALLOW_ALL,
        /** Treat negative values as invalid */
        DISALLOW_NEGATIVE,
        /** Truncate negative values to zero */
        TRUNCATE_NEGATIVE,
        /** Treat zero as invalid */
        DISALLOW_ZERO
    }
    
    /**
     * Inherit acceptance flags
     */
    public static final boolean AVOID_INH = true;
    public static final boolean ALLOW_INH = false;
    
    public static final RuleFactory rf = CSSFactory.getRuleFactory();
    public static final TermFactory tf = CSSFactory.getTermFactory();

    
    /**
     * Converts TermIdent into CSSProperty using intersection set.
     * CSSProperty.Translator is used.
     * 
     * @param 
     *            Subclass of CSSProperty to be returned
     * @param type
     *            Class of property to be used to retrieve value
     * @param intersection
     *            Intersection set or null if no intersection is
     *            used
     * @param term
     *            TermIdent to be transferred to property
     * @return CSSProperty of type <T> or null
     */
    public static  T genericPropertyRaw(Class type,
            Set intersection, TermIdent term) {

        try {
            String name = term.getValue().replace("-", "_").toUpperCase();
            T property = CSSProperty.Translator.valueOf(type, name);
            if (intersection != null && intersection.contains(property))
                return property;
            return property;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Converts TermIdent into value of enum of given class and stores it into
     * properties map under key property
     * 
     * @param 
     *            Enum & CSSProperty limitation
     * @param type
     *            Type of enum which instance is retrieved
     * @param term
     *            Term with value to be converted
     * @param avoidInherit
     *            If true inherit value is not considered valid
     * @param properties
     *            Properties map where to store value
     * @param propertyName
     *            Name under which property is stored in map
     * @return true in case of success, false
     *         otherwise
     */
    public static  boolean genericProperty(Class type,
            TermIdent term, boolean avoidInherit,
            Map properties, String propertyName) {

        T property = genericPropertyRaw(type, null, term);
        if (property == null || (avoidInherit && property.equalsInherit()))
            return false;

        properties.put(propertyName, property);
        return true;
    }

    /**
     * Converts TermIdent into value of CSSProperty for given class
     * 
     */
    public static  boolean genericTermIdent(Class type,
            Term term, boolean avoidInherit, String propertyName,
            Map properties) {

        if (term instanceof TermIdent) {
            return genericProperty(type, (TermIdent) term, avoidInherit,
                    properties, propertyName);
        }
        return false;
    }

    /**
     * Converts term into Color and stored values and types in maps
     * 
     * @param 
     *            CSSProperty
     * @param term
     *            Term to be parsed
     * @param propertyName
     *            How to store colorIdentificiton
     * @param colorIdentification
     *            What to store under propertyName
     * @param properties
     *            Map to store property types
     * @param values
     *            Map to store property values
     * @return true in case of success, false
     *         otherwise
     */
    public static  boolean genericTermColor(Term term,
            String propertyName, T colorIdentification,
            Map properties, Map> values) {

        if (term instanceof TermColor) {
            properties.put(propertyName, colorIdentification);
            values.put(propertyName, term);
            return true;
        }

        return false;

    }

    /**
     * Converts term into TermLength and stores values and types in maps
     * 
     * @param 
     *            CSSProperty
     * @param term
     *            Term to be parsed
     * @param propertyName
     *            How to store colorIdentificiton
     * @param lengthIdentification
     *            What to store under propertyName
     * @param properties
     *            Map to store property types
     * @param values
     *            Map to store property values
     * @return true in case of success, false
     *         otherwise
     */
    public static  boolean genericTermLength(Term term,
            String propertyName, T lengthIdentification, ValueRange range,
            Map properties, Map> values) {

        if (term instanceof TermInteger  && ((TermInteger) term).getUnit().equals(TermNumber.Unit.none)) {
            if (CSSFactory.getImplyPixelLength() || ((TermInteger) term).getValue() == 0) { //0 is always allowed with no units
                // convert to length with units of px
                TermLength tl = tf.createLength(((TermInteger) term).getValue(), TermNumber.Unit.px);
                return genericTerm(TermLength.class, tl, propertyName, lengthIdentification, range, properties, values);
            } else {
                return false;
            }
        }
        else if (term instanceof TermLength) { 
            return genericTerm(TermLength.class, term, propertyName, lengthIdentification, range, properties, values); 
        }

        return false;

    }

    /**
     * Check whether given declaration contains one term of given type. It is
     * able to check even whether is above zero for numeric values
     * 
     * @param 
     *            Class of CSSProperty to be used for result
     * @param termType
     *            Supposed type of term
     * @param term
     *            Term of which is supposed to be of type termType,
     *            that is input data
     * @param propertyName
     *            Name under which property's value and type is stored in maps
     * @param typeIdentification
     *            How this type of term is described in type T
     * @param sanify
     *            Check if value is positive
     * @param properties
     *            Where to store property type
     * @param values
     *            Where to store property value
     * @return true if succeeded in recognition, false
     *         otherwise
     */
    public static  boolean genericTerm(
            Class> termType, Term term,
            String propertyName, T typeIdentification, ValueRange range,
            Map properties, Map> values) {

        // check type
        if (termType.isInstance(term)) {
            // sanity check
            if (range != ValueRange.ALLOW_ALL) {
                // check for integer
                if (term.getValue() instanceof Integer) {
                    final Integer zero = 0;
                    int result = zero.compareTo((Integer) term.getValue());
                    if (result > 0) {
                        // return false is also possibility
                        // but we will change to zero
                        if (range == ValueRange.TRUNCATE_NEGATIVE)
                            ((TermInteger) term).setZero();
                        else
                            return false;
                    } else if(result == 0) {
                        if(range == ValueRange.DISALLOW_ZERO) {
                            return false;
                        }
                    }
                }
                // check for float
                else if (term.getValue() instanceof java.lang.Float) {
                    final java.lang.Float zero = 0f;
                    int result = zero.compareTo((java.lang.Float) term.getValue());
                    if (result > 0) {
                        // return false is also possibility
                        // but we will change to zero
                        if (range == ValueRange.TRUNCATE_NEGATIVE)
                            ((TermFloatValue) term).setZero();
                        else
                            return false;
                    } else if(result == 0) {
                        if(range == ValueRange.DISALLOW_ZERO) {
                            return false;
                        }
                    }
                }
            }
            // passed both type check and range check,
            // store
            properties.put(propertyName, typeIdentification);
            values.put(propertyName, term);
            return true;

        }
        return false;

    }

    /**
     * Processes declaration which is supposed to contain one identification
     * term
     * 
     * @param 
     *            Type of CSSProperty
     * @param type
     *            Class of CSSProperty to be stored
     * @param d
     *            Declaration to be parsed
     * @param properties
     *            Properties map where to store enum
     * @return true in case of success, false
     *         elsewhere
     */
    public static  boolean genericOneIdent(Class type,
            Declaration d, Map properties) {

        if (d.size() != 1)
            return false;

        return genericTermIdent(type, d.get(0), ALLOW_INH, d.getProperty(),
                properties);
    }

    /**
     * Processes declaration which is supposed to contain one identification
     * term or one TermColor
     * 
     * @param 
     *            Type of CSSProperty
     * @param type
     *            Class of enum to be stored
     * @param colorIdentification
     *            Instance of CSSProperty stored into properties to indicate
     *            that additional value of type TermColor is stored in values
     * @param d
     *            Declaration to be parsed
     * @param properties
     *            Properties map where to store enum
     * @param values
     * @return true in case of success, false
     *         elsewhere
     */
    public static  boolean genericOneIdentOrColor(
            Class type, T colorIdentification, Declaration d,
            Map properties, Map> values) {

        if (d.size() != 1)
            return false;

        return genericTermIdent(type, d.get(0), ALLOW_INH, d.getProperty(),
                properties)
                || genericTermColor(d.get(0), d.getProperty(),
                        colorIdentification, properties, values);
    }

    public static  boolean genericOneIdentOrInteger(
            Class type, T integerIdentification, ValueRange range,
            Declaration d, Map properties,
            Map> values) {

        if (d.size() != 1)
            return false;

        return genericTermIdent(type, d.get(0), ALLOW_INH, d.getProperty(),
                properties)
                || genericTerm(TermInteger.class, d.get(0), d.getProperty(),
                        integerIdentification, range, properties, values);
    }

    public static  boolean genericOneIdentOrIntegerOrNumber(
            Class type, T integerIdentification, T numberIdentification, ValueRange range,
            Declaration d, Map properties,
            Map> values) {

        if (d.size() != 1)
            return false;

        return genericTermIdent(type, d.get(0), ALLOW_INH, d.getProperty(), properties)
                || genericTerm(TermInteger.class, d.get(0), d.getProperty(),
                        integerIdentification, range, properties, values)
                || genericTerm(TermNumber.class, d.get(0), d.getProperty(),
                        numberIdentification, range, properties, values);
    }
    
    public static  boolean genericOneIdentOrLength(
            Class type, T lengthIdentification, ValueRange range,
            Declaration d, Map properties,
            Map> values) {

        if (d.size() != 1)
            return false;

        return genericTermIdent(type, d.get(0), ALLOW_INH, d.getProperty(),
                properties)
                || genericTermLength(d.get(0), d.getProperty(),
                        lengthIdentification, range, properties, values);
    }
    
    public static  boolean genericTime(
            Class type, T integerIdentification, ValueRange range,
            Declaration d, Map properties,
            Map> values) {
        if (d.size() != 1)
            return false;
        
        Term term = d.get(0);
        if (term instanceof TermIdent) {
            T property = genericPropertyRaw(type, null, (TermIdent) term);
            if (!property.equalsInherit())
                return false;
            else
            {
                properties.put(d.getProperty(), property);
                return true;
            }
        }
        return genericTerm(TermTime.class, term, d.getProperty(), integerIdentification, range, properties, values);
    }
    
    public static  boolean genericInteger(
            Class type, T integerIdentification, ValueRange range,
            Declaration d, Map properties,
            Map> values) {

        if (d.size() != 1)
            return false;
        
        Term term = d.get(0);
        if (term instanceof TermIdent)
        {
            T property = genericPropertyRaw(type, null, (TermIdent) term);
            if (!property.equalsInherit())
                return false;
            else
            {
                properties.put(d.getProperty(), property);
                return true;
            }
        }
        else
        {
            return genericTerm(TermInteger.class, term, d.getProperty(), integerIdentification, range, properties, values);
        }
    }
    
    public static  boolean genericIntegerOrLength(
            Class type, T integerIdentification, T lengthIdentification, ValueRange range,
            Declaration d, Map properties,
            Map> values) {

        if (d.size() != 1)
            return false;
        
        Term term = d.get(0);
        if (term instanceof TermIdent)
        {
            T property = genericPropertyRaw(type, null, (TermIdent) term);
            if (!property.equalsInherit())
                return false;
            else
            {
                properties.put(d.getProperty(), property);
                return true;
            }
        }
        else
        {
            return genericTerm(TermInteger.class, term, d.getProperty(),
                            integerIdentification, range, properties, values)
                    || genericTermLength(term, d.getProperty(), lengthIdentification, range, properties, values);
        }
    }
    
    public static  & CSSProperty> boolean genericOneIdentOrLengthOrPercent(
            Class type, T lengthIdentification, T percentIdentification,
            ValueRange range, Declaration d, Map properties,
            Map> values) {

        if (d.size() != 1)
            return false;

        return genericTermIdent(type, d.get(0), ALLOW_INH, d.getProperty(),
                properties)
                || genericTermLength(d.get(0), d.getProperty(),
                        lengthIdentification, range, properties, values)
                || genericTerm(TermPercent.class, d.get(0), d.getProperty(),
                        percentIdentification, range, properties, values);
    }

    public static  & CSSProperty> boolean genericTwoIdentsOrLengthsOrPercents(
            Class type, T listIdentification,
            ValueRange range, Declaration d, Map properties,
            Map> values) {

        if (d.size() == 1) {
            Term term = d.get(0);
            String propertyName = d.getProperty();
            // is it identifier or length ?
            if (genericTermIdent(type, term, ALLOW_INH, propertyName, properties)
                || genericTermLength(term, propertyName,
                        listIdentification, range, properties, values)
                || genericTerm(TermPercent.class, term, propertyName,
                        listIdentification, range, properties, values)) {
                // one term with length was inserted, double it
                if (properties.get(propertyName) == listIdentification) {
                    TermList terms = tf.createList(2);
                    terms.add(term);
                    terms.add(term);
                    values.put(propertyName, terms);
                }
                return true;
            }
            else
                return false;
        }
        // two numerical values
        else if (d.size() == 2) {
            Term term1 = d.get(0);
            Term term2 = d.get(1);
            String propertyName = d.getProperty();
            // two lengths ?
            if ((genericTermLength(term1, propertyName,
                            listIdentification, range, properties, values)
                    || genericTerm(TermPercent.class, term1, propertyName,
                            listIdentification, range, properties, values))
                 && (genericTermLength(term2, propertyName,
                            listIdentification, range, properties, values)
                    || genericTerm(TermPercent.class, term2, propertyName,
                            listIdentification, range, properties, values))) {
                TermList terms = tf.createList(2);
                terms.add(term1);
                terms.add(term2);
                values.put(propertyName, terms);
                return true;
            }
            else
                return false;
        }
        else
            return false;
    }
    
    /**
     * Splits a declaration to multiple declarations by a separating term.
     * @param src the source declarations
     * @param separator separating operator
     * @return a list of declarations where each of them contains a sub-list of terms of the source declaration
     */
    public static List splitDeclarations(Declaration src, Operator sepOperator)
    {
        final List ret = new ArrayList<>();
        Declaration current = rf.createDeclaration();
        current.unlock();
        for (Term t : src.asList()) {
            if (t.getOperator() == sepOperator) {
                ret.add(current);
                current = rf.createDeclaration();
                current.unlock();
            }
            current.add(t);
        }
        ret.add(current);
        return ret;
    }

    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy