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

net.sf.jabb.util.stat.AggregationPeriodHierarchy Maven / Gradle / Ivy

The newest version!
/**
 * 
 */
package net.sf.jabb.util.stat;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * The forest structure of AggregationPeriod nodes.
 * Each node can have an attachment object.
 * @author James Hu
 *
 * @param  type of attachments
 */
public class AggregationPeriodHierarchy implements Serializable{
	private static final long serialVersionUID = 8664232464718744888L;

	protected Map> codeMapping = new HashMap<>();
	protected SortedMap> roots = new TreeMap<>();

	
	static class AggregationPeriodNode implements Serializable{
		private static final long serialVersionUID = 4925692035577355240L;

		AggregationPeriodAndAttachment aggregationPeriodAndAttachment;
		AggregationPeriodNode lowerLevelNode;
		Set> upperLevelNodes;
		SortedMap> upperLevels;

		AggregationPeriodNode(AggregationPeriodAndAttachment aggregationPeriodAndAttachment){
			this.aggregationPeriodAndAttachment = aggregationPeriodAndAttachment;
		}

		AggregationPeriodNode(AggregationPeriod aggregationPeriod, NT attachment){
			this.aggregationPeriodAndAttachment = new AggregationPeriodAndAttachment(aggregationPeriod, attachment);
		}
		
		void addUpperLevel(AggregationPeriodNode upperLevel){
			if (upperLevelNodes == null){
				upperLevelNodes = new HashSet<>();
				upperLevels = new TreeMap<>();
			}
			upperLevelNodes.add(upperLevel);
			upperLevels.put(upperLevel.aggregationPeriodAndAttachment.getAggregationPeriod(), upperLevel.aggregationPeriodAndAttachment);
			upperLevel.lowerLevelNode = this;
		}
	}

	/**
	 * Add a root which represents the lowest level aggregation period in the aggregation hierarchy
	 * @param aggregationPeriod		the root - lowest level in the aggregation hierarchy
	 * @return		true if successfully added, false if such a root already exists
	 */
	public boolean add(AggregationPeriod aggregationPeriod){
		return add(aggregationPeriod, (T)null);
	}
	/**
	 * Add a root which represents the lowest level aggregation period in the aggregation hierarchy
	 * @param aggregationPeriod		the root - lowest level in the aggregation hierarchy
	 * @param attachment		the attachment object
	 * @return		true if successfully added, false if such a root already exists
	 */
	public boolean add(AggregationPeriod aggregationPeriod, T attachment){
		AggregationPeriodNode root = new AggregationPeriodNode(aggregationPeriod, attachment);
		String code = root.aggregationPeriodAndAttachment.getAggregationPeriod().getCodeName();
		if (codeMapping.putIfAbsent(code, root) == null){
			roots.put(aggregationPeriod, new AggregationPeriodAndAttachment(aggregationPeriod, attachment));
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Add a root which represents the lowest level aggregation period in the aggregation hierarchy
	 * @param codeName	code name of the root - lowest level in the aggregation hierarchy
	 * @return		true if successfully added, false if such a root already exists
	 */
	public boolean add(String codeName){
		return add(codeName, (T)null);
	}
	/**
	 * Add a root which represents the lowest level aggregation period in the aggregation hierarchy
	 * @param codeName	code name of the root - lowest level in the aggregation hierarchy
	 * @param attachment		the attachment object
	 * @return		true if successfully added, false if such a root already exists
	 */
	public boolean add(String codeName, T attachment){
		return add(AggregationPeriod.parse(codeName), attachment);
	}
	
	/**
	 * Add a root which represents the lowest level aggregation period in the aggregation hierarchy
	 * @param amount	amount of the aggregation period
	 * @param unit		unit of the aggregation period
	 * @return	true if successfully added, false if such a root already exists
	 */
	public boolean add(int amount, AggregationPeriodUnit unit){
		return add(amount, unit, (T)null);
	}
	/**
	 * Add a root which represents the lowest level aggregation period in the aggregation hierarchy
	 * @param amount	amount of the aggregation period
	 * @param unit		unit of the aggregation period
	 * @param attachment		the attachment object
	 * @return	true if successfully added, false if such a root already exists
	 */
	public boolean add(int amount, AggregationPeriodUnit unit, T attachment){
		return add(new AggregationPeriod(amount, unit), attachment);
	}

	/**
	 * Add a non-root aggregation period
	 * @param base			the lower level aggregation period that the upper level one one is based on. 
	 * 						It must already exist in the hierarchy
	 * @param upperLevel	the aggregation period that will be added
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(AggregationPeriod base, AggregationPeriod upperLevel){
		return add(base, upperLevel, (T)null);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param base			the lower level aggregation period that the upper level one one is based on. 
	 * 						It must already exist in the hierarchy
	 * @param upperLevel	the aggregation period that will be added
	 * @param attachment		the attachment object
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(AggregationPeriod base, AggregationPeriod upperLevel, T attachment){
		return add(base.getCodeName(), upperLevel, attachment);
	}
		
	/**
	 * Add a non-root aggregation period
	 * @param baseCodeName	the code name of the lower level aggregation period that the upper level one one is based on.
	 * 						It must already exist in the hierarchy
	 * @param upperLevel	the aggregation period that will be added
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(String baseCodeName, AggregationPeriod upperLevel){
		return add(baseCodeName, upperLevel, (T)null);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseCodeName	the code name of the lower level aggregation period that the upper level one one is based on.
	 * 						It must already exist in the hierarchy
	 * @param upperLevel	the aggregation period that will be added
	 * @param attachment		the attachment object
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(String baseCodeName, AggregationPeriod upperLevel, T attachment){
		AggregationPeriodNode parent = codeMapping.get(baseCodeName);
		if (parent == null){
			return false;
		}
		
		if (!parent.aggregationPeriodAndAttachment.aggregationPeriod.canBeAggregatedTo(upperLevel)){
			throw new IllegalArgumentException("Aggregation period [" + parent.aggregationPeriodAndAttachment.aggregationPeriod + "] cannot be aggregated to ["
					+ upperLevel + "]");
		}
		
		AggregationPeriodNode child = new AggregationPeriodNode(upperLevel, attachment);
		String code = upperLevel.getCodeName();
		if (codeMapping.putIfAbsent(code, child) == null){
			parent.addUpperLevel(child);
			return true;
		}else{
			return false;
		}
		
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseCodeName	the code name of the lower level aggregation period that the upper level one one is based on.
	 * 						It must already exist in the hierarchy
	 * @param amount	amount of the aggregation period
	 * @param unit		unit of the aggregation period
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(String baseCodeName, int amount, AggregationPeriodUnit unit){
		return add(baseCodeName, amount, unit, (T)null);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseCodeName	the code name of the lower level aggregation period that the upper level one one is based on.
	 * 						It must already exist in the hierarchy
	 * @param amount	amount of the aggregation period
	 * @param unit		unit of the aggregation period
	 * @param attachment		the attachment object
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(String baseCodeName, int amount, AggregationPeriodUnit unit, T attachment){
		return add(baseCodeName, new AggregationPeriod(amount, unit), attachment);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseCodeName	the code name of the lower level aggregation period that the upper level one one is based on.
	 * 						It must already exist in the hierarchy
	 * @param codeName		code name of the aggregation period that will be added
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(String baseCodeName, String codeName){
		return add(baseCodeName, codeName, (T)null);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseCodeName	the code name of the lower level aggregation period that the upper level one one is based on.
	 * 						It must already exist in the hierarchy
	 * @param codeName		code name of the aggregation period that will be added
	 * @param attachment		the attachment object
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(String baseCodeName, String codeName, T attachment){
		return add(baseCodeName, AggregationPeriod.parse(codeName), attachment);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseAmount	amount of the lower level aggregation period that the upper level one one is based on.
	 * @param baseUnit		unit of the lower level aggregation period that the upper level one one is based on.
	 * @param amount	amount of the aggregation period that will be added
	 * @param unit		unit of the aggregation period that will be added
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(int baseAmount, AggregationPeriodUnit baseUnit, int amount, AggregationPeriodUnit unit){
		return add(baseAmount, baseUnit, amount, unit, (T)null);
	}
	
	/**
	 * Add a non-root aggregation period
	 * @param baseAmount	amount of the lower level aggregation period that the upper level one one is based on.
	 * @param baseUnit		unit of the lower level aggregation period that the upper level one one is based on.
	 * @param amount	amount of the aggregation period that will be added
	 * @param unit		unit of the aggregation period that will be added
	 * @param attachment		the attachment object
	 * @return	true if successfully added, false if the upper level aggregation period already exists or if the base does not exist
	 * @throws IllegalArgumentException  if the base aggregation period cannot be aggregated to the upper level aggregation period
	 */
	public boolean add(int baseAmount, AggregationPeriodUnit baseUnit, int amount, AggregationPeriodUnit unit, T attachment){
		return add(AggregationPeriod.getCodeName(baseAmount, baseUnit), new AggregationPeriod(amount, unit), attachment);
	}
	
	/**
	 * Get all roots - aggregation periods that are of the lowest level.
	 * The result is sorted.
	 * @return	the roots
	 */
	public Set getRoots(){
		return roots.keySet();
	}
	
	/**
	 * Get all roots with attachments - aggregation periods that are of the lowest level.
	 * The result is sorted.
	 * @return	the roots
	 */
	public Collection> getRootsWithAttachments(){
		return roots.values();
	}
	
	/**
	 * Get all aggregation periods across all levels.
	 * The result is not sorted.
	 * @return	all aggregation periods
	 */
	public Set getAll(){
		return codeMapping.values().stream()
				.map(node->node.aggregationPeriodAndAttachment.getAggregationPeriod())
				.collect(Collectors.toSet());
	}
	
	/**
	 * Get all aggregation periods with attachments across all levels.
	 * The result is not sorted.
	 * @return	all aggregation periods with attachments
	 */
	public Collection> getAllWithAttachments(){
		return codeMapping.values().stream()
				.map(node->node.aggregationPeriodAndAttachment)
				.collect(Collectors.toSet());
	}
	
	/**
	 * Get the number of aggregation periods contained in the hierarchy
	 * @return	number of aggregation periods
	 */
	public int size(){
		return codeMapping.size();
	}
	
	/**
	 * Get the aggregation period in the hierarchy with the specified code name
	 * @param code	the code name
	 * @return	the matching AggregationPeriod found in the hierarchy, or null if not found
	 */
	public AggregationPeriod get(String code){
		AggregationPeriodNode node = codeMapping.get(code);
		return node == null ? null : node.aggregationPeriodAndAttachment.getAggregationPeriod();
	}
	
	/**
	 * Get the aggregation period in the hierarchy with the specified code name, with attachment
	 * @param code	the code name
	 * @return	the matching AggregationPeriod found in the hierarchy including attachment, or null if not found
	 */
	public AggregationPeriodAndAttachment getWithAttachment(String code){
		AggregationPeriodNode node = codeMapping.get(code);
		return node == null ? null : node.aggregationPeriodAndAttachment;
	}
	
	/**
	 * Get the lower level aggregation period of an aggregation period in the hierarchy
	 * @param code	the code name of the aggregation period for which the lower level aggregation period needs to be returned
	 * @return the lower level aggregation period, or null if there is no aggregation period matching the code name or if the one matching the code name is a root
	 */
	public AggregationPeriod getLowerLevelAggregationPeriod(String code){
		AggregationPeriodNode node = codeMapping.get(code);
		return node == null ? null : 
			(node.lowerLevelNode == null ? null : node.lowerLevelNode.aggregationPeriodAndAttachment.getAggregationPeriod());
	}
	
	/**
	 * Get the lower level aggregation period of an aggregation period in the hierarchy, with attachment
	 * @param code	the code name of the aggregation period for which the lower level aggregation period needs to be returned
	 * @return the lower level aggregation period, or null if there is no aggregation period matching the code name or if the one matching the code name is a root
	 */
	public AggregationPeriodAndAttachment getLowerLevelAggregationPeriodWithAttachment(String code){
		AggregationPeriodNode node = codeMapping.get(code);
		return node == null ? null : 
			(node.lowerLevelNode == null ? null : node.lowerLevelNode.aggregationPeriodAndAttachment);
	}
	
	/**
	 * Get the upper level aggregation periods of an aggregation period in the hierarchy
	 * @param code	the code name of the aggregation period for which the upper level aggregation periods need to be returned
	 * @return the upper level aggregation periods, it will not be null but may be empty.
	 */
	public Set getUpperLevelAggregationPeriods(String code){
		AggregationPeriodNode node = codeMapping.get(code);
		Set result = node == null ? null : 
			(node.upperLevels == null ? null : node.upperLevels.keySet());
		return result == null ? Collections.emptySortedSet() : result;
	}
	
	/**
	 * Get the upper level aggregation periods of an aggregation period in the hierarchy, with attachments
	 * @param code	the code name of the aggregation period for which the upper level aggregation periods need to be returned
	 * @return the sorted upper level aggregation periods with attachments, it will not be null but may be empty.
	 */
	public Collection> getUpperLevelAggregationPeriodsWithAttachments(String code){
		AggregationPeriodNode node = codeMapping.get(code);
		Collection> result = node == null ? null : 
			(node.upperLevels == null ? null : node.upperLevels.values());
		return result == null ? Collections.emptySortedSet() : result;
	}
	
	/**
	 * Get the lower level aggregation period of an aggregation period in the hierarchy
	 * @param aggregationPeriod	the aggregation period for which the lower level aggregation period needs to be returned
	 * @return	the lower level aggregation period, or null if the specified aggregation period is a root
	 */
	public AggregationPeriod getLowerLevelAggregationPeriod(AggregationPeriod aggregationPeriod){
		return getLowerLevelAggregationPeriod(aggregationPeriod.getCodeName());
	}
	
	/**
	 * Get the lower level aggregation period of an aggregation period in the hierarchy, with attachments
	 * @param aggregationPeriod	the aggregation period for which the lower level aggregation period needs to be returned
	 * @return	the lower level aggregation period with attachment, or null if the specified aggregation period is a root
	 */
	public AggregationPeriodAndAttachment getLowerLevelAggregationPeriodWithAttachment(AggregationPeriod aggregationPeriod){
		return getLowerLevelAggregationPeriodWithAttachment(aggregationPeriod.getCodeName());
	}
	
	/**
	 * Get the upper level aggregation periods of an aggregation period in the hierarchy
	 * @param aggregationPeriod	the aggregation period for which the upper level aggregation periods need to be returned
	 * @return	the upper level aggregation periods, it will not be null but may be empty.
	 */
	public Set getUpperLevelAggregationPeriods(AggregationPeriod aggregationPeriod){
		return getUpperLevelAggregationPeriods(aggregationPeriod.getCodeName());
	}
	
	/**
	 * Get the upper level aggregation periods of an aggregation period in the hierarchy, with attachments
	 * @param aggregationPeriod	the aggregation period for which the upper level aggregation periods need to be returned
	 * @return	the sorted upper level aggregation periods with attachments, it will not be null but may be empty.
	 */
	public Collection> getUpperLevelAggregationPeriodsWithAttachments(AggregationPeriod aggregationPeriod){
		return getUpperLevelAggregationPeriodsWithAttachments(aggregationPeriod.getCodeName());
	}
	
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy