use {
    laddertypes::{TypeDict, morphism::Morphism},
};

#[derive(Clone, Debug)]
pub struct LdmcPrimCMorphism {
    pub symbol: String,
    pub type_args: Vec<(laddertypes::TypeID, String)>,
    pub src_type: laddertypes::TypeTerm,
    pub dst_type: laddertypes::TypeTerm,
    pub c_source: String
}

#[derive(Clone)]
pub enum LdmcMorphism {
    Primitive( LdmcPrimCMorphism ),
    LengthPrefixMap{
        length_prefix_type: laddertypes::TypeTerm,
        item_morph: Box<LdmcPrimCMorphism>
    },
    ValueDelimMap{
        delim: u64,
        item_morph: Box<LdmcPrimCMorphism>
    }
}

impl Morphism for LdmcMorphism {
    fn weight(&self) -> u64 {
        1
    }

    fn get_type(&self) -> laddertypes::MorphismType {
        match self {
            LdmcMorphism::Primitive(prim_morph) =>
                laddertypes::MorphismType {
                    src_type: prim_morph.src_type.clone().normalize(),
                    dst_type: prim_morph.dst_type.clone().normalize()
                },
            LdmcMorphism::LengthPrefixMap{ length_prefix_type, item_morph } => {
                laddertypes::MorphismType {
                    src_type: laddertypes::TypeTerm::App(vec![ length_prefix_type.clone(), item_morph.src_type.clone() ]),
                    dst_type: laddertypes::TypeTerm::App(vec![ length_prefix_type.clone(), item_morph.dst_type.clone() ]),
                }
            },
            LdmcMorphism::ValueDelimMap{ delim, item_morph } => {
                let value_delim_type = laddertypes::TypeTerm::App(vec![]);
                laddertypes::MorphismType {
                    src_type: laddertypes::TypeTerm::App(vec![ value_delim_type.clone(), item_morph.src_type.clone() ]),
                    dst_type: laddertypes::TypeTerm::App(vec![ value_delim_type.clone(), item_morph.dst_type.clone() ]),
                }
            }
        }.normalize()
    }

    fn map_morphism(&self, seq_type: laddertypes::TypeTerm) -> Option< Self > {
        match self {
            LdmcMorphism::Primitive(prim) => {
                let item_morph = Box::new(prim.clone());
/*
                if seq_type == self.length_prefix_type {
                */
                    Some(LdmcMorphism::LengthPrefixMap{
                        length_prefix_type: seq_type,
                        item_morph,
                    })
                    /*
                } else if seq_type == self.value_delim_type {
                    Some(LdmcMorphism::ValueDelimMap { delim, item_morph })
                } else {
                    None
                }
                */
            }
            _ => None
        }
    }
}