use cdtypes::{Error, cd::{sector::Sector, CD}};

pub fn check_edc(cd: &CD, sector_id: usize) -> Result<(), Error> {
    if let Some(sector) = cd.get_sector(sector_id) {
        if let Some((edc, _)) = sector.get_error_correction() {
            let mut sector = (*sector).clone();

            sector.calculate_edc();
            if let Some(calc_edc) = sector.get_edc() {
                println!("ISO EDC is:        {}", edc);
                println!("Calculated EDC is: {}", calc_edc);
            }
        }

        else {
            println!("No EDC");
        }

        Ok(())
    }

    else {
        Err(Error::GenericError(format!("Sector {} not found", sector_id)))
    }
}

pub fn check_ecc(cd: &CD, sector_id: usize) -> Result<(), Error> {
    if let Some(sector) = cd.get_sector(sector_id) {
        if let Some((_, Some(ecc))) = sector.get_error_correction() {
            let mut sector = (*sector).clone();

            sector.calculate_ecc();
            if let Some(calc_ecc) = sector.get_ecc() {
                if ecc == calc_ecc {
                    println!("ECC is same");
                }

                else {
                    println!("ECC is different");
                }
            }
        }

        else {
            println!("No ECC");
        }

        Ok(())
    }

    else {
        Err(Error::GenericError(format!("Sector {} not found", sector_id)))
    }    
}

pub fn dump(cd: &CD) -> Result<(), Error> {
    println!("{}", cd.get_primary_volume_descriptor()?);
    Ok(())
}

pub fn dump_root_dir_rec(cd: &CD, detailed: bool) -> Result<(), Error> {
    let root_dir = cd.get_primary_volume_descriptor()?.get_root_dir_record();

    dump_dir_rec(cd, root_dir.data_block_number.read_any() as usize, detailed)
}

pub fn dump_dir_rec(cd: &CD, sector_id: usize, detailed: bool) -> Result<(), Error> {
    for entry in cd.directory_record_iter(sector_id) {
        if detailed {
            println!("{}", entry)
        }

        else {
            let type_name = {
                if entry.is_file() {
                    "File"
                }

                else {
                    "Directory"
                }
            };
            println!("{}: {} @{}", type_name, entry.get_name(), entry.data_block_number.read_any());
        }
    }

    Ok(())
}

pub fn dump_path_table(cd: &CD) -> Result<(), Error> {
    let mut number = 1usize;

    for entry in cd.path_table_iter() {
        println!("{}.) {}", number, entry);
        number += 1;
    }

    Ok(())
}

pub fn dump_stats(cd: &CD) -> Result<(), Error> {
    let mut audio_count      = 0;
    let mut mode0_count      = 0;
    let mut mode1_count      = 0;
    let mut mode2form1_count = 0;
    let mut mode2form2_count = 0;

    for sector in cd.sector_iter() {
        match sector {
            Sector::Audio(_)     => audio_count      += 1,
            Sector::Empty(_)     => mode0_count      += 1,
            Sector::CDData(_)    => mode1_count      += 1,
            Sector::CDXAData(_)  => mode2form1_count += 1,
            Sector::CDXAAudio(_) => mode2form2_count += 1,
        }
    }

    println!("Audio:      {}\nMode0:      {}\nMode1:      {}\nMode2Form1: {}\nMode2Form2: {}", audio_count, mode0_count, mode1_count, mode2form1_count, mode2form2_count);
    Ok(())
}

pub fn dump_tracks(cd: &CD) -> Result<(), Error> {
    if cd.has_tracks() {
        let mut track_count = 1;

        for track_info in cd.track_info_iter() {
            println!("Track {:02}: {:<10} @{}", track_count, track_info.r#type, track_info.start);
            track_count += 1;
        }
    }

    else {
        println!("Track 01");
    }

    Ok(())
}