package com.hithomelabs.princeton1.module7;

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

import java.util.Comparator;

public class ThreeWayQuick<E> implements MeasurableSort<E>, MeasurableHelper {
    @Override
    public void sort(E[] arr) {
        coreSortingLogic(arr, null, null);
    }

    private void coreSortingLogic(E[] arr, Comparator<E> cmp, SortingMetaData metaData) {
        int N = arr.length;
        threeWaySort(arr, 0, N - 1, cmp, metaData);
    }

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

        if (hi <= lo)
            return;
        int k = hi;
        int i = lo + 1;
        int j = lo;

        while (true) {
            if (MeasurableHelper.less(arr[i], arr[j], cmp, metaData)) MeasurableHelper.exch(arr, i++, j++, metaData);
            else if (MeasurableHelper.equals(arr[i],arr[j], cmp, metaData)) i++;
            else MeasurableHelper.exch(arr, i, k--, metaData);
            if (k < i) break;
        }
        threeWaySort(arr, lo, j - 1, cmp, metaData);
        threeWaySort(arr, k + 1, hi, cmp, metaData);
    }

    @Override
    public void sort(E[] arr, Comparator<E> cmp, SortingMetaData metaData) {
        if(metaData != null){
            metaData.startTime();
        }
        coreSortingLogic(arr, cmp, metaData);
        if (metaData != null)
            metaData.endTime();
    }

    @Override
    public void sort(E[] arr, Comparator<E> cmp) {
        coreSortingLogic(arr, cmp, null);
    }

}
