use super::super::types::{OverlayDesc, OverlaySection};
use tool_helper::{Error, Output};
use std::io::Write;

macro_rules! section_end_name_template {
    () => {
      "__{}_end"  
    };
}

pub fn write(output: &mut Output, overlay_desc: &OverlayDesc) -> Result<(), Error> {
    let     has_overlays   = !overlay_desc.is_empty();
    let mut slot_start_adr = format!(section_end_name_template!(), "engine_bss");

    writeln!(output, "")?;
    writeln!(output, "SECTIONS {{")?;
        writeln!(output, "\t/DISCARD/ : {{ *(.comment*) *(.gnu.*) *(.mdebug*) *(.debug_*) *(.pdr)}}")?;
        for slot in overlay_desc {
            writeln!(output, "\t/*{}*/", slot.name)?;
            writeln!(output, "\tOVERLAY {} : NOCROSSREFS SUBALIGN(4) {{", slot_start_adr)?;
                write_section(output, &slot.sections, false)?;
            writeln!(output, "\t}} > ram_alt")?;
            writeln!(output, "\t. = ALIGN(4);")?;
            writeln!(output, concat!("\t", section_end_name_template!(), " = .;"), slot.name)?;
            writeln!(output, "")?;

            slot_start_adr = format!(section_end_name_template!(), slot.name);
        }
    
    if has_overlays {
        writeln!(output, "\t__persistent_overlay_end = .;")?;
    }

    else {
        writeln!(output, "\t__persistent_overlay_end =__engine_bss_end;")?;
    }
    writeln!(output, "}}")?;
    return Ok(());
}

fn write_section(output: &mut Output, sections: &Vec<OverlaySection>, add_end_name: bool) -> Result<(), Error> {
    for section in sections {
        writeln!(output, "\t\t.{} {{", section.name)?;
            writeln!(output, "\t\t\t__{}_start = .;", section.name)?;
            writeln!(output, "\t\t\t__{}_lbas = .;", section.name)?;
            section.file_pattern.iter().try_for_each(|patr| writeln!(output, "\t\t\tKEEP({}(.header.lbas))", patr))?;
            writeln!(output, "\t\t\t__{}_ctor = .;", section.name)?;

            for (section_type, keep) in [(".text.startup._GLOBAL__*", false), (".ctors", false), (".text.*", false), (".rodata*", false), (".sdata*", false), (".data*", false), (".sbss*", false), (".bss*", false), (".keep.dummy", true)] {
                section.file_pattern.iter().try_for_each(|patr| {
                    let section_entry = format!("{}({})", patr, section_type);
                    
                    write!(output, "\t\t\t")?;
                    if keep {
                        writeln!(output, "KEEP({})", section_entry)
                    }
                    
                    else {
                        writeln!(output, "{}", section_entry)
                    }
                })?;
            }

            if add_end_name {
                writeln!(output, concat!("\t\t\t", section_end_name_template!(), " = .;"), section.name)?;
            }
        writeln!(output, "\t\t}}")?;
    }

    Ok(())
}