use std::collections::HashSet;
use std::fmt;
use std::hash::Hash;
use std::iter::FromIterator;
use reflection;
use utils;
use Predicate;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InPredicate<T>
where
    T: PartialEq + fmt::Debug,
{
    inner: utils::DebugAdapter<Vec<T>>,
}
impl<T> InPredicate<T>
where
    T: Ord + fmt::Debug,
{
                                                                                                pub fn sort(self) -> OrdInPredicate<T> {
        let mut items = self.inner.debug;
        items.sort();
        OrdInPredicate {
            inner: utils::DebugAdapter::new(items),
        }
    }
}
impl<T> Predicate<T> for InPredicate<T>
where
    T: PartialEq + fmt::Debug,
{
    fn eval(&self, variable: &T) -> bool {
        self.inner.debug.contains(variable)
    }
    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}
impl<'a, T> Predicate<T> for InPredicate<&'a T>
where
    T: PartialEq + fmt::Debug + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        self.inner.debug.contains(&variable)
    }
    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}
impl<T> reflection::PredicateReflection for InPredicate<T>
where
    T: PartialEq + fmt::Debug,
{
    fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
        let params = vec![reflection::Parameter::new("values", &self.inner)];
        Box::new(params.into_iter())
    }
}
impl<T> fmt::Display for InPredicate<T>
where
    T: PartialEq + fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "var in values")
    }
}
pub fn in_iter<I, T>(iter: I) -> InPredicate<T>
where
    T: PartialEq + fmt::Debug,
    I: IntoIterator<Item = T>,
{
    InPredicate {
        inner: utils::DebugAdapter::new(Vec::from_iter(iter)),
    }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OrdInPredicate<T>
where
    T: Ord + fmt::Debug,
{
    inner: utils::DebugAdapter<Vec<T>>,
}
impl<T> Predicate<T> for OrdInPredicate<T>
where
    T: Ord + fmt::Debug,
{
    fn eval(&self, variable: &T) -> bool {
        self.inner.debug.binary_search(variable).is_ok()
    }
    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}
impl<'a, T> Predicate<T> for OrdInPredicate<&'a T>
where
    T: Ord + fmt::Debug + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        self.inner.debug.binary_search(&variable).is_ok()
    }
    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}
impl<T> reflection::PredicateReflection for OrdInPredicate<T>
where
    T: Ord + fmt::Debug,
{
    fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
        let params = vec![reflection::Parameter::new("values", &self.inner)];
        Box::new(params.into_iter())
    }
}
impl<T> fmt::Display for OrdInPredicate<T>
where
    T: Ord + fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "var in values")
    }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HashableInPredicate<T>
where
    T: Hash + Eq + fmt::Debug,
{
    inner: utils::DebugAdapter<HashSet<T>>,
}
impl<T> Predicate<T> for HashableInPredicate<T>
where
    T: Hash + Eq + fmt::Debug,
{
    fn eval(&self, variable: &T) -> bool {
        self.inner.debug.contains(variable)
    }
    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}
impl<'a, T> Predicate<T> for HashableInPredicate<&'a T>
where
    T: Hash + Eq + fmt::Debug + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        self.inner.debug.contains(&variable)
    }
    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}
impl<T> reflection::PredicateReflection for HashableInPredicate<T>
where
    T: Hash + Eq + fmt::Debug,
{
    fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
        let params = vec![reflection::Parameter::new("values", &self.inner)];
        Box::new(params.into_iter())
    }
}
impl<T> fmt::Display for HashableInPredicate<T>
where
    T: Hash + Eq + fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "var in values")
    }
}
pub fn in_hash<I, T>(iter: I) -> HashableInPredicate<T>
where
    T: Hash + Eq + fmt::Debug,
    I: IntoIterator<Item = T>,
{
    HashableInPredicate {
        inner: utils::DebugAdapter::new(HashSet::from_iter(iter)),
    }
}