use std::fs::File;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Result;
use crate::VolatileSlice;
pub trait FileSync {
    fn fsync(&self) -> Result<()>;
    fn fdatasync(&self) -> Result<()>;
}
impl FileSync for File {
    fn fsync(&self) -> Result<()> {
        self.sync_all()
    }
    fn fdatasync(&self) -> Result<()> {
        self.sync_data()
    }
}
pub trait FileSetLen {
    fn set_len(&self, _len: u64) -> Result<()>;
}
impl FileSetLen for File {
    fn set_len(&self, len: u64) -> Result<()> {
        File::set_len(self, len)
    }
}
pub trait FileAllocate {
    fn allocate(&self, offset: u64, len: u64) -> Result<()>;
}
pub trait FileGetLen {
    fn get_len(&self) -> Result<u64>;
}
impl FileGetLen for File {
    fn get_len(&self) -> Result<u64> {
        Ok(self.metadata()?.len())
    }
}
pub trait FileReadWriteVolatile {
    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
    fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
        bufs.iter()
            .find(|b| b.size() > 0)
            .map(|&b| self.read_volatile(b))
            .unwrap_or(Ok(0))
    }
    fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
        while slice.size() > 0 {
            let bytes_read = self.read_volatile(slice)?;
            if bytes_read == 0 {
                return Err(Error::from(ErrorKind::UnexpectedEof));
            }
            slice = slice.offset(bytes_read).unwrap();
        }
        Ok(())
    }
    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;
    fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
        bufs.iter()
            .find(|b| b.size() > 0)
            .map(|&b| self.write_volatile(b))
            .unwrap_or(Ok(0))
    }
    fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
        while slice.size() > 0 {
            let bytes_written = self.write_volatile(slice)?;
            if bytes_written == 0 {
                return Err(Error::from(ErrorKind::WriteZero));
            }
            slice = slice.offset(bytes_written).unwrap();
        }
        Ok(())
    }
}
impl<T: FileReadWriteVolatile + ?Sized> FileReadWriteVolatile for &mut T {
    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
        (**self).read_volatile(slice)
    }
    fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
        (**self).read_vectored_volatile(bufs)
    }
    fn read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
        (**self).read_exact_volatile(slice)
    }
    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
        (**self).write_volatile(slice)
    }
    fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
        (**self).write_vectored_volatile(bufs)
    }
    fn write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
        (**self).write_all_volatile(slice)
    }
}
pub trait FileReadWriteAtVolatile {
    fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize>;
    fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
        if let Some(&slice) = bufs.first() {
            self.read_at_volatile(slice, offset)
        } else {
            Ok(0)
        }
    }
    fn read_exact_at_volatile(&self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
        while slice.size() > 0 {
            match self.read_at_volatile(slice, offset) {
                Ok(0) => return Err(Error::from(ErrorKind::UnexpectedEof)),
                Ok(n) => {
                    slice = slice.offset(n).unwrap();
                    offset = offset.checked_add(n as u64).unwrap();
                }
                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
    fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize>;
    fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
        if let Some(&slice) = bufs.first() {
            self.write_at_volatile(slice, offset)
        } else {
            Ok(0)
        }
    }
    fn write_all_at_volatile(&self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> {
        while slice.size() > 0 {
            match self.write_at_volatile(slice, offset) {
                Ok(0) => return Err(Error::from(ErrorKind::WriteZero)),
                Ok(n) => {
                    slice = slice.offset(n).unwrap();
                    offset = offset.checked_add(n as u64).unwrap();
                }
                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}
impl<T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &mut T {
    fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
        (**self).read_at_volatile(slice, offset)
    }
    fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
        (**self).read_vectored_at_volatile(bufs, offset)
    }
    fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
        (**self).read_exact_at_volatile(slice, offset)
    }
    fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
        (**self).write_at_volatile(slice, offset)
    }
    fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
        (**self).write_vectored_at_volatile(bufs, offset)
    }
    fn write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
        (**self).write_all_at_volatile(slice, offset)
    }
}
impl<T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &T {
    fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
        (**self).read_at_volatile(slice, offset)
    }
    fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
        (**self).read_vectored_at_volatile(bufs, offset)
    }
    fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
        (**self).read_exact_at_volatile(slice, offset)
    }
    fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
        (**self).write_at_volatile(slice, offset)
    }
    fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
        (**self).write_vectored_at_volatile(bufs, offset)
    }
    fn write_all_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
        (**self).write_all_at_volatile(slice, offset)
    }
}
#[cfg(test)]
mod tests {
    use std::io::Read;
    use std::io::Seek;
    use std::io::SeekFrom;
    use std::io::Write;
    use tempfile::tempfile;
    use super::*;
    #[test]
    fn read_file() -> Result<()> {
        let mut f = tempfile()?;
        f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA")
            .expect("Failed to write bytes");
        f.seek(SeekFrom::Start(0))?;
        let mut omem = [0u8; 30];
        let om = &mut omem[..];
        let buf = VolatileSlice::new(om);
        f.read_volatile(buf).expect("read_volatile failed.");
        f.seek(SeekFrom::Start(0))?;
        let mut mem = [0u8; 30];
        let (m1, rest) = mem.split_at_mut(10);
        let (m2, m3) = rest.split_at_mut(10);
        let buf1 = VolatileSlice::new(m1);
        let buf2 = VolatileSlice::new(m2);
        let buf3 = VolatileSlice::new(m3);
        let bufs = [buf1, buf2, buf3];
        f.read_vectored_volatile(&bufs)
            .expect("read_vectored_volatile failed.");
        assert_eq!(&mem[..], b"AAAAAAAAAAbbbbbbbbbbAAAAA\0\0\0\0\0");
        Ok(())
    }
    #[test]
    fn write_file() -> Result<()> {
        let mut f = tempfile()?;
        let mut omem = [0u8; 25];
        let om = &mut omem[..];
        let buf = VolatileSlice::new(om);
        buf.write_bytes(65);
        f.write_volatile(buf).expect("write_volatile failed.");
        f.seek(SeekFrom::Start(0))?;
        let mut filebuf = [0u8; 25];
        f.read_exact(&mut filebuf).expect("Failed to read filebuf");
        assert_eq!(&filebuf, b"AAAAAAAAAAAAAAAAAAAAAAAAA");
        Ok(())
    }
    #[test]
    fn write_vectored_file() -> Result<()> {
        let mut f = tempfile()?;
        let mut mem = [0u8; 30];
        let (m1, rest) = mem.split_at_mut(10);
        let (m2, m3) = rest.split_at_mut(10);
        let buf1 = VolatileSlice::new(m1);
        let buf2 = VolatileSlice::new(m2);
        let buf3 = VolatileSlice::new(m3);
        buf1.write_bytes(65);
        buf2.write_bytes(98);
        buf3.write_bytes(65);
        let bufs = [buf1, buf2, buf3];
        f.write_vectored_volatile(&bufs)
            .expect("write_vectored_volatile failed.");
        f.seek(SeekFrom::Start(0))?;
        let mut filebuf = [0u8; 30];
        f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
        assert_eq!(&filebuf, b"AAAAAAAAAAbbbbbbbbbbAAAAAAAAAA");
        Ok(())
    }
    #[test]
    fn read_at_file() -> Result<()> {
        let mut f = tempfile()?;
        f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA")
            .expect("Failed to write bytes.");
        let mut omem = [0u8; 20];
        let om = &mut omem[..];
        let buf = VolatileSlice::new(om);
        f.read_at_volatile(buf, 10)
            .expect("read_at_volatile failed.");
        assert_eq!(om, b"bbbbbbbbbbAAAAA\0\0\0\0\0");
        let mut mem = [0u8; 20];
        let (m1, m2) = mem.split_at_mut(10);
        let buf1 = VolatileSlice::new(m1);
        let buf2 = VolatileSlice::new(m2);
        let bufs = [buf1, buf2];
        f.read_vectored_at_volatile(&bufs, 10)
            .expect("read_vectored_at_volatile failed.");
        assert_eq!(&mem[..], b"bbbbbbbbbbAAAAA\0\0\0\0\0");
        Ok(())
    }
    #[test]
    fn write_at_file() -> Result<()> {
        let mut f = tempfile()?;
        f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ")
            .expect("Failed to write bytes");
        let mut omem = [0u8; 15];
        let om = &mut omem[..];
        let buf = VolatileSlice::new(om);
        buf.write_bytes(65);
        f.write_at_volatile(buf, 10)
            .expect("write_at_volatile failed.");
        f.seek(SeekFrom::Start(0))?;
        let mut filebuf = [0u8; 30];
        f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
        assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAAAAAAZZZZZ");
        Ok(())
    }
    #[test]
    fn write_vectored_at_file() -> Result<()> {
        let mut f = tempfile()?;
        f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ")
            .expect("Failed to write bytes");
        let mut mem = [0u8; 30];
        let (m1, m2) = mem.split_at_mut(10);
        let buf1 = VolatileSlice::new(m1);
        let buf2 = VolatileSlice::new(m2);
        buf1.write_bytes(65);
        buf2.write_bytes(98);
        let bufs = [buf1, buf2];
        f.write_vectored_at_volatile(&bufs, 10)
            .expect("write_vectored_at_volatile failed.");
        f.seek(SeekFrom::Start(0))?;
        let mut filebuf = [0u8; 30];
        f.read_exact(&mut filebuf).expect("Failed to read filebuf.");
        assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAbbbbbbbbbb");
        Ok(())
    }
}