pub mod bin_cue;

pub use cdtypes::{cd::sector::Sector, types::*};
use sector::Mode0;

use crate::types::helper::InterleavedXASector;
use super::{encoder::cd::encode_image, types::CDDesc};
use bin_cue::BinCueWriter;
use clap::ValueEnum;
use std::path::PathBuf;
use tool_helper::{Error, open_output_file};

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum ImageType {
    BinCue
}

pub trait SectorWriter {
    fn write_audio(&mut self, sector: sector::Audio) -> Result<usize, Error> {
        self.write(Sector::Audio(sector))
    }
    
    fn write_empty(&mut self, sector: sector::Mode0) -> Result<usize, Error> {
        self.write(Sector::Empty(sector))
    }

    fn write_cd_data(&mut self, sector: sector::Mode1) -> Result<usize, Error> {
        self.write(Sector::CDData(sector))
    }

    fn write_cd_xa_data(&mut self, sector: sector::Mode2Form1) -> Result<usize, Error> {
        self.write(Sector::CDXAData(sector))
    }

    fn write_cd_xa_audio(&mut self, sector: sector::Mode2Form2) -> Result<usize, Error> {
        self.write(Sector::CDXAAudio(sector))
    }
    
    fn write_interleaved(&mut self, sector: InterleavedXASector) -> Result<usize, Error> {
        match sector {
            InterleavedXASector::Empty         => self.write_empty(Mode0::new()),
            InterleavedXASector::Data(sector)  => self.write_cd_xa_data(sector),
            InterleavedXASector::Audio(sector) => self.write_cd_xa_audio(sector),
        }
    }

    fn write(&mut self, sector: Sector) -> Result<usize, Error>;
    fn cd_da_start(&mut self)           -> Result<(), Error>;
    fn sectors_to_next_second(&self)    -> usize;
}

pub fn write_image(cd_desc: &CDDesc, image_type: ImageType, mut output_path: PathBuf) -> Result<(), Error> {
    match image_type {
        ImageType::BinCue => {
            output_path.set_extension("bin");

            let cue_output_path = {
                let mut cue_output_path = output_path.clone();

                cue_output_path.set_extension("cue");
                cue_output_path
            };

            let mut writer = BinCueWriter::new(open_output_file(&output_path)?, &output_path)?;
            
            encode_image(cd_desc, &mut writer)?;
            writer.write_cue(open_output_file(&cue_output_path)?)
        }
    }
}