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

cz.vutbr.web.domassign.QuadrupleMapNodeData Maven / Gradle / Ivy

package cz.vutbr.web.domassign;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import cz.vutbr.web.css.CSSProperty;
import cz.vutbr.web.css.Declaration;
import cz.vutbr.web.css.NodeData;
import cz.vutbr.web.css.Term;
import cz.vutbr.web.csskit.OutputUtil;

/**
 * Implementation of NodeData by four distinct HashMaps. According to tests,
 * it is about 25% faster then SingleDataMap when retrieving values and inheriting 
 * but occupies up to 100% more memory.
 * 
 * @author kapy
 *
 */
public class QuadrupleMapNodeData extends BaseNodeDataImpl {

	private static final int COMMON_DECLARATION_SIZE = 7;
	
	private Map propertiesOwn;
	private Map propertiesInh;
	private Map> valuesOwn;
	private Map> valuesInh;
	private Map sourcesOwn;
    private Map sourcesInh;
	
	public QuadrupleMapNodeData() {
		this.propertiesOwn = new HashMap(css.getTotalProperties(), 1.0f);
		this.propertiesInh = new HashMap(css.getTotalProperties(), 1.0f);
		this.valuesOwn = new HashMap>(css.getTotalProperties(), 1.0f);
		this.valuesInh = new HashMap>(css.getTotalProperties(), 1.0f);
        this.sourcesOwn = new HashMap(css.getTotalProperties(), 1.0f);
        this.sourcesInh = new HashMap(css.getTotalProperties(), 1.0f);
	}
	
	
	public  T getProperty(String name) {
		return this.getProperty(name, true);
	}
	
	public  T getProperty(String name, boolean includeInherited) {

		CSSProperty inh = null, tmp = null;
		
		if(includeInherited) 
			inh = propertiesInh.get(name);

		tmp = propertiesOwn.get(name);
		if(tmp==null) tmp = inh;
		
		// this will cast to inferred type
		// if there is no inferred type, cast to CSSProperty is safe
		// otherwise the possibility having wrong left side of assignment
		// is roughly the same as use wrong dynamic class cast 
		@SuppressWarnings("unchecked")
		T retval = (T) tmp;
		return retval;
	}
	
    public Term getValue(String name, boolean includeInherited) {
        
        if (includeInherited) { 
            final Term own = valuesOwn.get(name);
            if (own != null)
                return own;
            else
            {
                Term inherited = null;
                if (!propertiesOwn.containsKey(name))
                    inherited = valuesInh.get(name);
                return inherited;
            }
        }
        else
            return valuesOwn.get(name);
    }
    
	public > T getValue(Class clazz, String name, boolean includeInherited) {
		
        if(includeInherited) { 
            final T own = clazz.cast(valuesOwn.get(name));
            if (own != null)
                return own;
            else
            {
                T inherited = null;
                if (!propertiesOwn.containsKey(name))
                    inherited = clazz.cast(valuesInh.get(name));
                return inherited;
            }
        }
        else
            return clazz.cast(valuesOwn.get(name));
	}
	
	public > T getValue(Class clazz, String name) {
		return getValue(clazz, name, true);
	}
	
    public String getAsString(String name, boolean includeInherited) {
        boolean usedInherited = false;
        CSSProperty prop = propertiesOwn.get(name);
        if (prop == null && includeInherited) {
            prop = propertiesInh.get(name);
            usedInherited = true;
        }
        if (prop == null)
            return null;
        else if (!prop.toString().isEmpty())
            return prop.toString();
        else {
            Term val = usedInherited ? valuesInh.get(name) : valuesOwn.get(name);
            return (val == null) ? null : val.toString();
        }
    }
    
	public NodeData push(Declaration d) {
		
		Map properties = 
			new HashMap(COMMON_DECLARATION_SIZE);
		Map> terms = 
			new HashMap>(COMMON_DECLARATION_SIZE);
		
		boolean result = transformer.parseDeclaration(d, properties, terms);
		
		// in case of false do not insert anything
		if(!result) return this;
		
		//set the sources and store the properties
        for(Entry entry: properties.entrySet()) {
            propertiesOwn.put(entry.getKey(), entry.getValue());
            sourcesOwn.put(entry.getKey(), d);
        }
		
		// remove operators from terms and store the values
		for(Entry> entry: terms.entrySet()) {
		    Term t = entry.getValue();
		    if (t.getOperator() != null)
		        t = t.shallowClone().setOperator(null);
			valuesOwn.put(entry.getKey(), t);
		}
		
		return this;
		
	}
	
	public NodeData inheritFrom(NodeData parent) throws ClassCastException {
		
		if(parent==null)
			return this;
		
		if(!(parent instanceof QuadrupleMapNodeData))
			throw new ClassCastException(
					"Cant't inherit from NodeData different from "
							+ this.getClass().getName() + "("+ parent.getClass().getName()+")");
		
		QuadrupleMapNodeData nd = (QuadrupleMapNodeData) parent;
		
		// inherit values
		for(String key:nd.propertiesInh.keySet()) {
			CSSProperty value = nd.propertiesInh.get(key);
			CSSProperty cur = this.propertiesOwn.get(key);
			if(value.inherited() || (cur != null && cur.equalsInherit())) {
				this.propertiesInh.put(key, value);
				// remove old value to be sure
				this.valuesInh.remove(key);
				Term term = nd.valuesInh.get(key);
				if(term!=null) this.valuesInh.put(key, term);
				Declaration src = nd.sourcesInh.get(key);
				if (src != null) this.sourcesInh.put(key, src);
			}
		}
		
		for(String key:nd.propertiesOwn.keySet()) {
			CSSProperty value = nd.propertiesOwn.get(key);
			CSSProperty cur = this.propertiesOwn.get(key);
			if(value.inherited() || (cur != null && cur.equalsInherit())) {
				this.propertiesInh.put(key, value);
				// remove old value to be sure
				this.valuesInh.remove(key);
				Term term = nd.valuesOwn.get(key);
				if(term!=null) this.valuesInh.put(key, term);
				Declaration src = nd.sourcesOwn.get(key);
				if(src!=null) this.sourcesInh.put(key, src);
			}
		}		
	
		return this;
	}
	
	public NodeData concretize() {
		
		// inherited firstly, replace them with defaults
		for(String key: propertiesInh.keySet()) {
			CSSProperty p = propertiesInh.get(key);
			if(p.equalsInherit()) {
				propertiesInh.put(key, css.getDefaultProperty(key));
				Term value = css.getDefaultValue(key);
				if(value!=null) valuesInh.put(key, value);
			}
		
		}
		
		// own after, replace them with inherited or default
		for(String key:propertiesOwn.keySet()) {
			CSSProperty p = propertiesOwn.get(key);
			if(p.equalsInherit()) {
				CSSProperty rp = propertiesInh.get(key);
				if(rp==null) rp = css.getDefaultProperty(key);
				
				propertiesOwn.put(key, rp);
				
				Term value = valuesInh.get(key);
				if(value==null) value = css.getDefaultValue(key);
				if(value!=null) valuesOwn.put(key, value);
				
				Declaration source = sourcesInh.get(key);
				if(source!=null) sourcesOwn.put(key, source);
			} else if (p.equalsInitial()) {
			    CSSProperty rp = css.getDefaultProperty(key);
			    propertiesOwn.put(key, rp);
			    Term value = css.getDefaultValue(key);
			    if (value != null)
			        valuesOwn.put(key, value);
			} else if (p.equalsUnset()) {
			    if (p.inherited()) {
	                CSSProperty rp = propertiesInh.get(key);
	                if(rp==null) rp = css.getDefaultProperty(key);
	                propertiesOwn.put(key, rp);
	                
	                Term value = valuesInh.get(key);
	                if(value==null) value = css.getDefaultValue(key);
	                if(value!=null) valuesOwn.put(key, value);
			    } else {
	                CSSProperty rp = css.getDefaultProperty(key);
	                propertiesOwn.put(key, rp);
	                Term value = css.getDefaultValue(key);
	                if (value != null)
	                    valuesOwn.put(key, value);
			    }
			}
		}
		
		return this;
	}

	@Override
	public String toString() {
		
		StringBuilder sb = new StringBuilder();
		
		
		Set tmp = new LinkedHashSet();
		tmp.addAll(propertiesInh.keySet());
		tmp.addAll(propertiesOwn.keySet());
		
		List keys = new ArrayList(tmp);
		Collections.sort(keys);

		for(String key:keys) {
			// always use own value if exists
			CSSProperty prop = propertiesOwn.get(key);
			if(prop==null) prop = propertiesInh.get(key);

			Term value = valuesOwn.get(key);
			if(value==null) value = valuesInh.get(key);
			
			sb.append(key).append(OutputUtil.PROPERTY_OPENING);
			
			if(value!=null) sb.append(value.toString());
			else sb.append(prop.toString());
				
			sb.append(OutputUtil.PROPERTY_CLOSING);
			
		}
		
		return sb.toString();
	}

    @Override
    public Collection getPropertyNames()
    {
        final Set props = new LinkedHashSet();
        props.addAll(propertiesInh.keySet());
        props.addAll(propertiesOwn.keySet());

        final List keys = new ArrayList(props);
        Collections.sort(keys);

        return keys;
    }

    @Override
    public Declaration getSourceDeclaration(String name)
    {
        return sourcesOwn.get(name);
    }
    
    @Override
    public Declaration getSourceDeclaration(String name, boolean includeInherited)
    {
        Declaration ret = sourcesOwn.get(name);
        if (includeInherited && ret == null)
            ret = sourcesInh.get(name);
        return ret;
    }
    
	
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((propertiesInh == null) ? 0 : propertiesInh.hashCode());
		result = prime * result
				+ ((propertiesOwn == null) ? 0 : propertiesOwn.hashCode());
		result = prime * result
				+ ((valuesInh == null) ? 0 : valuesInh.hashCode());
		result = prime * result
				+ ((valuesOwn == null) ? 0 : valuesOwn.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof QuadrupleMapNodeData))
			return false;
		QuadrupleMapNodeData other = (QuadrupleMapNodeData) obj;
		if (propertiesInh == null) {
			if (other.propertiesInh != null)
				return false;
		} else if (!propertiesInh.equals(other.propertiesInh))
			return false;
		if (propertiesOwn == null) {
			if (other.propertiesOwn != null)
				return false;
		} else if (!propertiesOwn.equals(other.propertiesOwn))
			return false;
		if (valuesInh == null) {
			if (other.valuesInh != null)
				return false;
		} else if (!valuesInh.equals(other.valuesInh))
			return false;
		if (valuesOwn == null) {
			if (other.valuesOwn != null)
				return false;
		} else if (!valuesOwn.equals(other.valuesOwn))
			return false;
		return true;
	}

	
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy