use std::io::BufReader;

use byteorder::{BigEndian, ReadBytesExt};

use vfile::util::buf::previewer::BufPreviewer;

use crate::chopper::error::Result;
use crate::source::source::Source;
use crate::source::source_factory::{ChopperSourceFactory, SourceFactory};
use crate::util::dc_factory::DCFactory;
use crate::util::dc_util;

#[derive(Clone)]
pub struct DCSourceFactory {
    dc_factory: DCFactory,
}

impl DCSourceFactory {
    pub fn new(dc_factory: DCFactory) -> DCSourceFactory {
        DCSourceFactory { dc_factory }
    }
}

impl SourceFactory<Box<dyn Source>, ()> for DCSourceFactory {
    fn can_create_from_format(&self, format: &str) -> bool {
        format.ends_with(".dc")
    }

    fn can_create_from_previewer(&self, previewer: &BufPreviewer) -> bool {
        let buf = previewer.buf();
        let mut reader = BufReader::new(buf.as_slice());

        match reader.read_u64::<BigEndian>() {
            Ok(magic_num) => {
                if &magic_num != &dc_util::MAGIC_NUM {
                    return false;
                }
            }
            Err(_) => return false,
        }

        match reader.read_u16::<BigEndian>() {
            Ok(version) => {
                if &version != &dc_util::VERSION {
                    return false;
                }
            }
            Err(_) => return false,
        };

        true
    }

    fn create_source(&self, previewer: BufPreviewer, _: ()) -> Result<Box<dyn Source>> {
        let reader = previewer.into_reader();
        Ok(Box::new(self.dc_factory.new_source(reader)?))
    }

    fn box_clone(&self) -> Box<ChopperSourceFactory> {
        Box::new((*self).clone())
    }
}
