package sort;

import java.util.*;
import java.text.DecimalFormat;
import java.util.Arrays;

public class Utility {
    
    private static Random rand = new Random();
    private static DecimalFormat fmt = new DecimalFormat(".000");
    
    // Make an array of random integers between 0 and 10n
    public static int[] makeIntArray(int n) {
        int[] array = new int[n];
        for (int i = 0; i < n; i++)
            array[i] = rand.nextInt(10 * n + 1);
        return array;
    }
    
    public static Double[] makeDoubleArray(int n) {
        Double[] array = new Double[n];
        for (int i = 0; i < n; i++)
            array[i] = new Double(rand.nextDouble());
        return array;
    }
    
    public static int[] cloneArray(int[] array) {
        int[] newArray = new int[array.length];
        for (int i=0;i<array.length;i++)
            newArray[i] = array[i];
        return newArray;
    }
    
    public static Double[] cloneArray(Double[] array) {
        Double[] newArray = new Double[array.length];
        for (int i=0;i<array.length;i++)
            newArray[i] = array[i];
        return newArray;
    }

    public static void show(int[] array) {
        System.out.print("[");
        for (int i = 0; i < array.length - 1; i++)
            System.out.print(array[i] + ", ");
        System.out.println(array[array.length - 1] + "]");
    }
    
    public static void show(Double[] array) {
        System.out.print("[");
        for (int i = 0; i < array.length - 1; i++)
            System.out.print(format(array[i]) + ", ");
        System.out.println(format(array[array.length - 1]) + "]");
    }
    
    public static String format(Double f) {
        return fmt.format(f.doubleValue());
    }
    
    private static String padLeft(String s, int n) {
        while (s.length() < n)
            s = " " + s;
        return s;
    }
    
    public static String timeSearchHeader() {
        return "           n  found   linear   linear/n" + 
        "    binary  binary/log n  linear/binary\n" +
        "                       (ms.)      (ns.)     (ms.)        (ns.)";
    }
    
    
    // generate a string comparing linear and binary search times
    // all times are in milliseconds
    public static String timeSearch(int n) {
      final double MILLION = 1000000.0;
      long startTime;
      long endTime;
      int pos;
      double linearSearchTime;
      double binarySearchTime;
      double logN;
      String found;
      int[] array;
      int target;
      DecimalFormat dfmt = new DecimalFormat("0.00000");
      DecimalFormat ifmt = new DecimalFormat("#,###");
      array = makeIntArray(n);
      target = 10*n + 1;
      logN = Math.log(n);
      startTime = System.nanoTime();
      pos = Search.linearSearch(array, target);
      endTime = System.nanoTime();
      linearSearchTime = (endTime - startTime)/MILLION;
      Arrays.sort(array);
      startTime = System.nanoTime();
      pos = Search.binarySearch(array, target);
      endTime = System.nanoTime();
      binarySearchTime = (endTime -startTime)/MILLION;
      if (pos >= 0)
          found = "   yes";
      else
          found = "    no";
      return padLeft(ifmt.format(n),12) + found + 
         padLeft(dfmt.format(linearSearchTime),10) + " " + 
         padLeft(dfmt.format(MILLION*linearSearchTime/n),10) + 
         padLeft(dfmt.format(binarySearchTime),10) + "   " +
         padLeft(dfmt.format(MILLION*binarySearchTime/logN),10) + " " +
         padLeft("" + (int)(linearSearchTime/binarySearchTime),7);   
    }
    
    
    public static String timeSortHeader() {
        return "      n   selection  sel/n*n" + 
        "  insertion  ins/n*n" +
        "    Java  Java/n(log n)  ins/\n" +
        "              (ms.)    (ns.)      (ms.)    (ns.)"+
        "    (ms.)     (ns.)      Java";
    }
    
    
    // generate a string comparing selection, insertion, and Java sort times
    // all times are in milliseconds
    public static String timeSort(int n) {
      final double MILLION = 1000000.0;
      long startTime;
      long endTime;
      double selectionSortTime;
      double insertionSortTime;
      double javaSortTime;
      double logN;
      double nsqr;
      double nLogN;
      int[] array1;
      int[] array2;
      int[] array3;
      DecimalFormat dfmt = new DecimalFormat("0.0000");
      DecimalFormat ifmt = new DecimalFormat("#,###");
      array1 = makeIntArray(n);
      array2 = cloneArray(array1);
      array3 = cloneArray(array1);
      logN = Math.log(n);
      nLogN = n * logN;
      nsqr = n*n;
      startTime = System.nanoTime();
      QuadraticSort.selectionSort(array1);
      endTime = System.nanoTime();
      selectionSortTime = (endTime - startTime)/MILLION;
      startTime = System.nanoTime();
      QuadraticSort.insertionSort(array2);
      endTime = System.nanoTime();
      insertionSortTime = (endTime -startTime)/MILLION;
      startTime = System.nanoTime();
      Arrays.sort(array3);
      endTime = System.nanoTime();
      javaSortTime = (endTime -startTime)/MILLION;
      
      return padLeft(ifmt.format(n),7) + " " +
         padLeft(dfmt.format(selectionSortTime),11) + " " + 
         padLeft(dfmt.format(MILLION*selectionSortTime/nsqr),8) + 
         padLeft(dfmt.format(insertionSortTime),11) + " " +
         padLeft(dfmt.format(MILLION*insertionSortTime/nsqr),8) + " " +
         padLeft(dfmt.format(javaSortTime),8) + " " +
         padLeft(dfmt.format(MILLION*javaSortTime/nLogN),9) + " " +
         padLeft("" + (int)(insertionSortTime/javaSortTime),8);   
    }

}

