// Path: src/main/java/io/rainfall/statistics/StatisticsHolder.java
// public abstract class StatisticsHolder<E extends Enum<E>> {
// 
//   public abstract Enum<E>[] getResultsReported();
// 
//   public abstract Set<String> getStatisticsKeys();
// 
//   public abstract Statistics<E> getStatistics(String name);
// 
//   public abstract Set<StatisticsCollector> getStatisticsCollectors();
// 
//   public abstract Histogram fetchHistogram(final Enum<E> result);
// 
//   public abstract void reset();
// 
//   public abstract long getCurrentTps(Enum result);
// 
//   public abstract void record(String name, long responseTimeInNs, Enum result);
// 
//   public abstract void increaseAssertionsErrorsCount(String name);
// 
//   public abstract void pause();
// 
//   public abstract void resume();
// 
//   public long getTimeInNs() {
//     return System.nanoTime();
//   }
// 
//   public abstract long getStartTime();
// }
// 
// Path: src/main/java/io/rainfall/utils/ConcurrentPseudoRandom.java
// public class ConcurrentPseudoRandom {
// 
//   private final ThreadLocal<RandomFunction> randomFunction = new ThreadLocal<RandomFunction>() {
//     protected RandomFunction initialValue() {
//       return new RandomFunction();
//     }
//   };
// 
//   private RandomFunction getRandomFunction() {
//     return randomFunction.get();
//   }
// 
//   public long nextLong() {
//     return getRandomFunction().nextLong();
//   }
// 
//   public long nextLong(final long seed) {
//     return getRandomFunction().nextLong(seed);
//   }
// 
//   public float nextFloat() {
//     return getRandomFunction().nextFloat();
//   }
// 
//   public float nextFloat(final long seed) {
//     return getRandomFunction().nextFloat(seed);
//   }
// 
//   public float nextFloat(float max) {
//     return max * getRandomFunction().nextFloat();
//   }
// 
//   private class RandomFunction {
// 
//     long seed = 8682522807148012L ^ System.nanoTime();
// 
//     public long nextLong() {
//       long nb = nextLong(this.seed);
//       this.seed = this.seed * 181783497276652981L;
//       return nb;
//     }
// 
//     public long nextLong(long seed) {
//       seed ^= (seed << 21);
//       seed ^= (seed >>> 35);
//       seed ^= (seed << 4);
//       return seed;
//     }
// 
//     public float nextFloat() {
//       float nb = nextFloat(this.seed);
//       this.seed = this.seed * 181783497276652981L;
//       return nb;
//     }
// 
//     //  Float.intBitsToFloat(nextInt()) ???
//     public float nextFloat(final long next) {
//       return Math.abs(((nextLong(next)) % 100000) / 100000f);
//     }
//   }
// }
// 
// Path: src/main/java/io/rainfall/utils/RangeMap.java
// public class RangeMap<E> {
// 
//   private final Map<Float, E> values = new HashMap<Float, E>();
//   private final List<Range> keys = new LinkedList<Range>();
//   private Float higherBound = 0.0f;
//   private final ConcurrentPseudoRandom rnd = new ConcurrentPseudoRandom();
// 
//   public synchronized void put(final Float weight, final E value) {
//     if (weight > 0) {
//       values.put(higherBound, value);
//       keys.add(new Range(higherBound, higherBound + weight, higherBound));
//       higherBound += weight;
//     }
//   }
// 
//   public E get(final float key) {
//     for (Range range : keys) {   // the Iterator is way better for the LinkedList that doesn't implement RandomAccess
//       if (range.contains(key))
//         return values.get(range.getKey());
//     }
//     return null;
//   }
// 
//   public Float getHigherBound() {
//     return higherBound;
//   }
// 
//   public Collection<E> getAll() {
//     return values.values();
//   }
// 
//   public E getNextRandom(ConcurrentPseudoRandom concurrentPseudoRandom) {
//     return get(concurrentPseudoRandom.nextFloat(higherBound));
//   }
// 
//   public class Range {
//     private float low;
//     private float high;
//     private Float key;
// 
//     public Range(final float low, final float high, final Float key) {
//       this.low = low;
//       this.high = high;
//       this.key = key;
//     }
// 
//     public boolean contains(final float key) {
//       return (this.low <= key && this.high > key);
//     }
// 
//     public Float getKey() {
//       return key;
//     }
//   }
// }


import io.rainfall.statistics.StatisticsHolder;
import io.rainfall.utils.ConcurrentPseudoRandom;
import io.rainfall.utils.RangeMap;
import java.util.List;
import java.util.Map;
/*
 * Copyright (c) 2014-2022 Aurélien Broszniowski
 *
 * 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 io.rainfall;



/**
 * This executes a {@link Scenario}, with the specific {@link Configuration}, and {@link Assertion}
 *
 * @author Aurelien Broszniowski
 */

public abstract class Execution {

  public enum ExecutionState {
    UNKNOWN,
    BEGINNING,
    ENDING
  }

  /**
   * Provide an easy way to mark all operations as underway.
   *
   * @param scenario the test scenario
   * @param state    phase of execution of the scenario
   */
  public void markExecutionState(Scenario scenario, ExecutionState state) {
// Path: src/main/java/io/rainfall/statistics/StatisticsHolder.java
// public abstract class StatisticsHolder<E extends Enum<E>> {
// 
//   public abstract Enum<E>[] getResultsReported();
// 
//   public abstract Set<String> getStatisticsKeys();
// 
//   public abstract Statistics<E> getStatistics(String name);
// 
//   public abstract Set<StatisticsCollector> getStatisticsCollectors();
// 
//   public abstract Histogram fetchHistogram(final Enum<E> result);
// 
//   public abstract void reset();
// 
//   public abstract long getCurrentTps(Enum result);
// 
//   public abstract void record(String name, long responseTimeInNs, Enum result);
// 
//   public abstract void increaseAssertionsErrorsCount(String name);
// 
//   public abstract void pause();
// 
//   public abstract void resume();
// 
//   public long getTimeInNs() {
//     return System.nanoTime();
//   }
// 
//   public abstract long getStartTime();
// }
// 
// Path: src/main/java/io/rainfall/utils/ConcurrentPseudoRandom.java
// public class ConcurrentPseudoRandom {
// 
//   private final ThreadLocal<RandomFunction> randomFunction = new ThreadLocal<RandomFunction>() {
//     protected RandomFunction initialValue() {
//       return new RandomFunction();
//     }
//   };
// 
//   private RandomFunction getRandomFunction() {
//     return randomFunction.get();
//   }
// 
//   public long nextLong() {
//     return getRandomFunction().nextLong();
//   }
// 
//   public long nextLong(final long seed) {
//     return getRandomFunction().nextLong(seed);
//   }
// 
//   public float nextFloat() {
//     return getRandomFunction().nextFloat();
//   }
// 
//   public float nextFloat(final long seed) {
//     return getRandomFunction().nextFloat(seed);
//   }
// 
//   public float nextFloat(float max) {
//     return max * getRandomFunction().nextFloat();
//   }
// 
//   private class RandomFunction {
// 
//     long seed = 8682522807148012L ^ System.nanoTime();
// 
//     public long nextLong() {
//       long nb = nextLong(this.seed);
//       this.seed = this.seed * 181783497276652981L;
//       return nb;
//     }
// 
//     public long nextLong(long seed) {
//       seed ^= (seed << 21);
//       seed ^= (seed >>> 35);
//       seed ^= (seed << 4);
//       return seed;
//     }
// 
//     public float nextFloat() {
//       float nb = nextFloat(this.seed);
//       this.seed = this.seed * 181783497276652981L;
//       return nb;
//     }
// 
//     //  Float.intBitsToFloat(nextInt()) ???
//     public float nextFloat(final long next) {
//       return Math.abs(((nextLong(next)) % 100000) / 100000f);
//     }
//   }
// }
// 
// Path: src/main/java/io/rainfall/utils/RangeMap.java
// public class RangeMap<E> {
// 
//   private final Map<Float, E> values = new HashMap<Float, E>();
//   private final List<Range> keys = new LinkedList<Range>();
//   private Float higherBound = 0.0f;
//   private final ConcurrentPseudoRandom rnd = new ConcurrentPseudoRandom();
// 
//   public synchronized void put(final Float weight, final E value) {
//     if (weight > 0) {
//       values.put(higherBound, value);
//       keys.add(new Range(higherBound, higherBound + weight, higherBound));
//       higherBound += weight;
//     }
//   }
// 
//   public E get(final float key) {
//     for (Range range : keys) {   // the Iterator is way better for the LinkedList that doesn't implement RandomAccess
//       if (range.contains(key))
//         return values.get(range.getKey());
//     }
//     return null;
//   }
// 
//   public Float getHigherBound() {
//     return higherBound;
//   }
// 
//   public Collection<E> getAll() {
//     return values.values();
//   }
// 
//   public E getNextRandom(ConcurrentPseudoRandom concurrentPseudoRandom) {
//     return get(concurrentPseudoRandom.nextFloat(higherBound));
//   }
// 
//   public class Range {
//     private float low;
//     private float high;
//     private Float key;
// 
//     public Range(final float low, final float high, final Float key) {
//       this.low = low;
//       this.high = high;
//       this.key = key;
//     }
// 
//     public boolean contains(final float key) {
//       return (this.low <= key && this.high > key);
//     }
// 
//     public Float getKey() {
//       return key;
//     }
//   }
// }


// Path: src/main/java/io/rainfall/Execution.java
import io.rainfall.statistics.StatisticsHolder;
import io.rainfall.utils.ConcurrentPseudoRandom;
import io.rainfall.utils.RangeMap;
import java.util.List;
import java.util.Map;

/*
 * Copyright (c) 2014-2022 Aurélien Broszniowski
 *
 * 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 io.rainfall;



/**
 * This executes a {@link Scenario}, with the specific {@link Configuration}, and {@link Assertion}
 *
 * @author Aurelien Broszniowski
 */

public abstract class Execution {

  public enum ExecutionState {
    UNKNOWN,
    BEGINNING,
    ENDING
  }

  /**
   * Provide an easy way to mark all operations as underway.
   *
   * @param scenario the test scenario
   * @param state    phase of execution of the scenario
   */
  public void markExecutionState(Scenario scenario, ExecutionState state) {
    final Map<String, RangeMap<WeightedOperation>> scenarioOperations = scenario.getOperations();