use self::explicit_le::ExplicitVRLittleEndianDecoder;
use self::implicit_le::{ImplicitVRLittleEndianDecoder, StandardImplicitVRLittleEndianDecoder};
use byteordered::Endianness;
use dicom_core::header::{DataElementHeader, SequenceItemHeader};
use dicom_core::Tag;
use snafu::{Backtrace, Snafu};
use std::io::{self, Read};
pub mod basic;
pub mod explicit_be;
pub mod explicit_le;
pub mod implicit_le;
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum Error {
    #[snafu(display("Failed to read the beginning (tag) of the header"))]
    ReadHeaderTag {
        backtrace: Option<Backtrace>,
        source: io::Error,
    },
    #[snafu(display("Failed to read the item header"))]
    ReadItemHeader {
        backtrace: Backtrace,
        source: io::Error,
    },
    #[snafu(display("Failed to read the header's item length field"))]
    ReadItemLength {
        backtrace: Backtrace,
        source: io::Error,
    },
    #[snafu(display("Failed to read the header's tag field"))]
    ReadTag {
        backtrace: Backtrace,
        source: io::Error,
    },
    #[snafu(display("Failed to read the header's reserved bytes"))]
    ReadReserved {
        backtrace: Backtrace,
        source: io::Error,
    },
    #[snafu(display("Failed to read the header's element length field"))]
    ReadLength {
        backtrace: Backtrace,
        source: io::Error,
    },
    #[snafu(display("Failed to read the header's value representation"))]
    ReadVr {
        backtrace: Backtrace,
        source: io::Error,
    },
    #[snafu(display("Bad sequence item header"))]
    BadSequenceHeader {
        source: dicom_core::header::SequenceItemHeaderError,
    },
}
pub type Result<T> = std::result::Result<T, Error>;
pub fn default_reader() -> StandardImplicitVRLittleEndianDecoder {
    ImplicitVRLittleEndianDecoder::default()
}
pub fn file_header_decoder() -> ExplicitVRLittleEndianDecoder {
    ExplicitVRLittleEndianDecoder::default()
}
pub trait BasicDecode {
    fn endianness(&self) -> Endianness;
    fn decode_us<S>(&self, source: S) -> io::Result<u16>
    where
        S: Read;
    fn decode_us_into<S>(&self, mut source: S, dst: &mut [u16]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_us(&mut source)?;
        }
        Ok(())
    }
    fn decode_ul<S>(&self, source: S) -> io::Result<u32>
    where
        S: Read;
    fn decode_ul_into<S>(&self, mut source: S, dst: &mut [u32]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_ul(&mut source)?;
        }
        Ok(())
    }
    fn decode_uv<S>(&self, source: S) -> io::Result<u64>
    where
        S: Read;
    fn decode_uv_into<S>(&self, mut source: S, dst: &mut [u64]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_uv(&mut source)?;
        }
        Ok(())
    }
    fn decode_ss<S>(&self, source: S) -> io::Result<i16>
    where
        S: Read;
    fn decode_ss_into<S>(&self, mut source: S, dst: &mut [i16]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_ss(&mut source)?;
        }
        Ok(())
    }
    fn decode_sl<S>(&self, source: S) -> io::Result<i32>
    where
        S: Read;
    fn decode_sl_into<S>(&self, mut source: S, dst: &mut [i32]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_sl(&mut source)?;
        }
        Ok(())
    }
    fn decode_sv<S>(&self, source: S) -> io::Result<i64>
    where
        S: Read;
    fn decode_sv_into<S>(&self, mut source: S, dst: &mut [i64]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_sv(&mut source)?;
        }
        Ok(())
    }
    fn decode_fl<S>(&self, source: S) -> io::Result<f32>
    where
        S: Read;
    fn decode_fl_into<S>(&self, mut source: S, dst: &mut [f32]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_fl(&mut source)?;
        }
        Ok(())
    }
    fn decode_fd<S>(&self, source: S) -> io::Result<f64>
    where
        S: Read;
    fn decode_fd_into<S>(&self, mut source: S, dst: &mut [f64]) -> io::Result<()>
    where
        S: Read,
    {
        for v in dst.iter_mut() {
            *v = self.decode_fd(&mut source)?;
        }
        Ok(())
    }
    fn decode_tag<S>(&self, mut source: S) -> io::Result<Tag>
    where
        S: Read,
    {
        let g = self.decode_us(&mut source)?;
        let e = self.decode_us(source)?;
        Ok(Tag(g, e))
    }
}
impl<T: ?Sized> BasicDecode for Box<T>
where
    T: BasicDecode,
{
    fn endianness(&self) -> Endianness {
        (**self).endianness()
    }
    fn decode_us<S>(&self, source: S) -> io::Result<u16>
    where
        S: Read,
    {
        (**self).decode_us(source)
    }
    fn decode_us_into<S>(&self, source: S, dst: &mut [u16]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_us_into(source, dst)
    }
    fn decode_ul<S>(&self, source: S) -> io::Result<u32>
    where
        S: Read,
    {
        (**self).decode_ul(source)
    }
    fn decode_ul_into<S>(&self, source: S, dst: &mut [u32]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_ul_into(source, dst)
    }
    fn decode_uv<S>(&self, source: S) -> io::Result<u64>
    where
        S: Read,
    {
        (**self).decode_uv(source)
    }
    fn decode_uv_into<S>(&self, source: S, dst: &mut [u64]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_uv_into(source, dst)
    }
    fn decode_ss<S>(&self, source: S) -> io::Result<i16>
    where
        S: Read,
    {
        (**self).decode_ss(source)
    }
    fn decode_ss_into<S>(&self, source: S, dst: &mut [i16]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_ss_into(source, dst)
    }
    fn decode_sl<S>(&self, source: S) -> io::Result<i32>
    where
        S: Read,
    {
        (**self).decode_sl(source)
    }
    fn decode_sl_into<S>(&self, source: S, dst: &mut [i32]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_sl_into(source, dst)
    }
    fn decode_sv<S>(&self, source: S) -> io::Result<i64>
    where
        S: Read,
    {
        (**self).decode_sv(source)
    }
    fn decode_sv_into<S>(&self, source: S, dst: &mut [i64]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_sv_into(source, dst)
    }
    fn decode_fl<S>(&self, source: S) -> io::Result<f32>
    where
        S: Read,
    {
        (**self).decode_fl(source)
    }
    fn decode_fl_into<S>(&self, source: S, dst: &mut [f32]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_fl_into(source, dst)
    }
    fn decode_fd<S>(&self, source: S) -> io::Result<f64>
    where
        S: Read,
    {
        (**self).decode_fd(source)
    }
    fn decode_fd_into<S>(&self, source: S, dst: &mut [f64]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_fd_into(source, dst)
    }
    fn decode_tag<S>(&self, source: S) -> io::Result<Tag>
    where
        S: Read,
    {
        (**self).decode_tag(source)
    }
}
impl<'a, T: ?Sized> BasicDecode for &'a T
where
    T: BasicDecode,
{
    fn endianness(&self) -> Endianness {
        (**self).endianness()
    }
    fn decode_us<S>(&self, source: S) -> io::Result<u16>
    where
        S: Read,
    {
        (**self).decode_us(source)
    }
    fn decode_us_into<S>(&self, source: S, dst: &mut [u16]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_us_into(source, dst)
    }
    fn decode_ul<S>(&self, source: S) -> io::Result<u32>
    where
        S: Read,
    {
        (**self).decode_ul(source)
    }
    fn decode_ul_into<S>(&self, source: S, dst: &mut [u32]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_ul_into(source, dst)
    }
    fn decode_uv<S>(&self, source: S) -> io::Result<u64>
    where
        S: Read,
    {
        (**self).decode_uv(source)
    }
    fn decode_uv_into<S>(&self, source: S, dst: &mut [u64]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_uv_into(source, dst)
    }
    fn decode_ss<S>(&self, source: S) -> io::Result<i16>
    where
        S: Read,
    {
        (**self).decode_ss(source)
    }
    fn decode_ss_into<S>(&self, source: S, dst: &mut [i16]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_ss_into(source, dst)
    }
    fn decode_sl<S>(&self, source: S) -> io::Result<i32>
    where
        S: Read,
    {
        (**self).decode_sl(source)
    }
    fn decode_sl_into<S>(&self, source: S, dst: &mut [i32]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_sl_into(source, dst)
    }
    fn decode_sv<S>(&self, source: S) -> io::Result<i64>
    where
        S: Read,
    {
        (**self).decode_sv(source)
    }
    fn decode_sv_into<S>(&self, source: S, dst: &mut [i64]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_sv_into(source, dst)
    }
    fn decode_fl<S>(&self, source: S) -> io::Result<f32>
    where
        S: Read,
    {
        (**self).decode_fl(source)
    }
    fn decode_fl_into<S>(&self, source: S, dst: &mut [f32]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_fl_into(source, dst)
    }
    fn decode_fd<S>(&self, source: S) -> io::Result<f64>
    where
        S: Read,
    {
        (**self).decode_fd(source)
    }
    fn decode_fd_into<S>(&self, source: S, dst: &mut [f64]) -> io::Result<()>
    where
        S: Read,
    {
        (**self).decode_fd_into(source, dst)
    }
    fn decode_tag<S>(&self, source: S) -> io::Result<Tag>
    where
        S: Read,
    {
        (**self).decode_tag(source)
    }
}
pub trait Decode {
    fn decode_header<S>(&self, source: &mut S) -> Result<(DataElementHeader, usize)>
    where
        S: ?Sized + Read;
    fn decode_item_header<S>(&self, source: &mut S) -> Result<SequenceItemHeader>
    where
        S: ?Sized + Read;
    fn decode_tag<S>(&self, source: &mut S) -> Result<Tag>
    where
        S: ?Sized + Read;
}
impl<T: ?Sized> Decode for Box<T>
where
    T: Decode,
{
    fn decode_header<S>(&self, source: &mut S) -> Result<(DataElementHeader, usize)>
    where
        S: ?Sized + Read,
    {
        (**self).decode_header(source)
    }
    fn decode_item_header<S>(&self, source: &mut S) -> Result<SequenceItemHeader>
    where
        S: ?Sized + Read,
    {
        (**self).decode_item_header(source)
    }
    fn decode_tag<S>(&self, source: &mut S) -> Result<Tag>
    where
        S: ?Sized + Read,
    {
        (**self).decode_tag(source)
    }
}
impl<'a, T: ?Sized> Decode for &'a T
where
    T: Decode,
{
    fn decode_header<S>(&self, source: &mut S) -> Result<(DataElementHeader, usize)>
    where
        S: ?Sized + Read,
    {
        (**self).decode_header(source)
    }
    fn decode_item_header<S>(&self, source: &mut S) -> Result<SequenceItemHeader>
    where
        S: ?Sized + Read,
    {
        (**self).decode_item_header(source)
    }
    fn decode_tag<S>(&self, source: &mut S) -> Result<Tag>
    where
        S: ?Sized + Read,
    {
        (**self).decode_tag(source)
    }
}
pub trait DecodeFrom<S: ?Sized + Read> {
    fn decode_header(&self, source: &mut S) -> Result<(DataElementHeader, usize)>;
    fn decode_item_header(&self, source: &mut S) -> Result<SequenceItemHeader>;
    fn decode_tag(&self, source: &mut S) -> Result<Tag>;
}
impl<S: ?Sized, T: ?Sized> DecodeFrom<S> for &T
where
    S: Read,
    T: DecodeFrom<S>,
{
    fn decode_header(&self, source: &mut S) -> Result<(DataElementHeader, usize)> {
        (**self).decode_header(source)
    }
    fn decode_item_header(&self, source: &mut S) -> Result<SequenceItemHeader> {
        (**self).decode_item_header(source)
    }
    fn decode_tag(&self, source: &mut S) -> Result<Tag> {
        (**self).decode_tag(source)
    }
}
impl<S: ?Sized, T: ?Sized> DecodeFrom<S> for Box<T>
where
    S: Read,
    T: DecodeFrom<S>,
{
    fn decode_header(&self, source: &mut S) -> Result<(DataElementHeader, usize)> {
        (**self).decode_header(source)
    }
    fn decode_item_header(&self, source: &mut S) -> Result<SequenceItemHeader> {
        (**self).decode_item_header(source)
    }
    fn decode_tag(&self, source: &mut S) -> Result<Tag> {
        (**self).decode_tag(source)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    fn is_decode_from<T: DecodeFrom<dyn Read>>(_decoder: &T) {}
    #[allow(unused)]
    fn boxed_decoder_from_is_decoder_from<T>(decoder: T)
    where
        T: DecodeFrom<dyn Read>,
    {
        is_decode_from(&decoder);
        let boxed = Box::new(decoder);
        is_decode_from(&boxed);
        let erased = boxed as Box<dyn DecodeFrom<dyn Read>>;
        is_decode_from(&erased);
    }
}