content: /**
   * Copyright 2020 Alexander Herzog
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package simulator.elements;
  
  import java.util.Arrays;
  
  import simulator.coreelements.RunElement;
  import simulator.coreelements.RunElementData;
  import simulator.runmodel.SimulationData;
  import statistics.StatisticsDataPerformanceIndicator;
  import statistics.StatisticsMultiPerformanceIndicator;
  
  /**
   * Laufzeitdaten eines {@link RunElementCounterBatch}-Laufzeit-Objekts
   * @author Alexander Herzog
   * @see RunElementCounterBatch
   * @see RunElementData
   */
  public class RunElementCounterBatchData extends RunElementData {
  	/**
  	 * Name des Zhlers
  	 */
  	private final String counterName;
  
  	/** Zustzliche Bedingung, die fr die Zhlung eines Kunden erfllt sein muss */
  	public final RunCounterConditionData condition;
  
  	/**
  	 * Zugehriges Statistikobjekt
  	 */
  	private final StatisticsMultiPerformanceIndicator counterBatchStatistic;
  
  	/**
  	 * Einzelne Zhler fr schnelleren Zugriff
  	 */
  	public StatisticsDataPerformanceIndicator[] indicators;
  
  	/**
  	 * Letzter Ankunftszeitpunkt (bezogen auf bestimmten Batch-Gren)
  	 */
  	private double[] lastArrivalByBatchSize;
  
  	/**
  	 * Letzter Ankunftszeitpunkt (bezogen auf einen Kunden)
  	 */
  	private long lastArrival=-1;
  
  	/**
  	 * Anzahl der Kunden, deren gleichzeitige Ankunft bereits gezhlt wurde
  	 */
  	private int count=0;
  
  	/**
  	 * Konstruktor der Klasse {@link RunElementCounterBatchData}
  	 * @param station	Station zu diesem Datenelement
  	 * @param counterName	Name des Zhlers
  	 * @param condition	Zustzliche Bedingung, die fr die Zhlung eines Kunden erfllt sein muss
  	 * @param counterBatchStatistic	Zugehriges Statistikobjekt
  	 * @param simData	Simulationsdatenobjekt
  	 */
  	public RunElementCounterBatchData(final RunElement station, final String counterName, final RunCounterConditionData condition, final StatisticsMultiPerformanceIndicator counterBatchStatistic, final SimulationData simData) {
  		super(station,simData);
  		this.counterName=counterName;
  		this.condition=condition;
  		this.counterBatchStatistic=counterBatchStatistic;
  		indicators=null;
  	}
  
  	/**
  	 * Um wie viel (mehr) soll das {@link #indicators}-Array bei jeder Vergrerung
  	 * wachsen (um so hufige Neuallokationen zu vermeiden)?
  	 */
  	private static final int ADDITIONAL_GROW_SIZE=10;
  
  	/**
  	 * Erfasst die Ankunft eines Batches
  	 * @param time	Ankunftszeitpunkt (in Sekunden)
  	 * @param batchSize	Batch-Gre
  	 */
  	private void logBatch(final double time, final int batchSize) {
  		if (lastArrivalByBatchSize==null) lastArrivalByBatchSize=new double[batchSize+1+ADDITIONAL_GROW_SIZE];
  		if (lastArrivalByBatchSize.length<=batchSize) lastArrivalByBatchSize=Arrays.copyOf(lastArrivalByBatchSize,batchSize+1+ADDITIONAL_GROW_SIZE);
  
  		if (indicators==null) indicators=new StatisticsDataPerformanceIndicator[batchSize+1+ADDITIONAL_GROW_SIZE];
  		if (indicators.length<=batchSize) indicators=Arrays.copyOf(indicators,batchSize+1+ADDITIONAL_GROW_SIZE);
  
  		/* Allgemeine Zhlung des Batches */
  		if (indicators[0]==null) indicators[0]=(StatisticsDataPerformanceIndicator)counterBatchStatistic.get(counterName);
  		if (lastArrivalByBatchSize[0]>0 && time>lastArrivalByBatchSize[0]) indicators[0].add(time-lastArrivalByBatchSize[0]);
  		lastArrivalByBatchSize[0]=time;
  
  		/* Batch-Gren-abhngige Zhlung */
  		if (indicators[batchSize]==null) indicators[batchSize]=(StatisticsDataPerformanceIndicator)counterBatchStatistic.get(counterName+" batch="+batchSize);
  		if (lastArrivalByBatchSize[batchSize]>0 && time>lastArrivalByBatchSize[batchSize]) indicators[batchSize].add(time-lastArrivalByBatchSize[batchSize]);
  		lastArrivalByBatchSize[batchSize]=time;
  	}
  
  	/**
  	 * Erfasst eine Kundenankunft und zhlt dann ggf. entsprechend einen Batch
  	 * @param isWarmUp	Befinden wir uns noch in der Einschwingphase?
  	 * @param time	Ankunftszeitpunkt (in MS)
  	 * @param simData	Simulationsdatenobjekt
  	 */
  	public void logArrival(final boolean isWarmUp, final long time, final SimulationData simData) {
  		if (time<lastArrival || lastArrival==-1) {
  			/* Neuer Tag */
  			lastArrival=-1;
  			count=0;
  		}
  
  		if (time==lastArrival && lastArrival!=-1) {
  			/* Ankunft zhlen */
  			count++;
  		} else {
  			/* Neuer Zeitpunkt: Batch zhlen, neuen Batch starten */
  			if (!isWarmUp && count>0) logBatch(lastArrival*simData.runModel.scaleToSeconds,count);
  			count=1;
  		}
  
  		lastArrival=time;
  	}
  }