def define_class(classname, classinfo, filename):
    t = tp('''
struct ${class_name} {
    %if class_info.get_type() == 'map_type':
        %for field in class_info.get_value():
        <%
            item_key_type, item_value_type = field.get_item_type()
            item_key, item_value = field.get_value()
        %>
        %if item_value_type == 'list_type':
    std::vector<${field.get_value_value().get_one_item_value().get_value().get_name()}> ${item_key.get_value()};
        %elif item_value_type == 'map_type':
    ${item_key.get_value()} ${item_key.get_value()};
        %else:
    ${field.value.get_name()} ${item_key.get_value()};
        %endif
        %endfor
    %elif class_info.get_type() == 'list_type':
    <%
        print class_info.items[0]
        item_value = class_info.get_one_item_value()
        item_name = None
        try:
            item_name = item_value.get_value().get_name()
        except:
            item_name = item_value.get_name()
    %>
    std::vector<${item_name}> ${class_info.get_name()};
    %else:

    %endif
};

''')
    return t.render(class_info=classinfo, class_name=classname, fn=filename)
def add_cpp_info(struct_info, hpp_filename):
    buf = '#include "%s"' %hpp_filename
    buf +=('''
    <%
    struct_info = struct_info_object
    field_counts = len(struct_info.fields);
    %>
    %for i in xrange(field_counts):
    <%
    cur_field_name = struct_info.fields[i]["field_name"]
    cur_field_type = struct_info.fields[i]["field_type"]
    if cur_field_type == "char*" or cur_field_type == "string":
        cur_field_type = "std::string"
    %>

    <%
    if cur_field_type == "std::string":
        param_type = 'const std::string &'
    else:
        param_type = 'int'
    %>

void ${struct_info_object.name}::set_${cur_field_name} (${param_type} ${cur_field_name}_) {
    this->${cur_field_name} = ${cur_field_name}_;
}

const ${cur_field_type}& ${struct_info_object.name}::get_${cur_field_name}() {
    return ${cur_field_name};
}

const ${cur_field_type}& ${struct_info_object.name}::get_${cur_field_name}() const{
    return ${cur_field_name};
}
%endfor

sqlite3_generator::type_info ${struct_info_object.name}::get_field(const std::string &field_name) {
    sqlite3_generator::type_info ti;
    %for i in xrange(field_counts):
    <%
    cur_field_name = struct_info.fields[i]["field_name"]
    cur_field_type = struct_info.fields[i]["field_type"]
    %>
    if ( field_name == "${cur_field_name}" ) {
    %if cur_field_type == "int":
        ti.type = sqlite3_generator::type_info::integer;
    %elif cur_field_type == "char*" or cur_field_type == "string" or cur_field_type == "std::string":
        ti.type = sqlite3_generator::type_info::string;
    %else:
        assert(false);
    %endif
        ti.data = static_cast<void *>(&this->${cur_field_name});
    }
    %endfor
    return ti;
}
''')
    t = tp(buf)
    return t.render(struct_info_object=struct_info)
def add_hpp_info(struct_info, hpp_filename=''):
    t = tp('''
class ${struct_info_object.name} : public sqlite3_generator::base_column {
private:
    <%
    struct_info = struct_info_object
    field_counts = len(struct_info.fields)
    %>
    %for i in xrange(field_counts):
    <%
    cur_field_name = struct_info.fields[i]["field_name"]
    cur_field_type = struct_info.fields[i]["field_type"]
    if cur_field_type == "char*" or cur_field_type == "string":
        cur_field_type = "std::string"
    %>
    ${cur_field_type} ${cur_field_name};
    %endfor

public:
    <%
    struct_info = struct_info_object
    field_counts = len(struct_info.fields);
    %>
    %for i in xrange(field_counts):
    <%
    cur_field_name = struct_info.fields[i]["field_name"]
    cur_field_type = struct_info.fields[i]["field_type"]
    if cur_field_type == "char*" or cur_field_type == "string":
        cur_field_type = "std::string"
    %>

    <%
    if cur_field_type == "std::string":
        param_type = 'const std::string &'
    else:
        param_type = 'int'
    %>

    void set_${cur_field_name} (${param_type} ${cur_field_name}_);
    const ${cur_field_type}& get_${cur_field_name}();
    const ${cur_field_type}& get_${cur_field_name}() const;
    %endfor
    sqlite3_generator::type_info get_field(const std::string &field_name);
};
    ''')
    return t.render(struct_info_object=struct_info)
    def __str__(self):
        decl_tp = tp('''
%for struct in all_structs:
class ${struct["struct_name"]} {
public:
    %for field in struct["fields"]:
    ${field.type_name["name"]}  ${field.field_name};
    %endfor
public:
    bool decode(const std::string &jsonbuf);
    void decode_from_json_object(const Json::Value &jsonobj);
    Json::Value encode_to_json_object();
    std::string encode(bool readable);
};
%endfor
''')
        decl = decl_tp.render(all_structs=self.structs)
        return decl
    def __str__(self):
        from mako.template import Template as tp
        info = tp('''
        %for struct in this.structs:
class ${struct["struct_name"]} {
public:
            %for field in struct["fields"]:
    ${str(field)};
            %endfor
public:
    bool decode(const std::string &jsonbuf);
    void decode_from_json_object(const Json::Value &jsonobj);
    Json::Value encode_to_json_object();
    std::string encode(bool readable);
};
        %endfor
''')
        return info.render(this=self)
def add_struct_info(struct_info):
    t = tp('''
class ${struct_info_object.name} : public sqlite3_generator::base_column {
private:
    <%
    struct_info = struct_info_object
    field_counts = len(struct_info.fields)
    %>
    %for i in xrange(field_counts):
    <%
    cur_field_name = struct_info.fields[i]["field_name"]
    cur_field_type = struct_info.fields[i]["field_type"]
    if cur_field_type == "char*" or cur_field_type == "string":
        cur_field_type = "std::string"
    %>
    ${cur_field_type} ${cur_field_name};
    %endfor
public:
    <%
    struct_info = struct_info_object
    field_counts = len(struct_info.fields);
    %>
    %for i in xrange(field_counts):
    <%
    cur_field_name = struct_info.fields[i]["field_name"]
    cur_field_type = struct_info.fields[i]["field_type"]
    if cur_field_type == "char*" or cur_field_type == "string":
        cur_field_type = "std::string"
    %>

    <%
    if cur_field_type == "std::string":
        param_type = 'const std::string &'
    else:
        param_type = 'int'
    %>

    void set_${cur_field_name} (${param_type} ${cur_field_name}_) {
        this->${cur_field_name} = ${cur_field_name}_;
    }

    const ${cur_field_type}& get_${cur_field_name}() {
        return ${cur_field_name};
    }

    const ${cur_field_type}& get_${cur_field_name}() const{
        return ${cur_field_name};
    }
    %endfor

    sqlite3_generator::type_info get_field(const std::string &field_name) {
        sqlite3_generator::type_info ti;
        %for i in xrange(field_counts):
        <%
        cur_field_name = struct_info.fields[i]["field_name"]
        cur_field_type = struct_info.fields[i]["field_type"]
        %>
        if ( field_name == "${cur_field_name}" ) {
        %if cur_field_type == "int":
            ti.type = sqlite3_generator::type_info::integer;
        %elif cur_field_type == "char*" or cur_field_type == "string" or cur_field_type == "std::string":
            ti.type = sqlite3_generator::type_info::string;
        %else:
            assert(false);
        %endif
            ti.data = static_cast<void *>(&this->${cur_field_name});
        }
        %endfor
        return ti;
    }
};''')
    return t.render(struct_info_object=struct_info)
    def template_init(self):
        self.template = tp('''
void ${struct["struct_name"]}::decode_from_json_object(const Json::Value &root)
{
    Json::Value tmp;
    %for field in struct["fields"]:

    <%
        field_name = field.field_name
        type_name = field.type_name["type"]
    %>
    %if type_name == 'builtin' or type_name == 'userdefine':
    if ( root.isObject() && root.isMember("${field_name}") ) {
        tmp = root["${field_name}"];
        if ( !tmp.isNull() )
        {
            %if field.type_name["name"] == 'int':
            ${field_name} = tmp.asInt();
            %elif field.type_name["name"] == 'string' or field.type_name["name"] == 'std::string':
            ${field_name} = tmp.asString();
            %elif field.type_name["type"] == 'userdefine':
            ${field_name}.decode_from_json_object(tmp);
            %else:
            <%
                assert(False)
            %>
            %endif
        }
    }
    %endif
    %endfor

    %for field in struct["fields"]:
    <%
        field_name = field.field_name
    %>
    %if field.type_name["type"] == 'vector':
    <%
        type_name = field.type_name["sub_type"]
    %>
    if ( root.isObject() && root.isMember("${field_name}") ) {
        const Json::Value &array_${field_name} = root["${field_name}"];
        if ( !array_${field_name}.isNull() )
        {
            int size = array_${field_name}.size();
            for ( int i = 0; i < size; i++ ) {
                %if type_name == 'int':
                ${field_name}.push_back(array_${field_name}[i].asInt());
                %elif type_name == 'std::string' or type_name == 'string':
                ${field_name}.push_back(array_${field_name}[i].asString());
                %else:
                ${type_name} item;
                item.decode_from_json_object(array_${field_name}[i]);
                ${field_name}.push_back(item);
                %endif
            }
        }
    }
    %elif field.type_name["type"] == 'map':
    if ( root.isObject() && root.isMember("${field_name}") ) {
        const Json::Value map_${field_name} = root["${field_name}"];
        if ( !map_${field_name}.isNull() ) {
            for( Json::ValueIterator it = map_${field_name}.begin(); it != map_${field_name}.end(); ++it ) {
            <%
                key_type_name = field.type_name["sub_type"]["key"]
                value_type_name = field.type_name["sub_type"]["value"]
                if key_type_name == 'std::string' or key_type_name == 'string':
                    key_function = 'asString()'
                elif key_type_name == 'int':
                    key_function = 'asInt()'
                else:
                    assert(False)
                if value_type_name == 'std::string' or value_type_name == 'string':
                    value_function = 'asString()'
                elif value_type_name == 'int':
                    value_function = 'asInt()'
                else:
                    assert(False)
            %>
                std::string key = it.key().${key_function};
                ${field_name}[key] = map_${field_name}[key].${value_function};
            }
        }
    }   
    %endif
    %endfor
}

bool ${struct["struct_name"]}::decode(const std::string &jsonbuf)
{
    Json::Reader reader;
    Json::Value root;
    if ( !reader.parse(jsonbuf, root) ) {
        return false;
    }
    decode_from_json_object(root);
    return true;
}

Json::Value ${struct["struct_name"]}::encode_to_json_object()
{
    Json::Value root(Json::objectValue);

    %for field in struct["fields"]:

    <%
        field_name = field.field_name
        type_name = field.type_name["type"]
    %>
    %if field.type_name["name"] == 'int' or field.type_name["name"] == 'string' or field.type_name["name"] == 'std::string':
    root["${field_name}"] = ${field_name};
    %elif type_name == 'userdefine':
    root["${field_name}"] = ${field_name}.encode_to_json_object();
    %endif
    %endfor


    int size = 0;
    int i = 0;
    %for field in struct["fields"]:
    <%
        field_name = field.field_name
        type_name = field.type_name["type"]
    %>
    %if field.type_name["type"] == 'vector':
    size = ${field_name}.size();
    root["${field_name}"] = Json::Value(Json::arrayValue);
    <%
    type_name = field.type_name["sub_type"]
    %>
    for ( i = 0; i < size; i++ ) {
        %if type_name == 'int' or type_name == 'string' or type_name == 'std::string':
        root["${field_name}"].append(${field_name}[i]);
        %else:
        root["${field_name}"].append(${field_name}[i].encode_to_json_object());
        %endif
    }
    // map in map, how to do ?
    %elif field.type_name["type"] == 'map':
    <%
        key_type_name = field.type_name["sub_type"]["key"]
        value_type_name = field.type_name["sub_type"]["value"]

    %>
    root["${field_name}"] = Json::Value(Json::objectValue);
    for ( std::map< ${key_type_name}, ${value_type_name} >::iterator it = ${field_name}.begin(); it != ${field_name}.end(); ++it) {
        root["${field_name}"][(*it).first] = (*it).second;
    }
    %endif
    %endfor
    return root;
}

std::string ${struct["struct_name"]}::encode(bool readable)
{
    Json::Value root = encode_to_json_object();
    if ( readable )
    {
        Json::StyledWriter writer;
        return writer.write(root);
    }
    else
    {
        Json::FastWriter writer;
        return writer.write(root);
    }
}

''')
    def template_init(self):
        self.template = tp('''
void ${struct["struct_name"]}::decode_from_json_object(const Json::Value &root)
{
    Json::Value tmp;
    %for field in struct["fields"]:

        %if field.container == 'NULL':
        <%
            field_name = field.field_name
            type_name = field.type_name
        %>
    if ( root.isObject() && root.isMember("${field_name}") )
    {
        tmp = root["${field_name}"];
        if ( !tmp.isNull() )
        {
            %if field.is_type_basic:
                %if type_name == 'int':
            ${field_name} = tmp.asInt();
                %else:
            ${field_name} = tmp.asString();
                %endif
            %else:
            ${field_name}.decode_from_json_object(tmp);
            %endif
        }
    }
    %endif
    %endfor

    int size = 0;
    int i = 0;
    %for field in struct["fields"]:
    <%
        field_name = None
        type_name = None
        if field.container == 'vector':
            field_name = field.field_name
            type_name = field.type_name
    %>
    %if field_name:
    if ( root.isObject() && root.isMember("${field_name}") )
    {
        Json::Value array_${field_name} = root["${field_name}"];
        if ( !array_${field_name}.isNull() )
        {
            size = array_${field_name}.size();
            for ( i = 0; i < size; i++ ) {
                %if field.is_type_basic:
                    %if type_name == 'int':
                ${field_name}.push_back(array_${field_name}[i].asInt());
                    %else:
                ${field_name}.push_back(array_${field_name}[i].asString());
                    %endif
                %else:
                ${type_name} item;
                item.decode_from_json_object(array_${field_name}[i]);
                ${field_name}.push_back(item);
                %endif
            }
        }
    }
    %endif
    %endfor
}

bool ${struct["struct_name"]}::decode(const std::string &jsonbuf)
{
    Json::Reader reader;
    Json::Value root;
    if ( !reader.parse(jsonbuf, root) ) {
        return false;
    }
    decode_from_json_object(root);
    return true;
}

Json::Value ${struct["struct_name"]}::encode_to_json_object()
{
    Json::Value root(Json::objectValue);

    %for field in struct["fields"]:

    %if field.container == 'NULL':
    <%
        field_name = field.field_name
        type_name = field.type_name
    %>
        %if field.is_type_basic:
    root["${field_name}"] = ${field_name};
        %else:
    root["${field_name}"] = ${field_name}.encode_to_json_object();
        %endif
    %endif
    %endfor


    int size = 0;
    int i = 0;
    %for field in struct["fields"]:
    <%
        field_name = None
        type_name = None
        if field.container == 'vector':
            field_name = field.field_name
            type_name = field.type_name
    %>
    %if field_name:
    size = ${field_name}.size();
    root["${field_name}"] = Json::Value(Json::arrayValue);

    for ( i = 0; i < size; i++ ) {
        %if field.is_type_basic:
        root["${field_name}"].append(${field_name}[i]);
        %else:
        root["${field_name}"].append(${field_name}[i].encode_to_json_object());
        %endif
    }
    %endif
    %endfor
    return root;
}

std::string ${struct["struct_name"]}::encode(bool readable)
{
    Json::Value root = encode_to_json_object();
    if ( readable )
    {
        Json::StyledWriter writer;
        return writer.write(root);
    }
    else
    {
        Json::FastWriter writer;
        return writer.write(root);
    }
}

''')