use crate::iterators::*;
use std::borrow::Borrow;
use std::cmp::{Eq, Ord};
use std::hash::Hash;
use std::iter::Iterator;
use indexmap::map::{IndexMap, MutableKeys};
#[derive(Clone, Eq)]
pub struct PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    pub(crate) map: IndexMap<I, Option<P>>, 
    heap: Vec<usize>,                       
    qp: Vec<usize>,                         
    
    size: usize, 
}
impl<I: Hash + Eq, P: Ord> Default for PriorityQueue<I, P> {
    fn default() -> Self {
        Self::new()
    }
}
impl<I, P> PriorityQueue<I, P>
where
    P: Ord,
    I: Hash + Eq,
{
    
    pub fn new() -> PriorityQueue<I, P> {
        PriorityQueue {
            map: IndexMap::new(),
            heap: Vec::new(),
            qp: Vec::new(),
            size: 0,
        }
    }
    
    
    
    
    
    pub fn with_capacity(capacity: usize) -> PriorityQueue<I, P> {
        PriorityQueue {
            map: IndexMap::with_capacity(capacity),
            heap: Vec::with_capacity(capacity),
            qp: Vec::with_capacity(capacity),
            size: 0,
        }
    }
    
    
    pub fn iter(&self) -> crate::pqueue::Iter<I, P> {
        crate::pqueue::Iter {
            iter: self.map.iter(),
        }
    }
    
    
    
    
    
    
    
    
    
    
    pub fn iter_mut(&mut self) -> crate::pqueue::IterMut<I, P> {
        crate::pqueue::IterMut::new(self)
    }
    
    
    
    
    pub fn peek(&self) -> Option<(&I, &P)> {
        if self.size == 0 {
            return None;
        }
        self.map
            .get_index(unsafe { *self.heap.get_unchecked(0) })
            .map(|(k, v)| (k, v.as_ref().unwrap()))
    }
    
    
    
    
    
    
    
    
    
    
    
    pub fn peek_mut(&mut self) -> Option<(&mut I, &P)> {
        if self.size == 0 {
            return None;
        }
        self.map
            .get_index_mut(unsafe { *self.heap.get_unchecked(0) })
            .map(|(k, v)| (k, v.as_ref().unwrap()))
    }
    
    
    
    
    
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }
    
    
    
    
    
    
    
    
    
    
    pub fn reserve(&mut self, additional: usize) {
        self.map.reserve(additional);
        self.heap.reserve(additional);
        self.qp.reserve(additional);
    }
    
    
    pub fn shrink_to_fit(&mut self) {
        self.heap.shrink_to_fit();
        self.qp.shrink_to_fit();
    }
    
    
    
    pub fn pop(&mut self) -> Option<(I, P)> {
        match self.size {
            0 => None,
            1 => self.swap_remove(),
            _ => {
                let r = self.swap_remove();
                self.heapify(0);
                r
            }
        }
    }
    
    
    
    
    
    
    
    pub fn push(&mut self, item: I, priority: P) -> Option<P> {
        use indexmap::map::Entry::*;
        let mut pos = 0;
        let oldp;
        match self.map.entry(item) {
            Occupied(mut e) => {
                oldp = e.get_mut().take();
                *e.get_mut() = Some(priority);
                pos = unsafe { *self.qp.get_unchecked(e.index()) };
            }
            Vacant(e) => {
                e.insert(Some(priority));
                oldp = None;
            }
        }
        if oldp.is_some() {
            unsafe {
                let tmp = *self.heap.get_unchecked(pos);
                while (pos > 0)
                    && (self
                        .map
                        .get_index(*self.heap.get_unchecked(parent(pos)))
                        .unwrap()
                        .1
                        < self.map.get_index(tmp).unwrap().1)
                {
                    *self.heap.get_unchecked_mut(pos) = *self.heap.get_unchecked(parent(pos));
                    *self.qp.get_unchecked_mut(*self.heap.get_unchecked(pos)) = pos;
                    pos = parent(pos);
                }
                *self.heap.get_unchecked_mut(pos) = tmp;
                *self.qp.get_unchecked_mut(tmp) = pos;
            }
            self.heapify(pos);
            return oldp;
        }
        
        let priority = self.map.get_index(self.size).unwrap().1;
        
        let mut i = self.size;
        let k = i;
        
        self.qp.push(i);
        self.heap.push(0);
        
        
        unsafe {
            while (i > 0)
                && (self
                    .map
                    .get_index(*self.heap.get_unchecked(parent(i)))
                    .unwrap()
                    .1
                    < priority)
            {
                *self.heap.get_unchecked_mut(i) = *self.heap.get_unchecked(parent(i));
                *self.qp.get_unchecked_mut(*self.heap.get_unchecked(i)) = i;
                i = parent(i);
            }
            
            
            *self.heap.get_unchecked_mut(i) = k;
            *self.qp.get_unchecked_mut(k) = i;
        }
        self.size += 1;
        None
    }
    
    
    
    
    
    
    
    
    pub fn change_priority<Q: ?Sized>(&mut self, item: &Q, new_priority: P) -> Option<P>
    where
        I: Borrow<Q>,
        Q: Eq + Hash,
    {
        let mut pos;
        let r = if let Some((index, _, p)) = self.map.get_full_mut(item) {
            let oldp = p.take();
            *p = Some(new_priority);
            pos = unsafe { *self.qp.get_unchecked(index) };
            oldp
        } else {
            return None;
        };
        if r.is_some() {
            unsafe {
                let tmp = *self.heap.get_unchecked(pos);
                while (pos > 0)
                    && (self
                        .map
                        .get_index(*self.heap.get_unchecked(parent(pos)))
                        .unwrap()
                        .1
                        < self.map.get_index(tmp).unwrap().1)
                {
                    *self.heap.get_unchecked_mut(pos) = *self.heap.get_unchecked(parent(pos));
                    *self.qp.get_unchecked_mut(*self.heap.get_unchecked(pos)) = pos;
                    pos = parent(pos);
                }
                *self.heap.get_unchecked_mut(pos) = tmp;
                *self.qp.get_unchecked_mut(tmp) = pos;
            }
            self.heapify(pos);
        }
        r
    }
    
    
    
    pub fn change_priority_by<Q: ?Sized, F>(&mut self, item: &Q, priority_setter: F)
    where
        I: Borrow<Q>,
        Q: Eq + Hash,
        F: FnOnce(P) -> P,
    {
        let mut pos = 0;
        let mut found = false;
        if let Some((index, _, p)) = self.map.get_full_mut(item) {
            let oldp = p.take().unwrap();
            *p = Some(priority_setter(oldp));
            pos = unsafe { *self.qp.get_unchecked(index) };
            found = true;
        }
        if found {
            unsafe {
                let tmp = *self.heap.get_unchecked(pos);
                while (pos > 0)
                    && (self
                        .map
                        .get_index(*self.heap.get_unchecked(parent(pos)))
                        .unwrap()
                        .1
                        < self.map.get_index(tmp).unwrap().1)
                {
                    *self.heap.get_unchecked_mut(pos) = *self.heap.get_unchecked(parent(pos));
                    *self.qp.get_unchecked_mut(*self.heap.get_unchecked(pos)) = pos;
                    pos = parent(pos);
                }
                *self.heap.get_unchecked_mut(pos) = tmp;
                *self.qp.get_unchecked_mut(tmp) = pos;
            }
            self.heapify(pos);
        }
    }
    
    pub fn get_priority<Q: ?Sized>(&self, item: &Q) -> Option<&P>
    where
        I: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map.get(item).map(|o| o.as_ref().unwrap())
    }
    
    
    pub fn get<Q>(&self, item: &Q) -> Option<(&I, &P)>
    where
        I: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map
            .get_full(item)
            .map(|(_, k, v)| (k, v.as_ref().unwrap()))
    }
    
    
    
    
    
    
    
    
    
    pub fn get_mut<Q>(&mut self, item: &Q) -> Option<(&mut I, &P)>
    where
        I: Borrow<Q>,
        Q: Eq + Hash,
    {
        self.map
            .get_full_mut2(item)
            .map(|(_, k, v)| (k, v.as_ref().unwrap()))
    }
    
    pub fn into_vec(self) -> Vec<I> {
        self.map.into_iter().map(|(i, _)| i).collect()
    }
    
    pub fn into_sorted_vec(mut self) -> Vec<I> {
        let mut res = Vec::with_capacity(self.size);
        while let Some((i, _)) = self.pop() {
            res.push(i);
        }
        res
    }
    
    pub fn len(&self) -> usize {
        self.size
    }
    
    pub fn is_empty(&self) -> bool {
        self.size == 0
    }
    
    pub fn clear(&mut self) {
        self.heap.clear();
        self.qp.clear();
        self.map.clear();
        self.size = 0;
    }
    
    
    
    
    
    
    
    pub fn append(&mut self, other: &mut Self) {
        if other.size > self.size {
            ::std::mem::swap(self, other);
        }
        if other.size == 0 {
            return;
        }
        let drain = other.map.drain(..);
        
        
        for (k, v) in drain {
            if !self.map.contains_key(&k) {
                let i = self.size;
                self.map.insert(k, v);
                self.heap.push(i);
                self.qp.push(i);
                self.size += 1;
            }
        }
        other.heap.clear();
        other.qp.clear();
        self.heap_build();
    }
    
    
    
    pub fn into_sorted_iter(self) -> IntoSortedIter<I, P> {
        IntoSortedIter { pq: self }
    }
    
    
    
    
    
    
    fn swap_remove(&mut self) -> Option<(I, P)> {
        
        let head = self.heap.swap_remove(0);
        self.size -= 1;
        
        if self.size == 0 {
            self.qp.pop();
            return self
                .map
                .swap_remove_index(head)
                .map(|(i, o)| (i, o.unwrap()));
        }
        unsafe {
            *self.qp.get_unchecked_mut(*self.heap.get_unchecked(0)) = 0;
        }
        self.qp.swap_remove(head);
        if head < self.size {
            unsafe {
                *self.heap.get_unchecked_mut(*self.qp.get_unchecked(head)) = head;
            }
        }
        
        self.map
            .swap_remove_index(head)
            .map(|(i, o)| (i, o.unwrap()))
    }
    
    
    
    fn swap(&mut self, a: usize, b: usize) {
        let (i, j) = unsafe { (*self.heap.get_unchecked(a), *self.heap.get_unchecked(b)) };
        self.heap.swap(a, b);
        self.qp.swap(i, j);
    }
    
    fn heapify(&mut self, i: usize) {
        let (mut l, mut r) = (left(i), right(i));
        let mut i = i;
        let mut largest = if l < self.size
            && unsafe {
                self.map.get_index(*self.heap.get_unchecked(l)).unwrap().1
                    > self.map.get_index(*self.heap.get_unchecked(i)).unwrap().1
            } {
            l
        } else {
            i
        };
        if r < self.size
            && unsafe {
                self.map.get_index(*self.heap.get_unchecked(r)).unwrap().1
                    > self
                        .map
                        .get_index(*self.heap.get_unchecked(largest))
                        .unwrap()
                        .1
            }
        {
            largest = r;
        }
        while largest != i {
            self.swap(i, largest);
            i = largest;
            l = left(i);
            r = right(i);
            if l < self.size
                && unsafe {
                    self.map.get_index(*self.heap.get_unchecked(l)).unwrap().1
                        > self.map.get_index(*self.heap.get_unchecked(i)).unwrap().1
                }
            {
                largest = l;
            } else {
                largest = i;
            }
            if r < self.size
                && unsafe {
                    self.map.get_index(*self.heap.get_unchecked(r)).unwrap().1
                        > self
                            .map
                            .get_index(*self.heap.get_unchecked(largest))
                            .unwrap()
                            .1
                }
            {
                largest = r;
            }
        }
    }
    
    
    pub(crate) fn heap_build(&mut self) {
        if self.size == 0 {
            return;
        }
        for i in (0..parent(self.size)).rev() {
            self.heapify(i);
        }
    }
}
impl<I, P> From<Vec<(I, P)>> for PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    fn from(vec: Vec<(I, P)>) -> PriorityQueue<I, P> {
        let mut pq = PriorityQueue::with_capacity(vec.len());
        let mut i = 0;
        for (item, priority) in vec {
            if !pq.map.contains_key(&item) {
                pq.map.insert(item, Some(priority));
                pq.qp.push(i);
                pq.heap.push(i);
                i += 1;
            }
        }
        pq.size = i;
        pq.heap_build();
        pq
    }
}
impl<I, P> ::std::iter::FromIterator<(I, P)> for PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    fn from_iter<IT>(iter: IT) -> PriorityQueue<I, P>
    where
        IT: IntoIterator<Item = (I, P)>,
    {
        let iter = iter.into_iter();
        let (min, max) = iter.size_hint();
        let mut pq = if let Some(max) = max {
            PriorityQueue::with_capacity(max)
        } else if min != 0 {
            PriorityQueue::with_capacity(min)
        } else {
            PriorityQueue::new()
        };
        for (item, priority) in iter {
            if !pq.map.contains_key(&item) {
                pq.map.insert(item, Some(priority));
                pq.qp.push(pq.size);
                pq.heap.push(pq.size);
                pq.size += 1;
            } else {
                let (_, old_item, old_priority) = pq.map.get_full_mut2(&item).unwrap();
                *old_item = item;
                *old_priority = Some(priority);
            }
        }
        pq.heap_build();
        pq
    }
}
use ::std::iter::IntoIterator;
impl<I, P> IntoIterator for PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    type Item = (I, P);
    type IntoIter = crate::pqueue::IntoIter<I, P>;
    fn into_iter(self) -> crate::pqueue::IntoIter<I, P> {
        crate::pqueue::IntoIter {
            iter: self.map.into_iter(),
        }
    }
}
impl<'a, I, P> IntoIterator for &'a PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    type Item = (&'a I, &'a P);
    type IntoIter = Iter<'a, I, P>;
    fn into_iter(self) -> Iter<'a, I, P> {
        Iter {
            iter: self.map.iter(),
        }
    }
}
impl<'a, I, P> IntoIterator for &'a mut PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    type Item = (&'a mut I, &'a mut P);
    type IntoIter = IterMut<'a, I, P>;
    fn into_iter(self) -> IterMut<'a, I, P> {
        IterMut::new(self)
    }
}
impl<I, P> ::std::iter::Extend<(I, P)> for PriorityQueue<I, P>
where
    I: Hash + Eq,
    P: Ord,
{
    fn extend<T: IntoIterator<Item = (I, P)>>(&mut self, iter: T) {
        let iter = iter.into_iter();
        let (min, max) = iter.size_hint();
        let mut rebuild = false;
        if let Some(max) = max {
            self.reserve(max);
            rebuild = better_to_rebuild(self.size, max);
        } else if min != 0 {
            self.reserve(min);
            rebuild = better_to_rebuild(self.size, min);
        }
        if rebuild {
            for (item, priority) in iter {
                if !self.map.contains_key(&item) {
                    self.map.insert(item, Some(priority));
                    self.qp.push(self.size);
                    self.heap.push(self.size);
                    self.size += 1;
                } else {
                    let (_, old_item, old_priority) = self.map.get_full_mut2(&item).unwrap();
                    *old_item = item;
                    *old_priority = Some(priority);
                }
            }
            self.heap_build();
        } else {
            for (item, priority) in iter {
                self.push(item, priority);
            }
        }
    }
}
use std::fmt;
impl<I, P> fmt::Debug for PriorityQueue<I, P>
where
    I: fmt::Debug + Hash + Eq,
    P: fmt::Debug + Ord,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_map()
            .entries(
                self.heap
                    .iter()
                    .map(|&i| self.map.get_index(i).unwrap())
                    .map(|(i, op)| (i, op.as_ref().unwrap())),
            )
            .finish()
    }
}
use std::cmp::PartialEq;
impl<I, P1, P2> PartialEq<PriorityQueue<I, P2>> for PriorityQueue<I, P1>
where
    I: Hash + Eq,
    P1: Ord,
    P1: PartialEq<P2>,
    Option<P1>: PartialEq<Option<P2>>,
    P2: Ord,
{
    fn eq(&self, other: &PriorityQueue<I, P2>) -> bool {
        self.map == other.map
    }
}
#[inline(always)]
fn left(i: usize) -> usize {
    (i * 2) + 1
}
#[inline(always)]
fn right(i: usize) -> usize {
    (i * 2) + 2
}
#[inline(always)]
fn parent(i: usize) -> usize {
    (i - 1) / 2
}
#[inline(always)]
fn log2_fast(x: usize) -> usize {
    use std::mem::size_of;
    8 * size_of::<usize>() - (x.leading_zeros() as usize) - 1
}
#[inline]
fn better_to_rebuild(len1: usize, len2: usize) -> bool {
    2 * (len1 + len2) < len2 * log2_fast(len1)
}
#[cfg(feature = "serde")]
mod serde {
    use crate::pqueue::PriorityQueue;
    use std::cmp::{Eq, Ord};
    use std::hash::Hash;
    use std::marker::PhantomData;
    use serde::ser::{Serialize, SerializeSeq, Serializer};
    impl<I, P> Serialize for PriorityQueue<I, P>
    where
        I: Hash + Eq + Serialize,
        P: Ord + Serialize,
    {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            let mut map_serializer = serializer.serialize_seq(Some(self.size))?;
            for (k, v) in &self.map {
                map_serializer.serialize_element(&(k, v.as_ref().unwrap()))?;
            }
            map_serializer.end()
        }
    }
    use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
    impl<'de, I, P> Deserialize<'de> for PriorityQueue<I, P>
    where
        I: Hash + Eq + Deserialize<'de>,
        P: Ord + Deserialize<'de>,
    {
        fn deserialize<D>(deserializer: D) -> Result<PriorityQueue<I, P>, D::Error>
        where
            D: Deserializer<'de>,
        {
            deserializer.deserialize_seq(PQVisitor {
                marker: PhantomData,
            })
        }
    }
    struct PQVisitor<I, P>
    where
        I: Hash + Eq,
        P: Ord,
    {
        marker: PhantomData<PriorityQueue<I, P>>,
    }
    impl<'de, I, P> Visitor<'de> for PQVisitor<I, P>
    where
        I: Hash + Eq + Deserialize<'de>,
        P: Ord + Deserialize<'de>,
    {
        type Value = PriorityQueue<I, P>;
        fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            write!(formatter, "A priority queue")
        }
        fn visit_unit<E>(self) -> Result<Self::Value, E> {
            Ok(PriorityQueue::new())
        }
        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
        where
            A: SeqAccess<'de>,
        {
            let mut pq: PriorityQueue<I, P> = if let Some(size) = seq.size_hint() {
                PriorityQueue::with_capacity(size)
            } else {
                PriorityQueue::new()
            };
            while let Some((item, priority)) = seq.next_element()? {
                pq.map.insert(item, Some(priority));
                pq.qp.push(pq.size);
                pq.heap.push(pq.size);
                pq.size += 1;
            }
            pq.heap_build();
            Ok(pq)
        }
    }
}