use nom::combinator::rest;
use nom::error::ErrorKind;
use nom::number::streaming::{be_u16, be_u24, be_u32, be_u8};
use nom::{Err, IResult};
use crate::tls_alert::*;
use crate::tls_ciphers::*;
use crate::tls_ec::ECPoint;
use std::convert::AsRef;
use std::fmt;
use std::ops::Deref;
pub const MAX_RECORD_LEN: u16 = 1 << 14;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsHandshakeType(pub u8);
newtype_enum! {
impl debug TlsHandshakeType {
    HelloRequest        = 0x00,
    ClientHello         = 0x01,
    ServerHello         = 0x02,
    NewSessionTicket    = 0x04,
    EndOfEarlyData      = 0x05,
    HelloRetryRequest   = 0x06,
    EncryptedExtensions = 0x08,
    Certificate         = 0x0b,
    ServerKeyExchange   = 0x0c,
    CertificateRequest  = 0x0d,
    ServerDone          = 0x0e,
    CertificateVerify   = 0x0f,
    ClientKeyExchange   = 0x10,
    Finished            = 0x14,
    CertificateURL      = 0x15,
    CertificateStatus   = 0x16,
    KeyUpdate           = 0x18,
    NextProtocol        = 0x43,
}
}
impl From<TlsHandshakeType> for u8 {
    fn from(v: TlsHandshakeType) -> u8 {
        v.0
    }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsVersion(pub u16);
newtype_enum! {
impl debug TlsVersion {
    Ssl30        = 0x0300,
    Tls10        = 0x0301,
    Tls11        = 0x0302,
    Tls12        = 0x0303,
    Tls13        = 0x0304,
    Tls13Draft18 = 0x7f12,
    Tls13Draft19 = 0x7f13,
    Tls13Draft20 = 0x7f14,
    Tls13Draft21 = 0x7f15,
    Tls13Draft22 = 0x7f16,
    Tls13Draft23 = 0x7f17,
}
}
impl From<TlsVersion> for u16 {
    fn from(v: TlsVersion) -> u16 {
        v.0
    }
}
impl fmt::LowerHex for TlsVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:x}", self.0)
    }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsHeartbeatMessageType(pub u8);
newtype_enum! {
impl debug TlsHeartbeatMessageType {
    HeartBeatRequest  = 0x1,
    HeartBeatResponse = 0x2,
}
}
impl From<TlsHeartbeatMessageType> for u8 {
    fn from(v: TlsHeartbeatMessageType) -> u8 {
        v.0
    }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsRecordType(pub u8);
newtype_enum! {
impl debug TlsRecordType {
    ChangeCipherSpec = 0x14,
    Alert            = 0x15,
    Handshake        = 0x16,
    ApplicationData  = 0x17,
    Heartbeat        = 0x18,
}
}
impl From<TlsRecordType> for u8 {
    fn from(v: TlsRecordType) -> u8 {
        v.0
    }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsCompressionID(pub u8);
newtype_enum! {
impl debug TlsCompressionID {
    Null = 0x00,
}
}
impl From<TlsCompressionID> for u8 {
    fn from(c: TlsCompressionID) -> u8 {
        c.0
    }
}
impl Deref for TlsCompressionID {
    type Target = u8;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl AsRef<u8> for TlsCompressionID {
    fn as_ref(&self) -> &u8 {
        &self.0
    }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsCipherSuiteID(pub u16);
impl TlsCipherSuiteID {
    pub fn get_ciphersuite(&self) -> Option<&'static TlsCipherSuite> {
        TlsCipherSuite::from_id(self.0)
    }
}
impl From<TlsCipherSuiteID> for u16 {
    fn from(c: TlsCipherSuiteID) -> u16 {
        c.0
    }
}
impl Deref for TlsCipherSuiteID {
    type Target = u16;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl AsRef<u16> for TlsCipherSuiteID {
    fn as_ref(&self) -> &u16 {
        &self.0
    }
}
impl fmt::Display for TlsCipherSuiteID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}
impl fmt::Debug for TlsCipherSuiteID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match TlsCipherSuite::from_id(self.0) {
            Some(ref c) => write!(f, "0x{:04x}({})", self.0, c.name),
            None => write!(f, "0x{:04x}(Unknown cipher)", self.0),
        }
    }
}
impl fmt::LowerHex for TlsCipherSuiteID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:x}", self.0)
    }
}
#[derive(Clone, PartialEq)]
pub struct TlsClientHelloContents<'a> {
    
    pub version: TlsVersion,
    pub rand_time: u32,
    pub rand_data: &'a [u8],
    pub session_id: Option<&'a [u8]>,
    
    pub ciphers: Vec<TlsCipherSuiteID>,
    
    pub comp: Vec<TlsCompressionID>,
    pub ext: Option<&'a [u8]>,
}
impl<'a> TlsClientHelloContents<'a> {
    pub fn new(
        v: u16,
        rt: u32,
        rd: &'a [u8],
        sid: Option<&'a [u8]>,
        c: Vec<TlsCipherSuiteID>,
        co: Vec<TlsCompressionID>,
        e: Option<&'a [u8]>,
    ) -> Self {
        TlsClientHelloContents {
            version: TlsVersion(v),
            rand_time: rt,
            rand_data: rd,
            session_id: sid,
            ciphers: c,
            comp: co,
            ext: e,
        }
    }
    pub fn get_version(&self) -> TlsVersion {
        self.version
    }
    pub fn get_ciphers(&self) -> Vec<Option<&'static TlsCipherSuite>> {
        self.ciphers.iter().map(|&x| x.get_ciphersuite()).collect()
    }
}
#[derive(Clone, PartialEq)]
pub struct TlsServerHelloContents<'a> {
    pub version: TlsVersion,
    pub rand_time: u32,
    pub rand_data: &'a [u8],
    pub session_id: Option<&'a [u8]>,
    pub cipher: TlsCipherSuiteID,
    pub compression: TlsCompressionID,
    pub ext: Option<&'a [u8]>,
}
#[derive(Clone, PartialEq)]
pub struct TlsServerHelloV13Draft18Contents<'a> {
    pub version: TlsVersion,
    pub random: &'a [u8],
    pub cipher: TlsCipherSuiteID,
    pub ext: Option<&'a [u8]>,
}
#[derive(Clone, PartialEq)]
pub struct TlsHelloRetryRequestContents<'a> {
    pub version: TlsVersion,
    pub cipher: TlsCipherSuiteID,
    pub ext: Option<&'a [u8]>,
}
impl<'a> TlsServerHelloContents<'a> {
    pub fn new(
        v: u16,
        rt: u32,
        rd: &'a [u8],
        sid: Option<&'a [u8]>,
        c: u16,
        co: u8,
        e: Option<&'a [u8]>,
    ) -> Self {
        TlsServerHelloContents {
            version: TlsVersion(v),
            rand_time: rt,
            rand_data: rd,
            session_id: sid,
            cipher: TlsCipherSuiteID(c),
            compression: TlsCompressionID(co),
            ext: e,
        }
    }
    pub fn get_version(&self) -> TlsVersion {
        self.version
    }
    pub fn get_cipher(&self) -> Option<&'static TlsCipherSuite> {
        self.cipher.get_ciphersuite()
    }
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsNewSessionTicketContent<'a> {
    pub ticket_lifetime_hint: u32,
    pub ticket: &'a [u8],
}
#[derive(Clone, PartialEq)]
pub struct RawCertificate<'a> {
    pub data: &'a [u8],
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsCertificateContents<'a> {
    pub cert_chain: Vec<RawCertificate<'a>>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsCertificateRequestContents<'a> {
    pub cert_types: Vec<u8>,
    pub sig_hash_algs: Option<Vec<u16>>,
    
    
    pub unparsed_ca: Vec<&'a [u8]>,
}
#[derive(Clone, PartialEq)]
pub struct TlsServerKeyExchangeContents<'a> {
    pub parameters: &'a [u8],
}
#[derive(Clone, PartialEq)]
pub enum TlsClientKeyExchangeContents<'a> {
    Dh(&'a [u8]),
    Ecdh(ECPoint<'a>),
    Unknown(&'a [u8]),
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsCertificateStatusContents<'a> {
    pub status_type: u8,
    pub blob: &'a [u8],
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsNextProtocolContent<'a> {
    pub selected_protocol: &'a [u8],
    pub padding: &'a [u8],
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct KeyUpdateRequest(pub u8);
newtype_enum! {
impl KeyUpdateRequest {
    NotRequested  = 0x0,
    Requested     = 0x1,
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum TlsMessageHandshake<'a> {
    HelloRequest,
    ClientHello(TlsClientHelloContents<'a>),
    ServerHello(TlsServerHelloContents<'a>),
    ServerHelloV13Draft18(TlsServerHelloV13Draft18Contents<'a>),
    NewSessionTicket(TlsNewSessionTicketContent<'a>),
    EndOfEarlyData,
    HelloRetryRequest(TlsHelloRetryRequestContents<'a>),
    Certificate(TlsCertificateContents<'a>),
    ServerKeyExchange(TlsServerKeyExchangeContents<'a>),
    CertificateRequest(TlsCertificateRequestContents<'a>),
    ServerDone(&'a [u8]),
    CertificateVerify(&'a [u8]),
    ClientKeyExchange(TlsClientKeyExchangeContents<'a>),
    Finished(&'a [u8]),
    CertificateStatus(TlsCertificateStatusContents<'a>),
    NextProtocol(TlsNextProtocolContent<'a>),
    KeyUpdate(u8),
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsMessageApplicationData<'a> {
    pub blob: &'a [u8],
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsMessageHeartbeat<'a> {
    pub heartbeat_type: TlsHeartbeatMessageType,
    pub payload_len: u16,
    pub payload: &'a [u8],
}
#[derive(Clone, Copy, PartialEq)]
pub struct TlsRecordHeader {
    pub record_type: TlsRecordType,
    pub version: TlsVersion,
    pub len: u16,
}
#[derive(Clone, Debug, PartialEq)]
pub enum TlsMessage<'a> {
    Handshake(TlsMessageHandshake<'a>),
    ChangeCipherSpec,
    Alert(TlsMessageAlert),
    ApplicationData(TlsMessageApplicationData<'a>),
    Heartbeat(TlsMessageHeartbeat<'a>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsPlaintext<'a> {
    pub hdr: TlsRecordHeader,
    pub msg: Vec<TlsMessage<'a>>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsEncryptedContent<'a> {
    pub blob: &'a [u8],
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsEncrypted<'a> {
    pub hdr: TlsRecordHeader,
    pub msg: TlsEncryptedContent<'a>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct TlsRawRecord<'a> {
    pub hdr: TlsRecordHeader,
    pub data: &'a [u8],
}
fn parse_cipher_suites(i: &[u8], len: usize) -> IResult<&[u8], Vec<TlsCipherSuiteID>> {
    if len == 0 {
        return Ok((i, Vec::new()));
    }
    if len % 2 == 1 || len > i.len() {
        return Err(Err::Error(error_position!(i, ErrorKind::LengthValue)));
    }
    let v = (&i[..len])
        .chunks(2)
        .map(|chunk| TlsCipherSuiteID((chunk[0] as u16) << 8 | chunk[1] as u16))
        .collect();
    Ok((&i[len..], v))
}
fn parse_compressions_algs(i: &[u8], len: usize) -> IResult<&[u8], Vec<TlsCompressionID>> {
    if len == 0 {
        return Ok((i, Vec::new()));
    }
    if len > i.len() {
        return Err(Err::Error(error_position!(i, ErrorKind::LengthValue)));
    }
    let v = (&i[..len]).iter().map(|&it| TlsCompressionID(it)).collect();
    Ok((&i[len..], v))
}
pub(crate) fn parse_tls_versions(i: &[u8]) -> IResult<&[u8], Vec<TlsVersion>> {
    let len = i.len();
    if len == 0 {
        return Ok((i, Vec::new()));
    }
    if len % 2 == 1 || len > i.len() {
        return Err(Err::Error(error_position!(i, ErrorKind::LengthValue)));
    }
    let v = (&i[..len])
        .chunks(2)
        .map(|chunk| TlsVersion((chunk[0] as u16) << 8 | chunk[1] as u16))
        .collect();
    Ok((&i[len..], v))
}
named! {parse_certs<Vec<RawCertificate>>,
    many0!(
        complete!(
            map!(
                length_data!(be_u24),
                |s| RawCertificate{ data: s }
                )
        )
    )
}
named! {parse_tls_record_header<TlsRecordHeader>,
    do_parse!(
        t: be_u8 >>
        v: be_u16 >>
        l: be_u16 >>
        (
            TlsRecordHeader {
                record_type: TlsRecordType(t),
                version: TlsVersion(v),
                len: l,
            }
        )
    )
}
named!(
    parse_tls_handshake_msg_hello_request<TlsMessageHandshake>,
    value!(TlsMessageHandshake::HelloRequest)
);
named! {parse_tls_handshake_msg_client_hello<TlsMessageHandshake>,
    do_parse!(
        v:         be_u16  >>
        rand_time: be_u32 >>
        rand_data: take!(28) >> 
        sidlen:    be_u8 >> 
                   error_if!(sidlen > 32, ErrorKind::Verify) >>
        sid:       cond!(sidlen > 0, take!(sidlen as usize)) >>
        ciphers_len: be_u16 >>
        ciphers:   call!(parse_cipher_suites, ciphers_len as usize) >>
        comp_len:  be_u8 >>
        comp:      call!(parse_compressions_algs, comp_len as usize) >>
        ext:       opt!(complete!(length_data!(be_u16))) >>
        (
            TlsMessageHandshake::ClientHello(
                TlsClientHelloContents::new(v,rand_time,rand_data,sid,ciphers,comp.to_vec(),ext)
            )
        )
    )
}
named! {parse_tls_handshake_msg_server_hello_tlsv12<TlsMessageHandshake>,
    do_parse!(
        v:         be_u16 >>
        rand_time: be_u32 >>
        rand_data: take!(28) >> 
        sidlen:    be_u8 >> 
                   error_if!(sidlen > 32, ErrorKind::Verify) >>
        sid:       cond!(sidlen > 0, take!(sidlen as usize)) >>
        cipher:    be_u16 >>
        comp:      be_u8 >>
        ext:       opt!(complete!(length_data!(be_u16))) >>
        (
            TlsMessageHandshake::ServerHello(
                TlsServerHelloContents::new(v,rand_time,rand_data,sid,cipher,comp,ext)
            )
        )
    )
}
named! {parse_tls_handshake_msg_server_hello_tlsv13draft18<TlsMessageHandshake>,
    do_parse!(
        hv:     be_u16 >>
        random: take!(32) >>
        cipher: be_u16 >>
        ext:    opt!(complete!(length_data!(be_u16))) >>
        (
            TlsMessageHandshake::ServerHelloV13Draft18(
                TlsServerHelloV13Draft18Contents {
                    version: TlsVersion(hv),
                    random: random,
                    cipher: TlsCipherSuiteID(cipher),
                    ext: ext,
                }
            )
        )
    )
}
fn parse_tls_handshake_msg_server_hello(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> {
    let (_, version) = peek!(i, call!(be_u16))?;
    match version {
        0x7f12 => parse_tls_handshake_msg_server_hello_tlsv13draft18(i),
        0x0303 => parse_tls_handshake_msg_server_hello_tlsv12(i),
        0x0302 => parse_tls_handshake_msg_server_hello_tlsv12(i),
        0x0301 => parse_tls_handshake_msg_server_hello_tlsv12(i),
        
        _ => Err(Err::Error(error_position!(i, ErrorKind::Tag))),
    }
}
fn parse_tls_handshake_msg_newsessionticket(
    i: &[u8],
    len: usize,
) -> IResult<&[u8], TlsMessageHandshake> {
    do_parse!(
        i,
        hint: be_u32
            >> raw: take!(len - 4)
            >> (TlsMessageHandshake::NewSessionTicket(TlsNewSessionTicketContent {
                ticket_lifetime_hint: hint,
                ticket: raw,
            }))
    )
}
named! {parse_tls_handshake_msg_hello_retry_request<TlsMessageHandshake>,
    do_parse!(
        hv:  be_u16 >>
        c:   be_u16 >>
        ext: opt!(complete!(length_data!(be_u16))) >>
        (
            TlsMessageHandshake::HelloRetryRequest(
                TlsHelloRetryRequestContents {
                    version: TlsVersion(hv),
                    cipher: TlsCipherSuiteID(c),
                    ext: ext,
                    }
            )
        )
    )
}
named! {parse_tls_handshake_msg_certificate<TlsMessageHandshake>,
    do_parse!(
        cert_len: be_u24 >>
        certs:    flat_map!(take!(cert_len),parse_certs) >>
        (
            TlsMessageHandshake::Certificate(
                TlsCertificateContents {
                    cert_chain: certs,
                }
            )
        )
    )
}
fn parse_tls_handshake_msg_serverkeyexchange(
    i: &[u8],
    len: usize,
) -> IResult<&[u8], TlsMessageHandshake> {
    map!(i, take!(len), |ext| {
        TlsMessageHandshake::ServerKeyExchange(TlsServerKeyExchangeContents { parameters: ext })
    })
}
fn parse_tls_handshake_msg_serverdone(i: &[u8], len: usize) -> IResult<&[u8], TlsMessageHandshake> {
    map!(i, take!(len), |ext| {
        TlsMessageHandshake::ServerDone(ext)
    })
}
fn parse_tls_handshake_msg_certificateverify(
    i: &[u8],
    len: usize,
) -> IResult<&[u8], TlsMessageHandshake> {
    map!(i, take!(len), |blob| {
        TlsMessageHandshake::CertificateVerify(blob)
    })
}
fn parse_tls_handshake_msg_clientkeyexchange(
    i: &[u8],
    len: usize,
) -> IResult<&[u8], TlsMessageHandshake> {
    map!(i, take!(len), |ext| {
        TlsMessageHandshake::ClientKeyExchange(TlsClientKeyExchangeContents::Unknown(ext))
    })
}
fn parse_certrequest_nosigalg(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> {
    do_parse! {
        i,
        cert_types:        length_count!(be_u8,be_u8) >>
        ca_len:            be_u16 >>
        ca:                flat_map!(take!(ca_len),many0!(complete!(length_data!(be_u16)))) >>
        (
            TlsMessageHandshake::CertificateRequest(
                TlsCertificateRequestContents {
                    cert_types: cert_types,
                    
                    sig_hash_algs: None,
                    unparsed_ca: ca,
                }
            )
        )
    }
}
fn parse_certrequest_full(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> {
    do_parse! {
        i,
        cert_types:        length_count!(be_u8,be_u8) >>
        sig_hash_algs_len: be_u16 >>
        sig_hash_algs:     flat_map!(take!(sig_hash_algs_len),many0!(complete!(be_u16))) >>
        ca_len:            be_u16 >>
        ca:                flat_map!(take!(ca_len),many0!(complete!(length_data!(be_u16)))) >>
        (
            TlsMessageHandshake::CertificateRequest(
                TlsCertificateRequestContents {
                    cert_types: cert_types,
                    sig_hash_algs: Some(sig_hash_algs),
                    unparsed_ca: ca,
                }
            )
        )
    }
}
#[inline]
fn parse_tls_handshake_msg_certificaterequest(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> {
    alt!(
        i,
        complete!(parse_certrequest_full) | complete!(parse_certrequest_nosigalg)
    )
}
fn parse_tls_handshake_msg_finished(i: &[u8], len: usize) -> IResult<&[u8], TlsMessageHandshake> {
    map!(i, take!(len), |blob| {
        TlsMessageHandshake::Finished(blob)
    })
}
named! {parse_tls_handshake_msg_certificatestatus<TlsMessageHandshake>,
    do_parse!(
        status_type: be_u8 >>
        blob:        length_data!(be_u24) >>
        ( TlsMessageHandshake::CertificateStatus(
                TlsCertificateStatusContents{
                    status_type:status_type,
                    blob:blob,
                }
        ) )
    )
}
fn parse_tls_handshake_msg_next_protocol(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> {
    do_parse! {
        i,
        selected_protocol: length_data!(be_u8) >>
        padding:           length_data!(be_u8) >>
        (
            TlsMessageHandshake::NextProtocol(
                TlsNextProtocolContent {
                    selected_protocol: selected_protocol,
                    padding: padding,
                }
            )
        )
    }
}
fn parse_tls_handshake_msg_key_update(i: &[u8]) -> IResult<&[u8], TlsMessageHandshake> {
    map!(i, be_u8, |update_request| {
        TlsMessageHandshake::KeyUpdate(update_request)
    })
}
named! {parse_tls_message_handshake<TlsMessage>,
    do_parse!(
        ht: be_u8 >>
        hl: be_u24 >>
        m: flat_map!(take!(hl),
            switch!(value!(ht),
                      0x00 => call!(parse_tls_handshake_msg_hello_request) |
                       0x01 => call!(parse_tls_handshake_msg_client_hello) |
                       0x02 => call!(parse_tls_handshake_msg_server_hello) |
                  0x04 => call!(parse_tls_handshake_msg_newsessionticket,hl as usize) |
                    0x05 => value!(TlsMessageHandshake::EndOfEarlyData) |
                 0x06 => call!(parse_tls_handshake_msg_hello_retry_request) |
                       0x0b => call!(parse_tls_handshake_msg_certificate) |
                 0x0c => call!(parse_tls_handshake_msg_serverkeyexchange,hl as usize) |
                 0x0d => call!(parse_tls_handshake_msg_certificaterequest) |
                        0x0e => call!(parse_tls_handshake_msg_serverdone,hl as usize) |
                 0x0f => call!(parse_tls_handshake_msg_certificateverify,hl as usize) |
                 0x10 => call!(parse_tls_handshake_msg_clientkeyexchange,hl as usize) |
                          0x14 => call!(parse_tls_handshake_msg_finished,hl as usize) |
                    
                 0x16 => call!(parse_tls_handshake_msg_certificatestatus) |
                         0x18 => call!(parse_tls_handshake_msg_key_update) |
                      0x43 => call!(parse_tls_handshake_msg_next_protocol)
             )
        ) >>
        ( TlsMessage::Handshake(m) )
    )
}
named!(
    parse_tls_message_changecipherspec<TlsMessage>,
    map!(tag!([0x01]), |_| { TlsMessage::ChangeCipherSpec })
);
named! {parse_tls_message_alert<TlsMessage>,
    do_parse!(
        s: be_u8 >>
        c: be_u8 >>
        ( TlsMessage::Alert(
                TlsMessageAlert {
                    severity: TlsAlertSeverity(s),
                    code: TlsAlertDescription(c),
            }
        ) )
    )
}
fn parse_tls_message_applicationdata(i: &[u8]) -> IResult<&[u8], TlsMessage> {
    map!(i, rest, |b| {
        TlsMessage::ApplicationData(TlsMessageApplicationData { blob: b })
    })
}
fn parse_tls_message_heartbeat(
    i: &[u8],
    tls_plaintext_len: u16,
) -> IResult<&[u8], Vec<TlsMessage>> {
    do_parse! {i,
        hb_type: be_u8 >>
        hb_len: be_u16 >>
           error_if!(tls_plaintext_len < 3, ErrorKind::Verify) >>
        b: take!(tls_plaintext_len - 3) >> 
        (
            vec![TlsMessage::Heartbeat(
                TlsMessageHeartbeat {
                    heartbeat_type: TlsHeartbeatMessageType(hb_type),
                    payload_len: hb_len,
                    payload: b,
                }
            )]
        )
    }
}
#[rustfmt::skip]
pub fn parse_tls_record_with_header<'i, 'hdr>(i:&'i [u8], hdr:&'hdr TlsRecordHeader ) -> IResult<&'i [u8], Vec<TlsMessage<'i>>> {
    match hdr.record_type {
        TlsRecordType::ChangeCipherSpec => many1!(i, complete!(parse_tls_message_changecipherspec)),
        TlsRecordType::Alert            => many1!(i, complete!(parse_tls_message_alert)),
        TlsRecordType::Handshake        => many1!(i, complete!(parse_tls_message_handshake)),
        TlsRecordType::ApplicationData  => many1!(i, complete!(parse_tls_message_applicationdata)),
        TlsRecordType::Heartbeat        => parse_tls_message_heartbeat(i, hdr.len),
        _                               => Err(Err::Error(error_position!(i, ErrorKind::Switch)))
    }
}
pub fn parse_tls_plaintext(i: &[u8]) -> IResult<&[u8], TlsPlaintext> {
    do_parse! {
        i,
        hdr: parse_tls_record_header >>
             error_if!(hdr.len > MAX_RECORD_LEN, ErrorKind::TooLarge) >>
        msg: flat_map!(take!(hdr.len),
            call!(parse_tls_record_with_header, &hdr)
            ) >>
        ( TlsPlaintext { hdr, msg } )
    }
}
pub fn parse_tls_encrypted(i: &[u8]) -> IResult<&[u8], TlsEncrypted> {
    do_parse! {
        i,
        hdr: parse_tls_record_header >>
             error_if!(hdr.len > MAX_RECORD_LEN, ErrorKind::TooLarge) >>
        blob: take!(hdr.len) >>
        ( TlsEncrypted { hdr, msg:TlsEncryptedContent{ blob } } )
    }
}
pub fn parse_tls_raw_record(i: &[u8]) -> IResult<&[u8], TlsRawRecord> {
    do_parse! {
        i,
        hdr: parse_tls_record_header >>
             error_if!(hdr.len > MAX_RECORD_LEN, ErrorKind::TooLarge) >>
        data: take!(hdr.len) >>
        ( TlsRawRecord { hdr, data } )
    }
}
pub fn tls_parser(i: &[u8]) -> IResult<&[u8], TlsPlaintext> {
    parse_tls_plaintext(i)
}
pub fn tls_parser_many(i: &[u8]) -> IResult<&[u8], Vec<TlsPlaintext>> {
    many1!(i, complete!(parse_tls_plaintext))
}