use crate::util::n_times;
use dicom_core::dictionary::VirtualVr;
use dicom_core::header::{DataElementHeader, HasLength, Length, SequenceItemHeader, Tag, VR};
use dicom_core::value::deserialize::{
    parse_date_partial, parse_datetime_partial, parse_time_partial,
};
use dicom_core::value::PrimitiveValue;
use dicom_dictionary_std::StandardDataDictionary;
use dicom_encoding::decode::basic::{BasicDecoder, LittleEndianBasicDecoder};
use dicom_encoding::decode::explicit_le::ExplicitVRLittleEndianDecoder;
use dicom_encoding::decode::{BasicDecode, DecodeFrom};
use dicom_encoding::text::{
    validate_da, validate_dt, validate_tm, DefaultCharacterSetCodec, SpecificCharacterSet,
    TextCodec, TextValidationOutcome,
};
use dicom_encoding::transfer_syntax::{DynDecoder, TransferSyntax};
use smallvec::smallvec;
use snafu::{Backtrace, OptionExt, ResultExt, Snafu};
use std::io::Read;
use std::{fmt::Debug, io::Seek, io::SeekFrom};
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum Error {
    #[snafu(display("Decoding in transfer syntax {} is unsupported", ts))]
    UnsupportedTransferSyntax {
        ts: &'static str,
        backtrace: Backtrace,
    },
    #[snafu(display("Unsupported character set {:?}", charset))]
    UnsupportedCharacterSet {
        charset: SpecificCharacterSet,
        backtrace: Backtrace,
    },
    #[snafu(display("Attempted to read non-primitive value at position {}", position))]
    NonPrimitiveType { position: u64, backtrace: Backtrace },
    #[snafu(display(
        "Undefined value length of element tagged {} at position {}",
        tag,
        position
    ))]
    UndefinedValueLength {
        tag: Tag,
        position: u64,
        backtrace: Backtrace,
    },
    #[snafu(display("Could not decode element header at position {}", position))]
    DecodeElementHeader {
        position: u64,
        #[snafu(backtrace)]
        source: dicom_encoding::decode::Error,
    },
    #[snafu(display("Could not decode element header at position {}", position))]
    DecodeItemHeader {
        position: u64,
        #[snafu(backtrace)]
        source: dicom_encoding::decode::Error,
    },
    #[snafu(display("Could not decode text at position {}", position))]
    DecodeText {
        position: u64,
        #[snafu(backtrace)]
        source: dicom_encoding::text::DecodeTextError,
    },
    #[snafu(display("Could not read value from source at position {}", position))]
    ReadValueData {
        position: u64,
        source: std::io::Error,
        backtrace: Backtrace,
    },
    #[snafu(display(
        "Could not move source cursor from position {} to {}",
        position,
        new_position
    ))]
    SeekReader {
        position: u64,
        new_position: u64,
        source: std::io::Error,
        backtrace: Backtrace,
    },
    #[snafu(display("Failed value deserialization at position {}", position))]
    DeserializeValue {
        position: u64,
        source: dicom_core::value::deserialize::Error,
    },
    #[snafu(display("Invalid integer value at position {}", position))]
    ReadInt {
        position: u64,
        source: std::num::ParseIntError,
    },
    #[snafu(display("Invalid float value at position {}", position))]
    ReadFloat {
        position: u64,
        source: std::num::ParseFloatError,
    },
    #[snafu(display("Invalid Date value element `{}` at position {}", string, position))]
    InvalidDateValue {
        position: u64,
        string: String,
        backtrace: Backtrace,
    },
    #[snafu(display("Invalid Time value element `{}` at position {}", string, position))]
    InvalidTimeValue {
        position: u64,
        string: String,
        backtrace: Backtrace,
    },
    #[snafu(display("Invalid DateTime value element `{}` at position {}", string, position))]
    InvalidDateTimeValue {
        position: u64,
        string: String,
        backtrace: Backtrace,
    },
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub trait StatefulDecode {
    type Reader: Read;
    fn decode_header(&mut self) -> Result<DataElementHeader>;
    fn decode_item_header(&mut self) -> Result<SequenceItemHeader>;
    fn read_value(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue>;
    fn read_value_preserved(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue>;
    fn read_value_bytes(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue>;
    fn read_to_vec(&mut self, length: u32, vec: &mut Vec<u8>) -> Result<()>;
    fn read_u32_to_vec(&mut self, length: u32, vec: &mut Vec<u32>) -> Result<()>;
    fn read_to<W>(&mut self, length: u32, out: W) -> Result<()>
    where
        Self: Sized,
        W: std::io::Write;
    fn skip_bytes(&mut self, length: u32) -> Result<()>;
    fn seek(&mut self, position: u64) -> Result<()>
    where
        Self::Reader: Seek;
    fn position(&self) -> u64;
}
pub type DynStatefulDecoder<S> = StatefulDecoder<DynDecoder<S>, S>;
const PARSER_BUFFER_CAPACITY: usize = 2048;
#[derive(Debug)]
pub struct StatefulDecoder<D, S, BD = BasicDecoder, TC = SpecificCharacterSet> {
    from: S,
    decoder: D,
    basic: BD,
    text: TC,
    buffer: Vec<u8>,
    position: u64,
    signed_pixeldata: Option<bool>,
}
impl<S> StatefulDecoder<DynDecoder<S>, S> {
    pub fn new_with(
        from: S,
        ts: &TransferSyntax,
        charset: SpecificCharacterSet,
        position: u64,
    ) -> Result<Self>
    where
        S: Read,
    {
        let basic = ts.basic_decoder();
        let decoder = ts
            .decoder_for::<S>()
            .context(UnsupportedTransferSyntaxSnafu { ts: ts.name() })?;
        Ok(StatefulDecoder::new_with_position(
            from, decoder, basic, charset, position,
        ))
    }
    pub fn new_with_ts(from: S, ts: &TransferSyntax, position: u64) -> Result<Self>
    where
        S: Read,
    {
        Self::new_with(from, ts, SpecificCharacterSet::default(), position)
    }
}
pub type FileHeaderParser<S> = StatefulDecoder<
    ExplicitVRLittleEndianDecoder,
    S,
    LittleEndianBasicDecoder,
    DefaultCharacterSetCodec,
>;
impl<S> FileHeaderParser<S>
where
    S: Read,
{
    pub fn file_header_parser(from: S) -> Self {
        Self {
            from,
            basic: LittleEndianBasicDecoder,
            decoder: ExplicitVRLittleEndianDecoder::default(),
            text: DefaultCharacterSetCodec,
            buffer: Vec::with_capacity(PARSER_BUFFER_CAPACITY),
            position: 0,
            signed_pixeldata: None,
        }
    }
}
impl<D, S, BD, TC> StatefulDecoder<D, S, BD, TC>
where
    BD: BasicDecode,
    TC: TextCodec,
{
    #[inline]
    pub fn new(from: S, decoder: D, basic: BD, text: TC) -> StatefulDecoder<D, S, BD, TC> {
        Self::new_with_position(from, decoder, basic, text, 0)
    }
    #[inline]
    pub fn new_with_position(from: S, decoder: D, basic: BD, text: TC, position: u64) -> Self {
        Self {
            from,
            basic,
            decoder,
            text,
            buffer: Vec::with_capacity(PARSER_BUFFER_CAPACITY),
            position,
            signed_pixeldata: None,
        }
    }
}
impl<D, S, BD, TC> StatefulDecoder<D, S, BD, TC>
where
    S: Seek,
    BD: BasicDecode,
    TC: TextCodec,
{
    pub fn new_positioned(
        mut from: S,
        decoder: D,
        basic: BD,
        text: TC,
    ) -> Result<Self, std::io::Error> {
        let position = from.stream_position()?;
        Ok(Self::new_with_position(
            from, decoder, basic, text, position,
        ))
    }
}
impl<D, S, BD, TC> StatefulDecoder<D, S, BD, TC>
where
    D: DecodeFrom<S>,
    BD: BasicDecode,
    S: Read,
    TC: TextCodec,
{
    fn require_known_length(&self, header: &DataElementHeader) -> Result<usize> {
        header
            .length()
            .get()
            .map(|len| len as usize)
            .context(UndefinedValueLengthSnafu {
                position: self.position,
                tag: header.tag,
            })
    }
    fn read_value_tag(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let ntags = len >> 2;
        let parts: Result<_> = n_times(ntags)
            .map(|_| {
                self.basic
                    .decode_tag(&mut self.from)
                    .context(ReadValueDataSnafu {
                        position: self.position,
                    })
            })
            .collect();
        self.position += len as u64;
        Ok(PrimitiveValue::Tags(parts?))
    }
    fn read_value_ob(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let mut buf = smallvec![0u8; len];
        self.from.read_exact(&mut buf).context(ReadValueDataSnafu {
            position: self.position,
        })?;
        self.position += len as u64;
        Ok(PrimitiveValue::U8(buf))
    }
    fn read_value_strs(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        let parts: Result<_> = match header.vr() {
            VR::AE | VR::CS | VR::AS => self
                .buffer
                .split(|v| *v == b'\\')
                .map(|slice| {
                    DefaultCharacterSetCodec
                        .decode(slice)
                        .context(DecodeTextSnafu {
                            position: self.position,
                        })
                })
                .collect(),
            _ => self
                .buffer
                .split(|v| *v == b'\\')
                .map(|slice| {
                    self.text.decode(slice).context(DecodeTextSnafu {
                        position: self.position,
                    })
                })
                .collect(),
        };
        self.position += len as u64;
        Ok(PrimitiveValue::Strs(parts?))
    }
    fn read_value_str(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::Str(
            self.text
                .decode(&self.buffer[..])
                .context(DecodeTextSnafu {
                    position: self.position,
                })?,
        ))
    }
    fn read_value_ss(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 1;
        let mut vec = smallvec![0; n];
        self.basic
            .decode_ss_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::I16(vec))
    }
    fn read_value_fl(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 2;
        let mut vec = smallvec![0.; n];
        self.basic
            .decode_fl_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::F32(vec))
    }
    fn read_value_da(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        let buf = trim_trail_empty_bytes(&self.buffer);
        if buf.is_empty() {
            return Ok(PrimitiveValue::Empty);
        }
        if validate_da(buf) != TextValidationOutcome::Ok {
            let lossy_str = DefaultCharacterSetCodec
                .decode(buf)
                .unwrap_or_else(|_| "[byte stream]".to_string());
            return InvalidDateValueSnafu {
                position: self.position,
                string: lossy_str,
            }
            .fail();
        }
        let vec: Result<_> = buf
            .split(|b| *b == b'\\')
            .map(|part| {
                parse_date_partial(part)
                    .map(|t| t.0)
                    .context(DeserializeValueSnafu {
                        position: self.position,
                    })
            })
            .collect();
        self.position += len as u64;
        Ok(PrimitiveValue::Date(vec?))
    }
    fn read_value_ds(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        let buf = trim_trail_empty_bytes(&self.buffer);
        if buf.is_empty() {
            return Ok(PrimitiveValue::Empty);
        }
        let parts: Result<_> = buf
            .split(|b| *b == b'\\')
            .map(|slice| {
                let codec = DefaultCharacterSetCodec;
                let txt = codec.decode(slice).context(DecodeTextSnafu {
                    position: self.position,
                })?;
                let txt = txt.trim();
                txt.parse::<f64>().context(ReadFloatSnafu {
                    position: self.position,
                })
            })
            .collect();
        self.position += len as u64;
        Ok(PrimitiveValue::F64(parts?))
    }
    fn read_value_dt(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        let buf = trim_trail_empty_bytes(&self.buffer);
        if buf.is_empty() {
            return Ok(PrimitiveValue::Empty);
        }
        if validate_dt(buf) != TextValidationOutcome::Ok {
            let lossy_str = DefaultCharacterSetCodec
                .decode(buf)
                .unwrap_or_else(|_| "[byte stream]".to_string());
            return InvalidDateTimeValueSnafu {
                position: self.position,
                string: lossy_str,
            }
            .fail();
        }
        let vec: Result<_> = buf
            .split(|b| *b == b'\\')
            .map(|part| {
                parse_datetime_partial(part).context(DeserializeValueSnafu {
                    position: self.position,
                })
            })
            .collect();
        self.position += len as u64;
        Ok(PrimitiveValue::DateTime(vec?))
    }
    fn read_value_is(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        let buf = trim_trail_empty_bytes(&self.buffer);
        if buf.is_empty() {
            return Ok(PrimitiveValue::Empty);
        }
        let parts: Result<_> = buf
            .split(|v| *v == b'\\')
            .map(|slice| {
                let codec = DefaultCharacterSetCodec;
                let txt = codec.decode(slice).context(DecodeTextSnafu {
                    position: self.position,
                })?;
                let txt = txt.trim();
                txt.parse::<i32>().context(ReadIntSnafu {
                    position: self.position,
                })
            })
            .collect();
        self.position += len as u64;
        Ok(PrimitiveValue::I32(parts?))
    }
    fn read_value_tm(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        self.buffer.resize_with(len, Default::default);
        self.from
            .read_exact(&mut self.buffer)
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        let buf = trim_trail_empty_bytes(&self.buffer);
        if buf.is_empty() {
            return Ok(PrimitiveValue::Empty);
        }
        if validate_tm(buf) != TextValidationOutcome::Ok {
            let lossy_str = DefaultCharacterSetCodec
                .decode(buf)
                .unwrap_or_else(|_| "[byte stream]".to_string());
            return InvalidTimeValueSnafu {
                position: self.position,
                string: lossy_str,
            }
            .fail();
        }
        let vec: std::result::Result<_, _> = buf
            .split(|b| *b == b'\\')
            .map(|part| {
                parse_time_partial(part)
                    .map(|t| t.0)
                    .context(DeserializeValueSnafu {
                        position: self.position,
                    })
            })
            .collect();
        self.position += len as u64;
        Ok(PrimitiveValue::Time(vec?))
    }
    fn read_value_od(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 3;
        let mut vec = smallvec![0.; n];
        self.basic
            .decode_fd_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::F64(vec))
    }
    fn read_value_ul(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 2;
        let mut vec = smallvec![0u32; n];
        self.basic
            .decode_ul_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::U32(vec))
    }
    fn read_u32(&mut self, n: usize, vec: &mut Vec<u32>) -> Result<()> {
        let base = vec.len();
        vec.resize(base + n, 0);
        self.basic
            .decode_ul_into(&mut self.from, &mut vec[base..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += n as u64 * 4;
        Ok(())
    }
    fn read_value_us(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 1;
        let mut vec = smallvec![0; n];
        self.basic
            .decode_us_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        if header.tag == Tag(0x0028, 0x0103) {
            self.signed_pixeldata = vec.first().map(|rep| *rep != 0);
        }
        Ok(PrimitiveValue::U16(vec))
    }
    fn read_value_uv(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 3;
        let mut vec = smallvec![0; n];
        self.basic
            .decode_uv_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::U64(vec))
    }
    fn read_value_sl(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 2;
        let mut vec = smallvec![0; n];
        self.basic
            .decode_sl_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::I32(vec))
    }
    fn read_value_sv(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let len = self.require_known_length(header)?;
        let n = len >> 3;
        let mut vec = smallvec![0; n];
        self.basic
            .decode_sv_into(&mut self.from, &mut vec[..])
            .context(ReadValueDataSnafu {
                position: self.position,
            })?;
        self.position += len as u64;
        Ok(PrimitiveValue::I64(vec))
    }
}
impl<S, D, BD> StatefulDecoder<D, S, BD>
where
    D: DecodeFrom<S>,
    BD: BasicDecode,
    S: Read,
{
    fn set_character_set(&mut self, charset: SpecificCharacterSet) -> Result<()> {
        self.text = charset;
        Ok(())
    }
    fn read_value_cs(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        let out = self.read_value_strs(header)?;
        let parts = match &out {
            PrimitiveValue::Strs(parts) => parts,
            _ => unreachable!(),
        };
        if header.tag == Tag(0x0008, 0x0005) {
            if let Some(charset) = parts.first().map(|x| x.as_ref()).and_then(|name| {
                SpecificCharacterSet::from_code(name).or_else(|| {
                    tracing::warn!("Unsupported character set `{}`, ignoring", name);
                    None
                })
            }) {
                self.set_character_set(charset)?;
            }
        }
        Ok(out)
    }
}
impl<'a, D> StatefulDecode for &'a mut D
where
    D: StatefulDecode,
{
    type Reader = D::Reader;
    fn decode_header(&mut self) -> Result<DataElementHeader> {
        (**self).decode_header()
    }
    fn decode_item_header(&mut self) -> Result<SequenceItemHeader> {
        (**self).decode_item_header()
    }
    fn read_value(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        (**self).read_value(header)
    }
    fn read_value_preserved(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        (**self).read_value_preserved(header)
    }
    fn read_value_bytes(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        (**self).read_value_bytes(header)
    }
    fn read_to_vec(&mut self, length: u32, vec: &mut Vec<u8>) -> Result<()> {
        (**self).read_to_vec(length, vec)
    }
    fn read_u32_to_vec(&mut self, length: u32, vec: &mut Vec<u32>) -> Result<()> {
        (**self).read_u32_to_vec(length, vec)
    }
    fn read_to<W>(&mut self, length: u32, out: W) -> Result<()>
    where
        Self: Sized,
        W: std::io::Write,
    {
        (**self).read_to(length, out)
    }
    fn skip_bytes(&mut self, length: u32) -> Result<()> {
        (**self).skip_bytes(length)
    }
    fn position(&self) -> u64 {
        (**self).position()
    }
    fn seek(&mut self, position: u64) -> Result<()>
    where
        Self::Reader: Seek,
    {
        (**self).seek(position)
    }
}
impl<D, S, BD> StatefulDecode for StatefulDecoder<D, S, BD>
where
    D: DecodeFrom<S>,
    BD: BasicDecode,
    S: Read,
{
    type Reader = S;
    fn decode_header(&mut self) -> Result<DataElementHeader> {
        let mut header = self
            .decoder
            .decode_header(&mut self.from)
            .context(DecodeElementHeaderSnafu {
                position: self.position,
            })
            .map(|(header, bytes_read)| {
                self.position += bytes_read as u64;
                header
            })
            .map_err(From::from)?;
        if let Some(vr) = self.determine_vr_based_on_pixel_representation(header.tag) {
            header.vr = vr;
        }
        Ok(header)
    }
    fn decode_item_header(&mut self) -> Result<SequenceItemHeader> {
        self.decoder
            .decode_item_header(&mut self.from)
            .context(DecodeItemHeaderSnafu {
                position: self.position,
            })
            .map(|header| {
                self.position += 8;
                header
            })
            .map_err(From::from)
    }
    fn read_value(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        if header.length() == Length(0) {
            return Ok(PrimitiveValue::Empty);
        }
        match header.vr() {
            VR::SQ => {
                NonPrimitiveTypeSnafu {
                    position: self.position,
                }
                .fail()
            }
            VR::AT => self.read_value_tag(header),
            VR::AE | VR::AS | VR::PN | VR::SH | VR::LO | VR::UC | VR::UI => {
                self.read_value_strs(header)
            }
            VR::CS => self.read_value_cs(header),
            VR::UT | VR::ST | VR::UR | VR::LT => self.read_value_str(header),
            VR::UN | VR::OB => self.read_value_ob(header),
            VR::US | VR::OW => self.read_value_us(header),
            VR::SS => self.read_value_ss(header),
            VR::DA => self.read_value_da(header),
            VR::DT => self.read_value_dt(header),
            VR::TM => self.read_value_tm(header),
            VR::DS => self.read_value_ds(header),
            VR::FD | VR::OD => self.read_value_od(header),
            VR::FL | VR::OF => self.read_value_fl(header),
            VR::IS => self.read_value_is(header),
            VR::SL => self.read_value_sl(header),
            VR::SV => self.read_value_sv(header),
            VR::OL | VR::UL => self.read_value_ul(header),
            VR::OV | VR::UV => self.read_value_uv(header),
        }
    }
    fn read_value_preserved(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        if header.length() == Length(0) {
            return Ok(PrimitiveValue::Empty);
        }
        match header.vr() {
            VR::SQ => {
                NonPrimitiveTypeSnafu {
                    position: self.position,
                }
                .fail()
            }
            VR::AT => self.read_value_tag(header),
            VR::AE
            | VR::AS
            | VR::PN
            | VR::SH
            | VR::LO
            | VR::UC
            | VR::UI
            | VR::IS
            | VR::DS
            | VR::DA
            | VR::TM
            | VR::DT => self.read_value_strs(header),
            VR::CS => self.read_value_cs(header),
            VR::UT | VR::ST | VR::UR | VR::LT => self.read_value_str(header),
            VR::UN | VR::OB => self.read_value_ob(header),
            VR::US | VR::OW => self.read_value_us(header),
            VR::SS => self.read_value_ss(header),
            VR::FD | VR::OD => self.read_value_od(header),
            VR::FL | VR::OF => self.read_value_fl(header),
            VR::SL => self.read_value_sl(header),
            VR::OL | VR::UL => self.read_value_ul(header),
            VR::SV => self.read_value_sv(header),
            VR::OV | VR::UV => self.read_value_uv(header),
        }
    }
    fn read_value_bytes(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
        if header.length() == Length(0) {
            return Ok(PrimitiveValue::Empty);
        }
        match header.vr() {
            VR::SQ => {
                NonPrimitiveTypeSnafu {
                    position: self.position,
                }
                .fail()
            }
            _ => self.read_value_ob(header),
        }
    }
    fn position(&self) -> u64 {
        self.position
    }
    fn read_to_vec(&mut self, length: u32, vec: &mut Vec<u8>) -> Result<()> {
        self.read_to(length, vec)
    }
    fn read_u32_to_vec(&mut self, length: u32, vec: &mut Vec<u32>) -> Result<()> {
        self.read_u32((length >> 2) as usize, vec)
    }
    fn read_to<W>(&mut self, length: u32, mut out: W) -> Result<()>
    where
        Self: Sized,
        W: std::io::Write,
    {
        let length = u64::from(length);
        std::io::copy(&mut self.from.by_ref().take(length), &mut out).context(
            ReadValueDataSnafu {
                position: self.position,
            },
        )?;
        self.position += length;
        Ok(())
    }
    fn skip_bytes(&mut self, length: u32) -> Result<()> {
        std::io::copy(
            &mut self.from.by_ref().take(u64::from(length)),
            &mut std::io::sink(),
        )
        .context(ReadValueDataSnafu {
            position: self.position,
        })?;
        self.position += u64::from(length);
        Ok(())
    }
    fn seek(&mut self, position: u64) -> Result<()>
    where
        Self::Reader: Seek,
    {
        self.from
            .seek(SeekFrom::Start(position))
            .context(SeekReaderSnafu {
                position: self.position,
                new_position: position,
            })
            .map(|_| ())
    }
}
impl<D, S, BD> StatefulDecoder<D, S, BD>
where
    D: DecodeFrom<S>,
    BD: BasicDecode,
    S: Read,
{
    fn determine_vr_based_on_pixel_representation(&self, tag: Tag) -> Option<VR> {
        use dicom_core::dictionary::DataDictionary;
        if self.signed_pixeldata == Some(true)
            && StandardDataDictionary.by_tag(tag).map(|e| e.vr) == Some(VirtualVr::Xs)
        {
            Some(VR::SS)
        } else {
            None
        }
    }
}
fn trim_trail_empty_bytes(mut x: &[u8]) -> &[u8] {
    while x.last() == Some(&b' ') || x.last() == Some(&b'\0') {
        x = &x[..x.len() - 1];
    }
    x
}
#[cfg(test)]
mod tests {
    use super::{StatefulDecode, StatefulDecoder};
    use dicom_core::header::{DataElementHeader, HasLength, Header, Length, SequenceItemHeader};
    use dicom_core::{Tag, VR};
    use dicom_encoding::decode::basic::LittleEndianBasicDecoder;
    use dicom_encoding::decode::{
        explicit_le::ExplicitVRLittleEndianDecoder, implicit_le::ImplicitVRLittleEndianDecoder,
    };
    use dicom_encoding::text::{SpecificCharacterSet, TextCodec};
    use std::io::{Cursor, Seek, SeekFrom};
    const RAW: &'static [u8; 62] = &[
        0x02, 0x00, 0x02, 0x00, 0x55, 0x49, 0x1a, 0x00, 0x31, 0x2e, 0x32, 0x2e, 0x38, 0x34, 0x30,
        0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e,
        0x31, 0x2e, 0x31, 0x00, 0x02, 0x00, 0x10, 0x00, 0x55, 0x49, 0x14, 0x00, 0x31, 0x2e, 0x32,
        0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x31, 0x2e, 0x32, 0x2e,
        0x31, 0x00,
    ];
    fn is_stateful_decoder<T>(_: &T)
    where
        T: StatefulDecode,
    {
    }
    #[test]
    fn decode_data_elements() {
        let mut cursor = Cursor::new(&RAW[..]);
        let mut decoder = StatefulDecoder::new(
            &mut cursor,
            ExplicitVRLittleEndianDecoder::default(),
            LittleEndianBasicDecoder,
            SpecificCharacterSet::default(),
        );
        is_stateful_decoder(&decoder);
        {
            let elem = decoder.decode_header().expect("should find an element");
            assert_eq!(elem.tag(), Tag(2, 2));
            assert_eq!(elem.vr(), VR::UI);
            assert_eq!(elem.length(), Length(26));
            assert_eq!(decoder.position(), 8);
            let value = decoder
                .read_value(&elem)
                .expect("value after element header");
            assert_eq!(value.multiplicity(), 1);
            assert_eq!(value.string(), Ok("1.2.840.10008.5.1.4.1.1.1\0"));
            assert_eq!(decoder.position(), 8 + 26);
        }
        {
            let elem = decoder.decode_header().expect("should find an element");
            assert_eq!(elem.tag(), Tag(2, 16));
            assert_eq!(elem.vr(), VR::UI);
            assert_eq!(elem.length(), Length(20));
            assert_eq!(decoder.position(), 8 + 26 + 8);
            let value = decoder
                .read_value(&elem)
                .expect("value after element header");
            assert_eq!(value.multiplicity(), 1);
            assert_eq!(value.string(), Ok("1.2.840.10008.1.2.1\0"));
            assert_eq!(decoder.position(), 8 + 26 + 8 + 20);
            decoder.seek(8 + 26 + 8).unwrap();
            let value = decoder
                .read_value(&elem)
                .expect("value after element header");
            assert_eq!(value.multiplicity(), 1);
            assert_eq!(value.string(), Ok("1.2.840.10008.1.2.1\0"));
            assert_eq!(decoder.position(), 8 + 26 + 8 + 20 + 20);
        }
    }
    #[test]
    fn update_character_set() {
        const RAW: &'static [u8; 18] = &[
            0x08, 0x00, 0x05, 0x00, b'C', b'S', 0x0a, 0x00, b'I', b'S', b'O', b'_', b'I', b'R', b' ', b'1', b'9', b'2',
        ];
        let mut cursor = &RAW[..];
        let mut decoder = StatefulDecoder::new(
            &mut cursor,
            ExplicitVRLittleEndianDecoder::default(),
            LittleEndianBasicDecoder,
            SpecificCharacterSet::default(),
        );
        is_stateful_decoder(&decoder);
        let header = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(
            header,
            DataElementHeader {
                tag: Tag(0x0008, 0x0005),
                vr: VR::CS,
                len: Length(10),
            }
        );
        let value = decoder
            .read_value_preserved(&header)
            .expect("should read a value");
        assert_eq!(value.string(), Ok("ISO_IR 192"));
        assert_eq!(decoder.text.name(), "ISO_IR 192",);
    }
    #[test]
    fn decode_data_elements_with_position() {
        let data = {
            let mut x = vec![0; 128];
            x.extend(RAW);
            x
        };
        let mut cursor = Cursor::new(&data[..]);
        cursor.seek(SeekFrom::Start(128)).unwrap();
        let mut decoder = StatefulDecoder::new_with_position(
            &mut cursor,
            ExplicitVRLittleEndianDecoder::default(),
            LittleEndianBasicDecoder,
            SpecificCharacterSet::default(),
            128,
        );
        is_stateful_decoder(&decoder);
        {
            let elem = decoder.decode_header().expect("should find an element");
            assert_eq!(elem.tag(), Tag(2, 2));
            assert_eq!(elem.vr(), VR::UI);
            assert_eq!(elem.length(), Length(26));
            assert_eq!(decoder.position(), 128 + 8);
            let value = decoder
                .read_value(&elem)
                .expect("value after element header");
            assert_eq!(value.multiplicity(), 1);
            assert_eq!(value.string(), Ok("1.2.840.10008.5.1.4.1.1.1\0"));
            assert_eq!(decoder.position(), 128 + 8 + 26);
        }
        {
            let elem = decoder.decode_header().expect("should find an element");
            assert_eq!(elem.tag(), Tag(2, 16));
            assert_eq!(elem.vr(), VR::UI);
            assert_eq!(elem.length(), Length(20));
            assert_eq!(decoder.position(), 128 + 8 + 26 + 8);
            let value = decoder
                .read_value(&elem)
                .expect("value after element header");
            assert_eq!(value.multiplicity(), 1);
            assert_eq!(value.string(), Ok("1.2.840.10008.1.2.1\0"));
            assert_eq!(decoder.position(), 128 + 8 + 26 + 8 + 20);
            decoder.seek(128 + 8 + 26 + 8).unwrap();
            let value = decoder
                .read_value(&elem)
                .expect("value after element header");
            assert_eq!(value.multiplicity(), 1);
            assert_eq!(value.string(), Ok("1.2.840.10008.1.2.1\0"));
            assert_eq!(decoder.position(), 128 + 8 + 26 + 8 + 20 + 20);
        }
    }
    #[test]
    fn decode_nested_datasets() {
        const RAW: &'static [u8; 138] = &[
            0x01, 0x20, 0x00, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0xE0, 0x72, 0x00, 0x00, 0x00, 0x08, 0x00, 0x15, 0x11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00, 0x40, 0x11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00, 0x50, 0x11, 0x1a, 0x00, 0x00, 0x00, b'1', b'.', b'2', b'.', b'8', b'4', b'0', b'.', b'1', b'0', b'0', b'0', b'8', b'.',
            b'5', b'.', b'1', b'.', b'4', b'.', b'1', b'.', b'1', b'.', b'7', b'\0',
            0xFE, 0xFF, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xDD, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xDD, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x20, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, b'I', b'D', b'E', b'N', b'T', b'I', b'T', b'Y', 0xFE, 0xFF, 0xDD, 0xE0, 0x00, 0x00, 0x00, 0x00, ];
        let mut cursor = &RAW[..];
        let mut decoder = StatefulDecoder::new(
            &mut cursor,
            ImplicitVRLittleEndianDecoder::default(),
            LittleEndianBasicDecoder,
            SpecificCharacterSet::default(),
        );
        is_stateful_decoder(&decoder);
        let header = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(header.tag(), Tag(0x2001, 0x9000));
        assert_eq!(header.vr(), VR::UN);
        assert!(header.length().is_undefined());
        assert_eq!(decoder.position(), 8);
        let item_header = decoder
            .decode_item_header()
            .expect("should find an item header");
        assert_eq!(item_header, SequenceItemHeader::Item { len: Length(114) });
        assert_eq!(decoder.position(), 16);
        let header = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(header.tag(), Tag(0x0008, 0x1115));
        assert_eq!(header.vr(), VR::SQ);
        assert!(header.length().is_undefined());
        assert_eq!(decoder.position(), 24);
        let item_header = decoder
            .decode_item_header()
            .expect("should find an item header (ReferencedSeriesSequence)");
        assert!(matches!(
            item_header,
            SequenceItemHeader::Item {
                len,
            } if len.is_undefined()
        ));
        assert_eq!(decoder.position(), 32);
        let header = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(header.tag(), Tag(0x0008, 0x1140));
        assert_eq!(header.vr(), VR::SQ);
        assert!(header.length().is_undefined());
        assert_eq!(decoder.position(), 40);
        let item_header = decoder
            .decode_item_header()
            .expect("should find an item header (ReferencedImageSequence)");
        assert!(matches!(
            item_header,
            SequenceItemHeader::Item {
                len,
            } if len.is_undefined()
        ));
        assert_eq!(decoder.position(), 48);
        let header = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(header.tag(), Tag(0x0008, 0x1150));
        assert_eq!(header.vr(), VR::UI);
        assert_eq!(header.length(), Length(26));
        assert_eq!(decoder.position(), 56);
        let value = decoder
            .read_value(&header)
            .expect("should find a value after element header");
        assert_eq!(value.to_str(), "1.2.840.10008.5.1.4.1.1.7");
        assert_eq!(decoder.position(), 82);
        let item_header = decoder
            .decode_item_header()
            .expect("should find item delimiter");
        assert_eq!(item_header, SequenceItemHeader::ItemDelimiter);
        assert_eq!(decoder.position(), 90);
        let item_header = decoder
            .decode_item_header()
            .expect("should find sequence delimiter");
        assert_eq!(item_header, SequenceItemHeader::SequenceDelimiter);
        assert_eq!(decoder.position(), 98);
        let item_header = decoder
            .decode_item_header()
            .expect("should find item delimiter");
        assert_eq!(item_header, SequenceItemHeader::ItemDelimiter);
        assert_eq!(decoder.position(), 106);
        let item_header = decoder
            .decode_item_header()
            .expect("should find sequence delimiter");
        assert_eq!(item_header, SequenceItemHeader::SequenceDelimiter);
        assert_eq!(decoder.position(), 114);
        let header = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(header.tag(), Tag(0x2050, 0x0020));
        assert_eq!(header.vr(), VR::CS);
        assert_eq!(header.length(), Length(8));
        assert_eq!(decoder.position(), 122);
        let value = decoder
            .read_value(&header)
            .expect("value after element header");
        assert_eq!(value.multiplicity(), 1);
        assert_eq!(value.to_str(), "IDENTITY");
        assert_eq!(decoder.position(), 130);
        let item_header = decoder
            .decode_item_header()
            .expect("should find an item header");
        assert_eq!(item_header, SequenceItemHeader::SequenceDelimiter);
        assert_eq!(decoder.position(), 138);
    }
    #[test]
    fn decode_and_use_pixel_representation() {
        const RAW: &'static [u8; 20] = &[
            0x28, 0x00, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, ];
        let mut cursor = &RAW[..];
        let mut decoder = StatefulDecoder::new(
            &mut cursor,
            ImplicitVRLittleEndianDecoder::default(),
            LittleEndianBasicDecoder,
            SpecificCharacterSet::default(),
        );
        is_stateful_decoder(&decoder);
        let header_1 = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(
            header_1,
            DataElementHeader {
                tag: Tag(0x0028, 0x0103),
                vr: VR::US,
                len: Length(2),
            }
        );
        decoder
            .read_value(&header_1)
            .expect("Can read Pixel Representation");
        let header_2 = decoder
            .decode_header()
            .expect("should find an element header");
        assert_eq!(
            header_2,
            DataElementHeader {
                tag: Tag(0x0028, 0x0120),
                vr: VR::SS,
                len: Length(2),
            }
        );
    }
}