content: package net.anotheria.moskito.core.predefined;
  
  import net.anotheria.moskito.core.producers.AbstractStats;
  import net.anotheria.moskito.core.stats.Interval;
  import net.anotheria.moskito.core.stats.StatValue;
  import net.anotheria.moskito.core.stats.TimeUnit;
  import net.anotheria.moskito.core.stats.impl.StatValueFactory;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * Stats for a QueuingSystem like the Enterpise Queue Processor in ano-prise.
   */
  public class QueuingSystemStats extends AbstractStats {
  
  	/**
  	 * Stat definition enum.
  	 */
  	static enum StatDef{
  		
  		SERVERS_SIZE("SS"),
  		/**
  		 * Size of the queue.
  		 */
  		QUEUE_SIZE("QS"),
  		/**
  		 * Number of arrived elements,
  		 */
  		ARRIVED("Arr"),
  		/**
  		 * Number of served elements.
  		 */
  		SERVICED("Serv"),
  		/**
  		 * Number of errors.
  		 */
  		ERRORS("Err"),
  		/**
  		 * Number of waiting times.
  		 */
  		WAITED("Wait"),
  		/**
  		 * Number of thrown away elements.
  		 */
  		THROWN_AWAY("Thr"),
  		/**
  		 * Time spent by item waiting for service.
  		 */
  		WAITING_TIME("WT"),
  		/**
  		 * Min time spent by an item waiting for service.
  		 */
  		WAITING_TIME_MIN("WTm"),
  		/**
  		 * Max time spent by an item waiting for service.
  		 */
  		WAITING_TIME_MAX("WTM"),
  		/**
  		 * Average time spent by an item waiting for service.
  		 */
  		WAITING_TIME_AVG("WTA"),
  		/**
  		 * Time spent by the item in servicing.
  		 */
  		SERVICE_TIME("ST"),
  		/**
  		 * Min time spent by the item in servicing.
  		 */
  		SERVICE_TIME_MIN("STm"),
  		/**
  		 * Max  time spent by the item in servicing.
  		 */
  		SERVICE_TIME_MAX("STM"),
  		/**
  		 * Average time spent in service
  		 */
  		SERVICE_TIME_AVG("STA");
  
  		/**
  		 * Name of the stat object.
  		 */
  		private String statName;
  
  		private StatDef(String aStatName){
  			statName = aStatName;
  		}
  		
  		public String getStatName(){
  			return statName;
  		}
  		
  		public String getStatLabel(){
  			return ' ' + statName + ": ";
  		}
  		
  		public static List<String> getStatNames(){
  			List<String> ret = new ArrayList<String>(StatDef.values().length);
  			for(StatDef v: StatDef.values())
  				ret.add(v.getStatName());
  			return ret;
  		}
  	}	
  	
  	/**
  	 * Min size value.
  	 */
  	public static final long MIN_SIZE_DEFAULT = Long.MAX_VALUE;
  	/**
  	 * Max size value.
  	 */
  	public static final long MAX_SIZE_DEFAULT = 0L;
  
  
  	/**
  	 * Number of processors that process queue elements.
  	 */
  	private StatValue serversSize;
  	/**
  	 * Size of the queue.
  	 */
  	private StatValue queueSize;
  	/**
  	 * Number of arrived elements.
  	 */
  	private StatValue arrived;
  	/**
  	 * Number of served elements.
  	 */
  	private StatValue serviced;
  	/**
  	 * Number of serving errors.
  	 */
  	private StatValue errors;
  	/**
  	 * Number of waited elements.
  	 */
  	private StatValue waited;
  	/**
  	 * Number of throwed away elements due to overflow.
  	 */
  	private StatValue throwedAway;
  	/**
  	 * Time spent in the queue before processing started.
  	 */
  	private StatValue waitingTime;
  	/**
  	 * Min time spent in the queue before processing started.
  	 */
  	private StatValue waitingTimeMin;
  	/**
  	 * Max time spent in the queue before processing started.
  	 */
  	private StatValue waitingTimeMax;
  	/**
  	 * Time spent in servicing the requests.
  	 */
  	private StatValue servicingTime;
  	/**
  	 * Min time spent in servicing the requests.
  	 */
  	private StatValue servicingTimeMin;
  	/**
  	 * Max time spent in servicing the requests.
  	 */
  	private StatValue servicingTimeMax;
  
  	
  	/**
  	 * Name of the cache.
  	 */
  	private String name;
  
  	public QueuingSystemStats(){
  		this("unnamed", Constants.getDefaultIntervals());
  	}
  	
  	public QueuingSystemStats(String name){
  		this(name, Constants.getDefaultIntervals());
  	} 
  	
  	
  	public QueuingSystemStats(String aName,  Interval[] selectedIntervals){
  		Long longPattern = Long.valueOf(0);
  		name = aName;
  		
  		serversSize = StatValueFactory.createStatValue(longPattern, "serversSize", selectedIntervals);
  		queueSize = StatValueFactory.createStatValue(longPattern, "queueSize", selectedIntervals);
  		arrived = StatValueFactory.createStatValue(longPattern, "arrived", selectedIntervals);
  		serviced = StatValueFactory.createStatValue(longPattern, "serviced", selectedIntervals);
  		errors = StatValueFactory.createStatValue(longPattern, "errors", selectedIntervals);
  		waited = StatValueFactory.createStatValue(longPattern, "waited", selectedIntervals);
  		throwedAway = StatValueFactory.createStatValue(longPattern, "throwedAway", selectedIntervals);
  		waitingTime = StatValueFactory.createStatValue(longPattern, "waitingTime", selectedIntervals);
  		waitingTimeMin = StatValueFactory.createStatValue(longPattern, "waitingTimeMin", selectedIntervals);
  		waitingTimeMin.setDefaultValueAsLong(Constants.MIN_TIME_DEFAULT);
  		waitingTimeMin.reset();
  		waitingTimeMax = StatValueFactory.createStatValue(longPattern, "waitingTimeMax", selectedIntervals);
  		waitingTimeMax.setDefaultValueAsLong(Constants.MAX_TIME_DEFAULT);
  		waitingTimeMax.reset();
  		servicingTime = StatValueFactory.createStatValue(longPattern, "servicingTime", selectedIntervals);
  		servicingTimeMin = StatValueFactory.createStatValue(longPattern, "servicingTimeMin", selectedIntervals);
  		servicingTimeMin.setDefaultValueAsLong(Constants.MIN_TIME_DEFAULT);
  		servicingTimeMin.reset();
  		servicingTimeMax = StatValueFactory.createStatValue(longPattern, "servicingTimeMax", selectedIntervals);
  		servicingTimeMax.setDefaultValueAsLong(Constants.MAX_TIME_DEFAULT);
  		servicingTimeMax.reset();
  
  		addStatValues(serversSize, queueSize, arrived, serviced, errors, waited, throwedAway, waitingTime, waitingTimeMin,
  				waitingTimeMax, servicingTime, servicingTimeMin, servicingTimeMax);
  	
  	}
  	
  	public void setServersSize(int size){
  		serversSize.setValueAsLong(size);
  	}
  	
  	public long getServersSize(String intervalName){
  		return serversSize.getValueAsLong();
  	}
  	
  	public void setQueueSize(int size){
  		queueSize.setValueAsLong(size);
  	}
  	
  	public long getQueueSize(String intervalName){
  		return queueSize.getValueAsLong();
  	}
  	
  	public void addArrived(){
  		arrived.increase();
  	}
  	
  	public long getArrived(String intervalName){
  		return arrived.getValueAsLong(intervalName);
  	}
  	
  	public void addServiced(){
  		serviced.increase();
  	}
  	
  	public long getServiced(String intervalName){
  		return serviced.getValueAsLong(intervalName);
  	}
  	
  	public void addError(){
  		errors.increase();
  	}
  	
  	public long getErrors(String intervalName){
  		return errors.getValueAsLong(intervalName);
  	}
  	
  	public void addWaited(){
  		waited.increase();
  	}
  	
  	public long getWaited(String intervalName){
  		return waited.getValueAsLong(intervalName);
  	}
  	
  	public void addThrowedAway(){
  		throwedAway.increase();
  	}
  	
  	public long getThrowedAway(String intervalName){
  		return throwedAway.getValueAsLong(intervalName);
  	}
  	
  	public void addWaitingTime(long time){
  		waitingTime.increaseByLong(time);
  		waitingTimeMin.setValueIfLesserThanCurrentAsLong(time);
  		waitingTimeMax.setValueIfGreaterThanCurrentAsLong(time);
  	}
  	
  	public long getWaitingTime(String intervalName){
  		return waitingTime.getValueAsLong(intervalName);
  	}
  	
  	public long getWaitingTimeMin(String intervalName){
  		return waitingTimeMin.getValueAsLong(intervalName);
  	}
  	
  	public long getWaitingTimeMax(String intervalName){
  		return waitingTimeMax.getValueAsLong(intervalName);
  	}
  	
  	public long getWaitingTimeAverage(String intervalName){
  		long waitedVal = waited.getValueAsLong(intervalName);
  		return waitedVal > 0? waitingTime.getValueAsLong(intervalName) / waitedVal: Constants.AVERAGE_TIME_DEFAULT;
  	}
  	
  	public void addServicingTime(long time){
  		servicingTime.increaseByLong(time);
  		servicingTimeMin.setValueIfLesserThanCurrentAsLong(time);
  		servicingTimeMax.setValueIfGreaterThanCurrentAsLong(time);
  	}
  	
  	public long getServicingTime(String intervalName){
  		return servicingTime.getValueAsLong(intervalName);
  	}
  	
  	public long getServicingTimeMin(String intervalName){
  		return servicingTimeMin.getValueAsLong(intervalName);
  	}
  	
  	public long getServicingTimeMax(String intervalName){
  		return servicingTimeMax.getValueAsLong(intervalName);
  	}
  	
  	public long getServicingTimeAverage(String intervalName){
  		long servicedVal = serviced.getValueAsLong(intervalName);
  		return servicedVal > 0? servicingTime.getValueAsLong(intervalName) / servicedVal: Constants.AVERAGE_TIME_DEFAULT;
  	}
  	
  	public String getName(){
  		return name;
  	}
  	
  	@Override
  	public List<String> getAvailableValueNames() {
  		return StatDef.getStatNames();
  	}
  
  	private String transformMinTimeNanos(long minTime, TimeUnit timeUnit){
  		if (minTime == Constants.MIN_TIME_DEFAULT)
  			return "NoR";
  			
  		return String.valueOf(timeUnit.transformNanos(minTime));
  	}
  	
  	private String transformMaxTimeNanos(long maxTime, TimeUnit timeUnit){
  		if (maxTime == Constants.MAX_TIME_DEFAULT)
  			return "NoR";
  			
  		return String.valueOf(timeUnit.transformNanos(maxTime));
  	}
  	
  	private String transformAverageTimeNanos(long maxTime, TimeUnit timeUnit){
  		if (maxTime == Constants.AVERAGE_TIME_DEFAULT)
  			return "NoR";
  			
  		return String.valueOf(timeUnit.transformNanos(maxTime));
  	}
  	
  	@Override public String toStatsString(String intervalName, TimeUnit timeUnit) {
  		StringBuilder b = new StringBuilder();
  		b.append(getName()).append(' ');
  		
  		b.append(StatDef.SERVERS_SIZE.getStatLabel()).append(getServersSize(intervalName));
  		b.append(StatDef.QUEUE_SIZE.getStatLabel()).append(getQueueSize(intervalName));
  		b.append(StatDef.ARRIVED.getStatLabel()).append(getArrived(intervalName));
  		b.append(StatDef.SERVICED.getStatLabel()).append(getServiced(intervalName));
  		b.append(StatDef.ERRORS.getStatLabel()).append(getErrors(intervalName));
  		b.append(StatDef.WAITED.getStatLabel()).append(getWaited(intervalName));
  		b.append(StatDef.THROWN_AWAY.getStatLabel()).append(getThrowedAway(intervalName));
  		b.append(StatDef.WAITING_TIME.getStatLabel()).append(timeUnit.transformNanos(getWaitingTime(intervalName)));
  		b.append(StatDef.WAITING_TIME_MIN.getStatLabel()).append(transformMinTimeNanos(getWaitingTimeMin(intervalName), timeUnit));
  		b.append(StatDef.WAITING_TIME_MAX.getStatLabel()).append(transformMaxTimeNanos(getWaitingTimeMax(intervalName),timeUnit));
  		b.append(StatDef.WAITING_TIME_AVG.getStatLabel()).append(transformAverageTimeNanos(getWaitingTimeAverage(intervalName), timeUnit));
  		b.append(StatDef.SERVICE_TIME.getStatLabel()).append(timeUnit.transformNanos(getServicingTime(intervalName)));
  		b.append(StatDef.SERVICE_TIME_MIN.getStatLabel()).append(transformMinTimeNanos(getServicingTimeMin(intervalName), timeUnit));
  		b.append(StatDef.SERVICE_TIME_MAX.getStatLabel()).append(transformMaxTimeNanos(getServicingTimeMax(intervalName),timeUnit));
  		b.append(StatDef.SERVICE_TIME_AVG.getStatLabel()).append(transformAverageTimeNanos(getServicingTimeAverage(intervalName), timeUnit));
  
  		return b.toString();
  	}
  
  	@Override public String getValueByNameAsString(String valueName, String intervalName, TimeUnit timeUnit){
  		
  		if (valueName==null || valueName.isEmpty())
  			throw new AssertionError("Value name can not be empty");
  		
  		if (valueName.equals(StatDef.SERVERS_SIZE.getStatName()))
  			return String.valueOf(getServersSize(intervalName));
  		
  		if (valueName.equals(StatDef.QUEUE_SIZE.getStatName()))
  			return String.valueOf(getQueueSize(intervalName));
  		
  		if (valueName.equals(StatDef.ARRIVED.getStatName()))
  			return String.valueOf(getArrived(intervalName));
  		
  		if (valueName.equals(StatDef.SERVICED.getStatName()))
  			return String.valueOf(getServiced(intervalName));
  		
  		if (valueName.equals(StatDef.ERRORS.getStatName()))
  			return String.valueOf(getErrors(intervalName));
  		
  		if (valueName.equals(StatDef.WAITED.getStatName()))
  			return String.valueOf(getWaited(intervalName));
  		
  		if (valueName.equals(StatDef.THROWN_AWAY.getStatName()))
  			return String.valueOf(getThrowedAway(intervalName));
  		
  		if (valueName.equals(StatDef.WAITING_TIME.getStatName()))
  			return String.valueOf(timeUnit.transformNanos(getWaitingTime(intervalName)));
  		
  		if (valueName.equals(StatDef.WAITING_TIME_MIN.getStatName()))
  			return transformMinTimeNanos(getWaitingTimeMin(intervalName), timeUnit);
  		
  		if (valueName.equals(StatDef.WAITING_TIME_MAX.getStatName()))
  			return transformMaxTimeNanos(getWaitingTimeMax(intervalName), timeUnit);
  		
  		if (valueName.equals(StatDef.WAITING_TIME_AVG.getStatName()))
  			return transformAverageTimeNanos(getWaitingTimeAverage(intervalName), timeUnit);
  		
  		if (valueName.equals(StatDef.SERVICE_TIME.getStatName()))
  			return String.valueOf(timeUnit.transformNanos(getServicingTime(intervalName)));
  		
  		if (valueName.equals(StatDef.SERVICE_TIME_MIN.getStatName()))
  			return transformMinTimeNanos(getServicingTimeMin(intervalName), timeUnit);
  		
  		if (valueName.equals(StatDef.SERVICE_TIME_MAX.getStatName()))
  			return transformMaxTimeNanos(getServicingTimeMax(intervalName), timeUnit);
  		
  		if (valueName.equals(StatDef.SERVICE_TIME_AVG.getStatName()))
  			return transformAverageTimeNanos(getServicingTimeAverage(intervalName), timeUnit);
  		
  		return super.getValueByNameAsString(valueName, intervalName, timeUnit);
  	}
  
  }
  