{{~ for mod in __mod.sub_mods ~}}
pub mod {{mod.name}};
{{~end~}}

{{~ if __mod.name != '' ~}}
use super::*;
{{~end~}}
use luban_lib::*;

{{~ for enum in __mod.enums ~}}
{{~ if enum.comment != '' ~}}
///{{enum.comment | html.escape}}
{{~end~}}
{{~ if enum.is_flags ~}}
bitflags::bitflags!{    
    #[derive(Debug, Hash, Eq, PartialEq)]
    pub struct {{enum.name}} : u32 {
        {{~ for item in enum.items ~}}
    {{~if item.comment_or_alias != '' ~}}
        ///{{item.comment_or_alias | html.escape}}
    {{~end~}}
        const {{item.name}} = {{item.int_value}};
        {{~end~}}
    }
}
{{~else~}}
#[derive(Debug, Hash, Eq, PartialEq, macros::EnumFromNum)]
pub enum {{enum.name}} {
    {{~ for item in enum.items ~}}
{{~if item.comment_or_alias != '' ~}}
    ///{{item.comment_or_alias | html.escape}}
{{~end~}}
    {{item.name}} = {{item.value}},
    {{~end~}}
    {{~if enum.items.empty?~}}
    None
    {{~end~}}
}

impl From<i32> for {{enum.name}} {
    fn from(value: i32) -> Self {
        match value { 
            {{~ for item in enum.items ~}}
            {{item.value}} => {{enum.name}}::{{item.name}},
            {{~end~}}
            _ => panic!("Invalid value for {{enum.name}}:{}", value),
        }
    }
}

{{~end~}}
{{~end~}}
{{~ for bean in __mod.beans 
    hierarchy_fields = bean.hierarchy_export_fields
~}}
#[derive(Debug)]
{{~if bean.parent != ''~}}
#[derive(macros::TryIntoBase)]
{{~end~}}
pub struct {{bean.name}} {
    {{~ for field in hierarchy_fields ~}}
{{~if field.comment != '' ~}}
    /// {{escape_comment field.comment}}
{{~end~}}
    pub {{field.name}}: {{declaring_type_name field.ctype}},
    {{~end~}}
}
{{~if bean.is_abstract_type~}}

impl {{bean.name}} {
    pub fn new(mut buf: &mut ByteBuf) -> Result<std::sync::Arc<AbstractBase>, LubanError> {
        let type_id = buf.read_int();
        match type_id {
            {{~for child in bean.hierarchy_not_abstract_children~}}
            {{full_name child}}::__ID__ => Ok(std::sync::Arc::new({{full_name child}}::new(buf)?)),
            {{~end~}}
            _ => Err(LubanError::Bean(format!("Invalid type for {{bean.name}}:{}", type_id)))
        }
    }
}

pub trait T{{bean.name}} {
    {{~ for field in hierarchy_fields ~}}
    fn {{getter_name field.name}}(&self) -> &{{declaring_type_name field.ctype}};
    {{~end~}}
}
{{~for child in bean.hierarchy_not_abstract_children~}}

impl {{base_trait_name bean}} for {{full_name child}} {
    {{~ for field in hierarchy_fields ~}}
    fn {{getter_name field.name}}(&self) -> &{{declaring_type_name field.ctype}} {
        &self.{{field.name}}
    }
    {{~end~}}
}
{{~end~}}

impl<'a> GetBase<'a, &'a dyn {{base_trait_name bean}}> for AbstractBase {
    fn get_base(&'a self) -> Result<&'a dyn {{base_trait_name bean}}, LubanError> {
        {{~for child in bean.hierarchy_not_abstract_children~}}
        let base: Result<&{{full_name child}}, _> = self.try_into();
        if let Ok(r) = base {
            return Ok(r);
        }
        {{~end~}}

        Err(LubanError::Polymorphic(format!("Invalid type for {{bean.name}}")))
    }
}
{{~else~}}

impl {{bean.name}}{
    pub fn new(mut buf: &mut ByteBuf) -> Result<{{bean.name}}, LubanError> {
        {{~ for field in hierarchy_fields ~}}
        {{deserialize field.name 'buf' field.ctype}}
        {{~end~}}
        
        Ok({{bean.name}} { {{ for field in hierarchy_fields }}{{field.name}}, {{end}}})
    }

    pub const __ID__: i32 = {{bean.id}};
}
{{~end~}}

{{~end~}}
{{~ for table in __mod.tables
    key_type = declaring_type_name table.key_ttype
    if table.value_ttype.def_bean.is_abstract_type
        value_type = declaring_type_name table.value_ttype
    else
        value_type = "std::sync::Arc<"+declaring_type_name table.value_ttype+">"
    end
    name = table.name    
    map_type = "std::collections::HashMap<"+key_type+", "+value_type+">"
~}}
{{
    
    func index_type_name
        ret (declaring_type_name $0.type)
    end
    
    func table_union_map_type_name
        ret 'std::collections::HashMap<(' + (array.each table.index_list @index_type_name | array.join ', ') + '), ' + value_type  + '>'
    end
    
    func table_key_list
        varName = $0
        indexList = table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end;
        ret array.join indexList ', '
    end
    
    func table_param_def_list
        paramList = table.index_list |array.each do; ret (declaring_type_name $0.type) + ' ' + $0.index_field.name; end
        ret array.join paramList ', '
    end
    
    func table_param_name_list
        paramList = table.index_list |array.each do; ret $0.index_field.name; end
        ret array.join paramList ', '
    end
}}
{{~ if table.comment != '' ~}}
///{{table.comment | html.escape}}
{{~end~}}
#[derive(Debug)]
pub struct {{table.name}} {
    {{~if table.is_map_table ~}}
    pub data_list: Vec<{{value_type}}>,
    pub data_map: {{map_type}},
    {{~else if table.is_list_table ~}}
    pub data_list: Vec<{{value_type}}>,
    {{~if table.is_union_index~}}    
    pub data_map_union: {{table_union_map_type_name}},
    {{~else if !table.index_list.empty?~}}
    {{~for idx in table.index_list~}}
    pub data_map_{{idx.index_field.name}}: std::collections::HashMap<{{declaring_type_name idx.type}}, {{value_type}}>,
    {{~end~}}
    {{~end~}}    
    {{~else~}}
    pub data: {{declaring_type_name table.value_ttype}},
    {{~end~}}
}
{{~if table.is_map_table ~}}

impl {{name}} {
    pub fn new(mut buf: ByteBuf) -> Result<std::sync::Arc<{{name}}>, LubanError> {
        let mut data_map: {{map_type}} = Default::default();
        let mut data_list: Vec<{{value_type}}> = vec![];

        for x in (0..buf.read_size()).rev() {
            {{deserialize_row "row" "buf" table.value_ttype}}
            data_list.push(row.clone());
            {{~ if table.value_ttype.def_bean.is_abstract_type ~}}
            let key = <AbstractBase as GetBase<&dyn {{base_trait_name table.value_ttype.def_bean}}>>::get_base(std::ops::Deref::deref(&row))?;
            data_map.insert(key.{{getter_name table.index_field.name}}().clone(), row.clone());
            {{~else~}}
            data_map.insert(row.{{table.index_field.name}}.clone(), row.clone());
            {{~end~}}
        }

        Ok(std::sync::Arc::new({{name}} { data_map, data_list }))
    }

    pub fn get(&self, key: &{{key_type}}) -> Option<{{value_type}}> {
        self.data_map.get(key).map(|x| x.clone())
    }
}

impl std::ops::Index<{{key_type}}> for {{name}} {
    type Output = {{value_type}};

    fn index(&self, index: {{key_type}}) -> &Self::Output {
        &self.data_map.get(&index).unwrap()
    }
}
{{~else if table.is_list_table ~}}

impl {{name}} {
    pub fn new(mut buf: ByteBuf) -> Result<std::sync::Arc<{{name}}>, LubanError> {
        let mut data_list: Vec<{{value_type}}> = vec![];

        for x in (0..buf.read_size()).rev() {
            {{deserialize_row "row" "buf" table.value_ttype}}
            data_list.push(row.clone());
        }
    {{~if table.is_union_index~}}
        let mut data_map_union: {{table_union_map_type_name}} = Default::default();
        for x in &data_list {
            data_map_union.insert(({{table_key_list "x"}}.clone()), x.clone());
        }
    {{~else if !table.index_list.empty?~}}
        {{~for idx in table.index_list~}}
        let mut data_map_{{idx.index_field.name}}: std::collections::HashMap<{{declaring_type_name idx.index_field.ctype}}, {{value_type}}> = Default::default();
        {{~end~}}
        for x in &data_list {
        {{~for idx in table.index_list~}}
            data_map_{{idx.index_field.name}}.insert(x.{{format_property_name __code_style idx.index_field.name}}.clone(), x.clone());
        {{~end~}}
        }
    {{~end~}}

    Ok(std::sync::Arc::new({{table.name}} { 
            data_list,
{{~if table.is_union_index~}}
            data_map_union,
{{~else if !table.index_list.empty?~}}
    {{~for idx in table.index_list~}}
            data_map_{{idx.index_field.name}},
    {{~end~}}
{{~end~}}
        }))
    }

    {{~if table.is_union_index~}}
    pub fn get(&self, key: &({{array.each table.index_list @index_type_name | array.join ', '}})) -> Option<{{value_type}}> {
        self.data_map_union.get(key).map(|x| x.clone())
    }
    {{~else if !table.index_list.empty? ~}}
    {{~for idx in table.index_list
        index = format_property_name __code_style idx.index_field.name
    ~}}
    pub fn get_by_{{index}}(&self, key: &{{declaring_type_name idx.type}}) -> Option<{{value_type}}> {
        self.data_map_{{index}}.get(key).map(|x| x.clone())
    }
    {{~end~}}
    {{~end~}}
}
{{~else~}}

impl {{name}} {
    pub fn new(mut buf: ByteBuf) -> Result<std::sync::Arc<{{name}}>, LubanError> {
        let n = buf.read_size();
        if n != 1 { return Err(LubanError::Table(format!("table mode=one, but size != 1"))); }
        {{deserialize 'data' 'buf' table.value_ttype}}
        Ok(std::sync::Arc::new({{name}} { data }))
    }
}
{{~end~}}

{{~end~}}
