use std::cmp::PartialOrd;

fn median_of_three<T: PartialOrd + Copy>(v: &[T]) -> usize {
    if v.len() < 3 {
        return 0;
    }

    let left = 0;
    let middle = if v.len() % 2 == 0 {
        v.len() / 2 - 1
    } else {
        v.len() / 2
    };
    let right = v.len() - 1;
    let mut values = vec![v[left], v[middle], v[right]];
    bubble_sort(&mut values);
    let median = values[1];
    if median == v[left] {
        return left;
    } else if median == v[middle] {
        return middle;
    } else if median == v[right] {
        return right;
    } else {
        panic!("Did not find median in values!");
    }
}

fn bubble_sort<T: PartialOrd>(v: &mut [T]) -> () {
    let mut unsorted = true;
    if v.len() <= 1 {
        return;
    }
    while unsorted {
        unsorted = false;
        for i in 0..v.len() - 1 {
            if v[i] > v[i + 1] {
                v.swap(i, i + 1);
                unsorted = true;
            }
        }
    }
}

pub fn quick_sort<T: PartialOrd + Copy>(v: &mut [T], comp_acc: &mut usize) -> () {
    if v.len() <= 1 {
        return;
    }
    // let pivot_index = 0;
    // let pivot_index = v.len() - 1;
    let pivot_index = median_of_three(&v);
    let mut i = 1;
    v.swap(0, pivot_index);
    for j in 1..v.len() {
        if v[j] < v[0] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(0, i - 1);
    quick_sort(&mut v[..i - 1], comp_acc);
    quick_sort(&mut v[i..], comp_acc);

    *comp_acc += v[..i - 1].len();
    *comp_acc += v[i..].len();
}
