use std::ops::Range;

pub fn are_continuous<'a, I, T: 'a + Ord + Copy + Eq>(iter: I) -> bool
where
    I: Iterator<Item = &'a Range<T>>,
{
    get_gaps(iter).is_empty()
}

pub fn get_gaps<'a, I, T: 'a + Ord + Copy + Eq>(iter: I) -> Vec<Range<T>>
where
    I: Iterator<Item = &'a Range<T>>,
{
    let mut sorted: Vec<&Range<T>> = iter.collect();
    sorted.sort_by(|a, b| a.start.partial_cmp(&b.start).unwrap());

    let mut gaps = Vec::new();
    for i in 1..sorted.len() {
        let left = &sorted[i - 1];
        let right = &sorted[i];
        if left.end != right.start {
            gaps.push(Range {
                start: left.end,
                end: right.start,
            });
        }
    }

    gaps
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_find_gaps() {
        let r1 = 10..20;
        let r2 = 30..40;
        let r3 = 40..50;
        let r4 = 80..100;

        let ranges = vec![r2, r1, r4, r3];
        let gaps = get_gaps(ranges.iter());
        assert_eq!(gaps, vec![20..30, 50..80]);
        assert!(!are_continuous(ranges.iter()));

        let r5 = 30..40;
        let r6 = 40..50;
        let ranges = vec![r5, r6];
        assert!(are_continuous(ranges.iter()));
    }
}
