use super::plumbing::*;
use super::*;
use std::cmp;
use std::iter::Fuse;
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug, Clone)]
pub struct Interleave<I, J>
where
    I: IndexedParallelIterator,
    J: IndexedParallelIterator<Item = I::Item>,
{
    i: I,
    j: J,
}
impl<I, J> Interleave<I, J>
where
    I: IndexedParallelIterator,
    J: IndexedParallelIterator<Item = I::Item>,
{
    
    pub(super) fn new(i: I, j: J) -> Self {
        Interleave { i, j }
    }
}
impl<I, J> ParallelIterator for Interleave<I, J>
where
    I: IndexedParallelIterator,
    J: IndexedParallelIterator<Item = I::Item>,
{
    type Item = I::Item;
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: Consumer<I::Item>,
    {
        bridge(self, consumer)
    }
    fn opt_len(&self) -> Option<usize> {
        Some(self.len())
    }
}
impl<I, J> IndexedParallelIterator for Interleave<I, J>
where
    I: IndexedParallelIterator,
    J: IndexedParallelIterator<Item = I::Item>,
{
    fn drive<C>(self, consumer: C) -> C::Result
    where
        C: Consumer<Self::Item>,
    {
        bridge(self, consumer)
    }
    fn len(&self) -> usize {
        self.i.len().checked_add(self.j.len()).expect("overflow")
    }
    fn with_producer<CB>(self, callback: CB) -> CB::Output
    where
        CB: ProducerCallback<Self::Item>,
    {
        let (i_len, j_len) = (self.i.len(), self.j.len());
        return self.i.with_producer(CallbackI {
            callback,
            i_len,
            j_len,
            i_next: false,
            j: self.j,
        });
        struct CallbackI<CB, J> {
            callback: CB,
            i_len: usize,
            j_len: usize,
            i_next: bool,
            j: J,
        }
        impl<CB, J> ProducerCallback<J::Item> for CallbackI<CB, J>
        where
            J: IndexedParallelIterator,
            CB: ProducerCallback<J::Item>,
        {
            type Output = CB::Output;
            fn callback<I>(self, i_producer: I) -> Self::Output
            where
                I: Producer<Item = J::Item>,
            {
                self.j.with_producer(CallbackJ {
                    i_producer,
                    i_len: self.i_len,
                    j_len: self.j_len,
                    i_next: self.i_next,
                    callback: self.callback,
                })
            }
        }
        struct CallbackJ<CB, I> {
            callback: CB,
            i_len: usize,
            j_len: usize,
            i_next: bool,
            i_producer: I,
        }
        impl<CB, I> ProducerCallback<I::Item> for CallbackJ<CB, I>
        where
            I: Producer,
            CB: ProducerCallback<I::Item>,
        {
            type Output = CB::Output;
            fn callback<J>(self, j_producer: J) -> Self::Output
            where
                J: Producer<Item = I::Item>,
            {
                let producer = InterleaveProducer::new(
                    self.i_producer,
                    j_producer,
                    self.i_len,
                    self.j_len,
                    self.i_next,
                );
                self.callback.callback(producer)
            }
        }
    }
}
struct InterleaveProducer<I, J>
where
    I: Producer,
    J: Producer<Item = I::Item>,
{
    i: I,
    j: J,
    i_len: usize,
    j_len: usize,
    i_next: bool,
}
impl<I, J> InterleaveProducer<I, J>
where
    I: Producer,
    J: Producer<Item = I::Item>,
{
    fn new(i: I, j: J, i_len: usize, j_len: usize, i_next: bool) -> InterleaveProducer<I, J> {
        InterleaveProducer {
            i,
            j,
            i_len,
            j_len,
            i_next,
        }
    }
}
impl<I, J> Producer for InterleaveProducer<I, J>
where
    I: Producer,
    J: Producer<Item = I::Item>,
{
    type Item = I::Item;
    type IntoIter = InterleaveSeq<I::IntoIter, J::IntoIter>;
    fn into_iter(self) -> Self::IntoIter {
        InterleaveSeq {
            i: self.i.into_iter().fuse(),
            j: self.j.into_iter().fuse(),
            i_next: self.i_next,
        }
    }
    fn min_len(&self) -> usize {
        cmp::max(self.i.min_len(), self.j.min_len())
    }
    fn max_len(&self) -> usize {
        cmp::min(self.i.max_len(), self.j.max_len())
    }
    
    
    
    
    
    
    
    
    
    
    
    
    fn split_at(self, index: usize) -> (Self, Self) {
        let even = index % 2 == 0;
        let idx = index >> 1;
        let odd_offset = |flag| if flag { 0 } else { 1 };
        
        let (i_idx, j_idx) = (
            idx + odd_offset(even || self.i_next),
            idx + odd_offset(even || !self.i_next),
        );
        let (i_split, j_split) = if self.i_len >= i_idx && self.j_len >= j_idx {
            (i_idx, j_idx)
        } else if self.i_len >= i_idx {
            
            (index - self.j_len, self.j_len)
        } else {
            
            (self.i_len, index - self.i_len)
        };
        let trailing_i_next = even == self.i_next;
        let (i_left, i_right) = self.i.split_at(i_split);
        let (j_left, j_right) = self.j.split_at(j_split);
        (
            InterleaveProducer::new(i_left, j_left, i_split, j_split, self.i_next),
            InterleaveProducer::new(
                i_right,
                j_right,
                self.i_len - i_split,
                self.j_len - j_split,
                trailing_i_next,
            ),
        )
    }
}
struct InterleaveSeq<I, J> {
    i: Fuse<I>,
    j: Fuse<J>,
    
    
    
    i_next: bool,
}
impl<I, J> Iterator for InterleaveSeq<I, J>
where
    I: Iterator,
    J: Iterator<Item = I::Item>,
{
    type Item = I::Item;
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.i_next = !self.i_next;
        if self.i_next {
            match self.i.next() {
                None => self.j.next(),
                r => r,
            }
        } else {
            match self.j.next() {
                None => self.i.next(),
                r => r,
            }
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (ih, jh) = (self.i.size_hint(), self.j.size_hint());
        let min = ih.0.saturating_add(jh.0);
        let max = match (ih.1, jh.1) {
            (Some(x), Some(y)) => x.checked_add(y),
            _ => None,
        };
        (min, max)
    }
}
impl<I, J> DoubleEndedIterator for InterleaveSeq<I, J>
where
    I: DoubleEndedIterator + ExactSizeIterator,
    J: DoubleEndedIterator<Item = I::Item> + ExactSizeIterator<Item = I::Item>,
{
    #[inline]
    fn next_back(&mut self) -> Option<I::Item> {
        if self.i.len() == self.j.len() {
            if self.i_next {
                self.i.next_back()
            } else {
                self.j.next_back()
            }
        } else if self.i.len() < self.j.len() {
            self.j.next_back()
        } else {
            self.i.next_back()
        }
    }
}
impl<I, J> ExactSizeIterator for InterleaveSeq<I, J>
where
    I: ExactSizeIterator,
    J: ExactSizeIterator<Item = I::Item>,
{
    #[inline]
    fn len(&self) -> usize {
        self.i.len() + self.j.len()
    }
}