package com.hithomelabs.princeton1.module7;

import com.hithomelabs.princeton1.module5.MeasurableSort;
import com.hithomelabs.princeton1.module5.SortingMetaData;

import java.util.Comparator;


    public class Quick<E> implements MeasurableSort<E> {
    @Override
    public void sort(E[] arr) {
        int N = arr.length;
        quickSort(arr, 0, N - 1, null, null);
    }

    public void altSort(E[] arr) {
        int N = arr.length;
        altQuickSort(arr, 0, N-1);
    }

    private void altQuickSort(E[] arr, int lo, int hi) {
        if (lo >= hi) return;
        int i = lo + 1;
        int j = i;
        while(j <= hi){
            if(less((Comparable<E>) arr[j], arr[lo])){
                exch(arr, i, j);
                i++;
            }
            j++;
        }
        exch(arr, i-1, lo);
        altQuickSort(arr, lo, i-2);
        altQuickSort(arr, i, hi);
    }

    private void quickSort(E[] arr, int lo, int hi, Comparator<E> cmp, SortingMetaData metaData) {

        if (lo >= hi) return;
        int i = lo;
        int j = hi+1;
        while(true){
            while(less( arr[++i], arr[lo], cmp, metaData)){
                if(i == hi) break;
            }
            while(!less(arr[--j], arr[lo], cmp, metaData)){
                if (j == lo ) break;
            }
            if(j<=i) break;
            exch(arr, i , j, metaData);
        }
        exch(arr, j, lo, metaData);
        quickSort(arr, lo, j-1, cmp, metaData);
        quickSort(arr, j+1, hi, cmp, metaData);

    }

    @Override
    public void sort(E[] arr, Comparator<E> cmp) {
        int N = arr.length;
        quickSort(arr, 0, N - 1, cmp, null);
    }

    public void sort(E[] arr, Comparator<E> cmp, SortingMetaData metaData) {
        if(metaData != null){
            metaData.startTime();
        }
        int N = arr.length;
        quickSort(arr, 0, N - 1, cmp, metaData);
        if (metaData != null)
            metaData.endTime();
    }
}
