pub mod target_morph;

use {
    crate::{
        c_gen::types::{
            get_c_repr_arg_type,
            get_c_repr_definition,
            get_c_repr_type
        },
        morphism::LdmcPrimMorph
    },
    laddertypes::{TypeDict, Substitution},
};

impl LdmcPrimMorph {
    pub fn instantiated_symbol_name(&self, dict: &mut impl TypeDict, σ: &impl Substitution) -> String {
        let mut s = self.symbol.clone();
        for (k_id,v) in self.type_args.iter() {
            if let Some(val_trm) = σ.get(k_id) {
                if let laddertypes::TypeID::Var(var_id) = k_id {

                    //if self.get_type().strip_halo().src_type.contains_var(*var_id) ||
                    //self.get_type().strip_halo().dst_type.contains_var(*var_id) {

                        let name = dict.get_varname(*var_id).unwrap();
                        let val_str = get_c_repr_type(dict, &val_trm);
                        s.push_str(&format!("_{}_{}", name, val_str));

                    //}
                }
            } else {
                if let laddertypes::TypeID::Var(var_id) = k_id {
                    let k = dict.get_varname(*var_id).unwrap();
                    s.push_str(&format!("_{:?}_MISSING", k));
                    eprintln!("INCOMPLETE MORPHISM INSTANTIATION, missing type parameter {} ({})", k, var_id);
                }
            }
        }
        s
    }

    pub fn expected_c_type_signature(&self, dict: &mut impl TypeDict,
        σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>
    ) -> String {
        format!("int {} ({} const * restrict src, {} * restrict dst);",
            self.instantiated_symbol_name(dict, σ),
            get_c_repr_definition(dict, self.ty.src_type.clone(), true).expect("cant get c-repr type for src type"),
            get_c_repr_definition(dict, self.ty.dst_type.clone(), true).expect("cant get c-repr type for dst type"))
    }

    pub fn generate_instantiation(&self, dict: &mut impl TypeDict, σ: &impl Substitution) -> Option<String> {
        let mut s = String::new();
        let symbol = self.instantiated_symbol_name(dict, σ);

        eprintln!("generate instantiation:");
        let ty = self.ty.clone();
        eprintln!("full type: {}   ---->    {}", ty.src_type.pretty(dict, 0),  ty.dst_type.pretty(dict,0));
        let ty = ty.strip_halo().apply_subst(σ);
        eprintln!("stripped type:  {}   ---->    {}", ty.src_type.pretty(dict, 0),  ty.dst_type.pretty(dict,0));

        let src_c_symbol = get_c_repr_arg_type(dict, &ty.src_type);
        let dst_c_symbol = get_c_repr_arg_type(dict, &ty.dst_type);

        s.push_str(&format!(r#"
int {} ( {} const * restrict src, {} * restrict dst ) {{
"#,
            symbol, src_c_symbol, dst_c_symbol,
        ));
        s.push_str(&self.c_source);
        s.push_str(&format!(r#"
    return 0;
}}
"#));
        Some(s)
    }
}