use std::convert::From;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::Deref;
use std::{char, u32};
use ast::{FromInputValue, InputValue, Selection, ToInputValue};
use executor::{Executor, Registry};
use parser::{LexerError, ParseError, ScalarToken, Token};
use schema::meta::MetaType;
use types::base::GraphQLType;
use value::{ParseScalarResult, ParseScalarValue, ScalarRefValue, ScalarValue, Value};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ID(String);
impl From<String> for ID {
    fn from(s: String) -> ID {
        ID(s)
    }
}
impl ID {
    
    pub fn new<S: Into<String>>(value: S) -> Self {
        ID(value.into())
    }
}
impl Deref for ID {
    type Target = str;
    fn deref(&self) -> &str {
        &self.0
    }
}
graphql_scalar!(ID as "ID" where Scalar = <S>{
    resolve(&self) -> Value {
        Value::scalar(self.0.clone())
    }
    from_input_value(v: &InputValue) -> Option<ID> {
        match *v {
            InputValue::Scalar(ref s) => {
                s.as_string().or_else(|| s.as_int().map(|i| i.to_string()))
                    .map(ID)
            }
            _ => None
        }
    }
    from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        match value {
            ScalarToken::String(value) | ScalarToken::Int(value) => {
                Ok(S::from(value.to_owned()))
            }
            _ => Err(ParseError::UnexpectedToken(Token::Scalar(value))),
        }
    }
});
graphql_scalar!(String as "String" where Scalar = <S>{
    resolve(&self) -> Value {
        Value::scalar(self.clone())
    }
    from_input_value(v: &InputValue) -> Option<String> {
        match *v {
            InputValue::Scalar(ref s) => s.as_string(),
            _ => None,
        }
    }
    from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        if let ScalarToken::String(value) = value {
            let mut ret = String::with_capacity(value.len());
            let mut char_iter = value.chars();
            while let Some(ch) = char_iter.next() {
                match ch {
                    '\\' => {
                        match char_iter.next() {
                            Some('"') => {ret.push('"');}
                            Some('/') => {ret.push('/');}
                            Some('n') => {ret.push('\n');}
                            Some('r') => {ret.push('\r');}
                            Some('t') => {ret.push('\t');}
                            Some('\\') => {ret.push('\\');}
                            Some('f') => {ret.push('\u{000c}');}
                            Some('b') => {ret.push('\u{0008}');}
                            Some('u') => {
                                ret.push(parse_unicode_codepoint(&mut char_iter)?);
                            }
                            Some(s) => return Err(ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\{}", s)))),
                            None => return Err(ParseError::LexerError(LexerError::UnterminatedString)),
                        }
                    },
                    ch => {ret.push(ch);}
                }
            }
            Ok(ret.into())
        } else {
            Err(ParseError::UnexpectedToken(Token::Scalar(value)))
        }
    }
});
fn parse_unicode_codepoint<'a, I>(char_iter: &mut I) -> Result<char, ParseError<'a>>
where
    I: Iterator<Item = char>,
{
    let escaped_code_point = char_iter
        .next()
        .ok_or_else(|| {
            ParseError::LexerError(LexerError::UnknownEscapeSequence(String::from("\\u")))
        }).and_then(|c1| {
            char_iter
                .next()
                .map(|c2| format!("{}{}", c1, c2))
                .ok_or_else(|| {
                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{}", c1)))
                })
        }).and_then(|mut s| {
            char_iter
                .next()
                .ok_or_else(|| {
                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
                        "\\u{}",
                        s.clone()
                    )))
                }).map(|c2| {
                    s.push(c2);
                    s
                })
        }).and_then(|mut s| {
            char_iter
                .next()
                .ok_or_else(|| {
                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
                        "\\u{}",
                        s.clone()
                    )))
                }).map(|c2| {
                    s.push(c2);
                    s
                })
        })?;
    let code_point = u32::from_str_radix(&escaped_code_point, 16).map_err(|_| {
        ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
            "\\u{}",
            escaped_code_point
        )))
    })?;
    char::from_u32(code_point).ok_or_else(|| {
        ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
            "\\u{}",
            escaped_code_point
        )))
    })
}
impl<'a, S> GraphQLType<S> for &'a str
where
    S: ScalarValue,
    for<'b> &'b S: ScalarRefValue<'b>,
{
    type Context = ();
    type TypeInfo = ();
    fn name(_: &()) -> Option<&str> {
        Some("String")
    }
    fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
    where
        S: 'r,
        for<'b> &'b S: ScalarRefValue<'b>,
    {
        registry.build_scalar_type::<String>(&()).into_meta()
    }
    fn resolve(
        &self,
        _: &(),
        _: Option<&[Selection<S>]>,
        _: &Executor<Self::Context, S>,
    ) -> Value<S> {
        Value::scalar(String::from(*self))
    }
}
impl<'a, S> ToInputValue<S> for &'a str
where
    S: ScalarValue,
{
    fn to_input_value(&self) -> InputValue<S> {
        InputValue::scalar(String::from(*self))
    }
}
graphql_scalar!(bool as "Boolean" where Scalar = <S>{
    resolve(&self) -> Value {
        Value::scalar(*self)
    }
    from_input_value(v: &InputValue) -> Option<bool> {
        match *v {
            InputValue::Scalar(ref b) => b.as_boolean(),
            _ => None,
        }
    }
    from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S > {
        
        Err(ParseError::UnexpectedToken(Token::Scalar(value)))
    }
});
graphql_scalar!(i32 as "Int" where Scalar = <S>{
    resolve(&self) -> Value {
        Value::scalar(*self)
    }
    from_input_value(v: &InputValue) -> Option<i32> {
        match *v {
            InputValue::Scalar(ref i) => i.as_int(),
            _ => None,
        }
    }
    from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        if let ScalarToken::Int(v) = value {
            v.parse()
             .map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
             .map(|s: i32| s.into())
        } else {
            Err(ParseError::UnexpectedToken(Token::Scalar(value)))
        }
    }
});
graphql_scalar!(f64 as "Float" where Scalar = <S>{
    resolve(&self) -> Value {
        Value::scalar(*self)
    }
    from_input_value(v: &InputValue) -> Option<f64> {
        match *v {
            InputValue::Scalar(ref s) => s.as_float(),
            _ => None,
        }
    }
    from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        match value {
            ScalarToken::Int(v) | ScalarToken::Float(v) => {
                v.parse()
                 .map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
                 .map(|s: f64| s.into())
            }
            ScalarToken::String(_) => {
                Err(ParseError::UnexpectedToken(Token::Scalar(value)))
            }
        }
    }
});
impl<S> GraphQLType<S> for ()
where
    S: ScalarValue,
    for<'b> &'b S: ScalarRefValue<'b>,
{
    type Context = ();
    type TypeInfo = ();
    fn name(_: &()) -> Option<&str> {
        Some("__Unit")
    }
    fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
    where
        S: 'r,
        for<'b> &'b S: ScalarRefValue<'b>,
    {
        registry.build_scalar_type::<Self>(&()).into_meta()
    }
}
impl<S> ParseScalarValue<S> for ()
where
    S: ScalarValue,
{
    fn from_str<'a>(_value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        Ok(S::from(0))
    }
}
impl<S: Debug> FromInputValue<S> for () {
    fn from_input_value<'a>(_: &'a InputValue<S>) -> Option<()>
    where
        for<'b> &'b S: ScalarRefValue<'b>,
    {
        None
    }
}
#[derive(Debug)]
pub struct EmptyMutation<T> {
    phantom: PhantomData<T>,
}
impl<T> EmptyMutation<T> {
    
    pub fn new() -> EmptyMutation<T> {
        EmptyMutation {
            phantom: PhantomData,
        }
    }
}
impl<S, T> GraphQLType<S> for EmptyMutation<T>
where
    S: ScalarValue,
    for<'b> &'b S: ScalarRefValue<'b>,
{
    type Context = T;
    type TypeInfo = ();
    fn name(_: &()) -> Option<&str> {
        Some("_EmptyMutation")
    }
    fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
    where
        S: 'r,
        for<'b> &'b S: ScalarRefValue<'b>,
    {
        registry.build_object_type::<Self>(&(), &[]).into_meta()
    }
}
#[cfg(test)]
mod tests {
    use super::ID;
    use parser::ScalarToken;
    use value::{DefaultScalarValue, ParseScalarValue};
    #[test]
    fn test_id_from_string() {
        let actual = ID::from(String::from("foo"));
        let expected = ID(String::from("foo"));
        assert_eq!(actual, expected);
    }
    #[test]
    fn test_id_new() {
        let actual = ID::new("foo");
        let expected = ID(String::from("foo"));
        assert_eq!(actual, expected);
    }
    #[test]
    fn test_id_deref() {
        let id = ID(String::from("foo"));
        assert_eq!(id.len(), 3);
    }
    #[test]
    fn parse_strings() {
        fn parse_string(s: &str, expected: &str) {
            let s =
                <String as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::String(s));
            assert!(s.is_ok(), "A parsing error occurred: {:?}", s);
            let s: Option<String> = s.unwrap().into();
            assert!(s.is_some(), "No string returned");
            assert_eq!(s.unwrap(), expected);
        }
        parse_string("simple", "simple");
        parse_string(" white space ", " white space ");
        parse_string(r#"quote \""#, "quote \"");
        parse_string(r#"escaped \n\r\b\t\f"#, "escaped \n\r\u{0008}\t\u{000c}");
        parse_string(r#"slashes \\ \/"#, "slashes \\ /");
        parse_string(
            r#"unicode \u1234\u5678\u90AB\uCDEF"#,
            "unicode \u{1234}\u{5678}\u{90ab}\u{cdef}",
        );
    }
}