/*
 * Copyright (c) 2014, Oracle America, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 *  * Neither the name of Oracle nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package SortTest;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.Random;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

// Dans test:  /usr/local/apache-maven-3.2.5/bin/mvn clean install
// ou à la racine sur aquitaine
// ou (sur le mac mini) /usr/local/bin/mvn clean install
// Dans test: java -Djmh.ignoreLock=true -jar target/benchmarks.jar 

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(1)
public class MyBenchmark {
    //private int nbr = 20000000;
        @Param({"10000", "20000", "30000", "40000", "50000", "60000", "70000",
                "80000", "90000", "100000", "110000", "120000", "130000", "140000",
                 "150000", "160000", "170000", "180000", "190000", "200000", "210000",
                 "220000", "230000", "240000", "250000", "260000", "270000", "280000",
                 "290000", "300000", "310000", "320000", "330000", "340000", "350000",
                 "360000", "370000", "380000", "390000", "400000", "410000", "420000",
                 "430000", "440000", "450000", "460000", "470000", "480000", "490000",
                 "500000"})
    public int size;    

    private double[] array;
    private Double[] arrayD;
    private Double[] arrayDcopy;
	private double[] alea;
	private double[] alea_sorted;
	private double[] alea_biased;
	private double key;
	private double key_sorted;
	private double key_biased;
	private int cpt;
    private Random myRand;

  
	
	@Setup(Level.Iteration)
    public void prepare() {
        array = new double[size];
		alea = new double[size];
		alea_sorted = new double[size];
		//alea_biased = new double[size];
		
		for (int i = 0; i < size; i++) {
			array[i]=Math.random();
		}
		Arrays.sort(array);
		
		for (int i = 0; i < size; i++) {
			alea[i]=Math.random();
		}
		alea_sorted = Arrays.copyOf(alea, size);
		Arrays.sort(alea_sorted);
		
		// for (int i = 0; i < size; i++) {
		// 	alea_biased[i]=alea[i]*0.5;
		// }
		
		cpt=0;
	}


    //@Setup(Level.Trial)
    public void prepareTrial(){ 
        myRand= new Random(658201546);   
    }

    private static void printArray(Double[] a){
        for(Double d : a){
            System.out.print(d + " ");
        }
        System.out.println();
    }

    //@Setup(Level.Iteration)
    public void prepare2() {
        arrayD = new Double[size];
       
        for (int i = 0; i < size; i++) {
            arrayD[i]=new Double(myRand.nextDouble());
        }

        //printArray(arrayD);
    }

    //@Setup(Level.Invocation)
    public void prep2() {
        arrayDcopy = Arrays.copyOf(arrayD,size);
        //printArray(arrayDcopy);
    }

    //@TearDown(Level.Iteration)
    public void end2() {
        printArray(arrayDcopy);
    }

	
	@Setup(Level.Invocation)
	public void incCpt() {
		key=alea[cpt];
		//key_sorted=alea_sorted[cpt];
		//key_biased=alea_biased[cpt];
		cpt=(cpt+1)%size;
	}
  
    // @Benchmark
    // @BenchmarkMode(Mode.AverageTime)
    // @Warmup(iterations = 5)
    // @Measurement(iterations = 10)
    // public int measureSkewSearch() throws InterruptedException {
    // 	return Search.skewSearch(array, key);
    // }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    @Measurement(iterations = 10)
    public int measureSuperSkewSearch() throws InterruptedException {
        return Search.superSkewSearch(array, key);
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    @Measurement(iterations = 10)
    public int measureBinarySearch() throws InterruptedException {
    	return Search.bSearch(array, key);
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 5)
    @Measurement(iterations = 10)
    public int measureBiasedBinarySearch() throws InterruptedException {
        return Search.biasedBSearch(array, key);
    }


}
