#! /usr/bin/python
#

from xgen.util import *
from xgen.yxsd import *
from xgen import util
import glob
import os
from jinja2 import Environment, DictLoader

# 2.7
# reload(sys)
# import sys
# sys.setdefaultencoding('utf-8')

import logging
logger = logging.getLogger(__name__)


def ypkcppname(name):
    return 'Y' + cppname(name)


def nodecppname(path):
    if path == 'yNode':
        return path
    elif path == 'yDoc':
        return path
    elif path.startswith('/'):
        path = path[1:]

    name = ''
    for n in path.split(':'):
        name = n
    return 'node' + cppname(name)


def nsprefix(prefix):
    if prefix == '':
        return 'nsMod'
    else:
        return 'ns' + cppname(prefix)


def myindent(indent=0):
    return ' '*4*indent


def mysplit(string, sep):
    return string.split(sep)


def nodename(path):
    if path.startswith('/'):
        return path[1:]

    return path


class CmdYPK(object):
    def __init__(self, inXsdDir, inBundle):
        self.m_mods = {}
        self.m_xsd_dir = inXsdDir
        self.m_bundle = inBundle
        self.initenv()

    def initenv(self):
        mytemplates = {
            "h_ymod": H_YMOD_TEMPLATE,
            "cpp_ymod_base": CPP_YMOD_BASE_TEMPLATE,
            "cpp_ymod": CPP_YMOD_TEMPLATE,
            "h_bundle": H_BUNDLE_TEMPLATE,
            "cpp_bundle": CPP_BUNDLE_TEMPLATE,
            "cpp_ypk": CPP_YPK_TEMPLATE,
            "h_ypk": H_YPK_TEMPLATE,
            "cpp_ypb_incremental": CPP_YPBINCREMENTAL_TEMPLATE
        }
        self.m_env = Environment(loader=DictLoader(
            mytemplates), trim_blocks=True, lstrip_blocks=True)
        self.m_env.filters["ypkcppname"] = ypkcppname
        self.m_env.filters["pbname"] = pbname
        self.m_env.filters["cppname"] = cppname
        self.m_env.filters["nodecppname"] = nodecppname
        self.m_env.filters["nodename"] = nodename
        self.m_env.filters["nsprefix"] = nsprefix
        self.m_env.filters["myindent"] = myindent
        self.m_env.filters["mysplit"] = mysplit
        self.m_env.filters["cppnormalize"] = util.cppnormalize
        self.m_env.tests['xSimpleTypeEnum'] = isXSimpleTypeEnum

    def run(self, inDir):
        if os.path.exists(inDir) is False:
            os.mkdir(inDir)

        path = self.m_xsd_dir + '/*.xsd'

        for xsd in glob.glob(path):
            mod = YModule(xsd)
            mod.parse()
            self.m_mods[mod.m_modname] = mod

            modname = mod.m_modname
            modtype = mod.m_modtype

            outfile = inDir + "/" + ypkcppname(modname) + ".h"
            logger.info("generate %s" % outfile)
            with open(outfile, 'w') as f:
                output = self.m_env.get_template('h_ymod').render(
                    ymod=mod, ybundle=self.m_bundle)
                f.write(output)

            outfile = inDir + "/" + ypkcppname(modname) + ".cpp"
            logger.info("generate %s" % outfile)
            with open(outfile, 'w') as f:
                output = self.m_env.get_template('cpp_ymod').render(
                    ymod=mod, ybundle=self.m_bundle)
                f.write(output)

        outfile = inDir + "/" + self.m_bundle + ".h"
        logger.info("generate %s" % outfile)
        with open(outfile, 'w') as f:
            output = self.m_env.get_template('h_bundle').render(
                ybundle=self.m_bundle, ymods=self.m_mods.values())
            f.write(output)

        outfile = inDir + "/" + self.m_bundle + ".cpp"
        logger.info("generate %s" % outfile)
        with open(outfile, 'w') as f:
            output = self.m_env.get_template('cpp_bundle').render(
                ybundle=self.m_bundle, ymods=self.m_mods.values())
            f.write(output)

        outfile = inDir + "/" + "YPK.h"
        logger.info("generate %s" % outfile)
        with open(outfile, 'w') as f:
            output = self.m_env.get_template('h_ypk').render()
            f.write(output)

        outfile = inDir + "/" + "YPK.cpp"
        logger.info("generate %s" % outfile)
        with open(outfile, 'w') as f:
            output = self.m_env.get_template('cpp_ypk').render()
            f.write(output)

        outfile = inDir + "/" + "YPBIncremental.cpp"
        logger.info("generate %s" % outfile)
        with open(outfile, 'w') as f:
            output = self.m_env.get_template('cpp_ypb_incremental').render()
            f.write(output)


cmddescription = 'generate cpp from dev yxsd model'


def makeoptions(optparser):
    optparser.add_argument(
        "--bundle",
        type=str,
        help="specify yang bundle")
    pass


def run(options):
    cmd = CmdYPK(options.input, options.bundle)
    cmd.run(options.output)


H_YMOD_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com

#pragma once
#include "YPK.h"
#include "{{ymod.m_modname|pbname}}.pb.h"

using namespace YPK;

namespace {{ybundle}}
{

class YPK_API {{ymod.m_modname | ypkcppname}} : public YPK::YPKBase
{
public:
    virtual int YConfigGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc);
    virtual int YFilterGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc);
    virtual int YRpcGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc);
    virtual int YRpcRetGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule);
    virtual int YNotifyGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule);
    virtual int YPBGen(xmlNodePtr yNode, YPK::YPBMessagePtr pModule);

private:
{% for complextype in ymod.m_complex_types %}
  {% if complextype.m_modname %}
    int YXmlGen(const {{ybundle}}PB::{{ymod.m_modname | pbname}}::{{complextype.m_name_pb}} &st{{complextype.m_name_cpp}}, xmlNodePtr yNode);
    int YPBGen(const xmlNodePtr yNode, {{ybundle}}PB::{{ymod.m_modname | pbname}}::{{complextype.m_name_pb}} &st{{complextype.m_name_cpp}});

  {% endif %}
{% endfor%}
{% for complextype in ymod.m_complex_types %}
  {% if not complextype.m_modname %}
    int YXmlGen(const {{ybundle}}PB::{{ymod.m_modname | pbname}}::{{complextype.m_name_pb}} &st{{complextype.m_name_cpp}}, xmlNodePtr yNode);
    int YPBGen(const xmlNodePtr yNode, {{ybundle}}PB::{{ymod.m_modname | pbname}}::{{complextype.m_name_pb}} &st{{complextype.m_name_cpp}});

  {% endif %}
{% endfor %}

public:
{%for xsimple in ymod.m_simple_types %}
{%if xsimple is xSimpleTypeEnum %}
    struct {{xsimple.m_name | cppnormalize}} {
        enum {
{%  for xenum in xsimple.m_enums.values() %}
            {{xenum.m_en | cppnormalize}} = {{xenum.m_field_index}},
{%  endfor %}
        };

        static const char* name(int value) {
            switch (value) {
{%  for xenum in xsimple.m_enums.values() %}
            case {{xenum.m_field_index}}:
                return "{{xenum.m_en}}";
{%  endfor %}
            default:
                assert(false);
                return "invalid";
            }
        }

        static int value(std::string name) {
{%  for xenum in xsimple.m_enums.values() %}
            if (name == "{{xenum.m_en}}")
                return {{xenum.m_field_index}};
{%  endfor %}
            assert(false);
            return -1;
        }
    };
{%endif %}

{%endfor %}


};

}
"""


CPP_YMOD_BASE_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com
{% set modname = ymod.m_modname %}
{% set modpbname = ymod.m_modname | pbname %}
{% set modpbtype = ymod.m_modtype | pbname %}
{% set modcppname = ymod.m_modname | ypkcppname %}
#include "{{modcppname}}.h"

using namespace YPK;
namespace {{ybundle}}
{

int {{modcppname}}::YConfigGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc)
{
    xmlNodePtr nodeConfig = xmlDocGetRootElement(yDoc);
    if (nodeConfig == NULL) {
        nodeConfig = xmlNewDocNode(yDoc, NULL, BAD_CAST "config", NULL);
        xmlDocSetRootElement(yDoc, nodeConfig);
    }

    {{ybundle}}PB::{{modpbname}}::{{modpbtype}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{modpbtype}}*>(pModule.get());
    return YXmlGen(*pPtr, nodeConfig);
}

int {{modcppname}}::YFilterGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc)
{
    xmlNodePtr nodeFilter = xmlDocGetRootElement(yDoc);
    if (nodeFilter == NULL) {
        nodeFilter = xmlNewDocNode(yDoc, NULL, BAD_CAST "filter", NULL);
        xmlDocSetRootElement(yDoc, nodeFilter);
    }

    {{ybundle}}PB::{{modpbname}}::{{modpbtype}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{modpbtype}}*>(pModule.get());
    return YXmlGen(*pPtr, nodeFilter);
}

int {{modcppname}}::YRpcGen(YPK::YPBMessagePtr pRpcPB, xmlDocPtr yDoc)
{
    std::string strMsgName = pRpcPB->GetTypeName();
{%for rpc in ymod.m_rpcs.values() %}
{%  if rpc.m_input %}
    if (strMsgName == "{{ybundle}}PB.{{modpbname}}.{{rpc.m_input|pbname}}") {
        {{ybundle}}PB::{{modpbname}}::{{rpc.m_input|pbname}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{rpc.m_input|pbname}}*>(pRpcPB.get());
        xmlNodePtr nodeRpc = xmlNewDocNode(yDoc, NULL, BAD_CAST "{{rpc.m_name}}", NULL);
        xmlDocSetRootElement(yDoc, nodeRpc);
        xmlNsPtr pNs = xmlNewNs(nodeRpc, BAD_CAST "{{rpc.m_namespace}}", NULL);
        xmlSetNs(nodeRpc, pNs);
        return YXmlGen(*pPtr, nodeRpc);
    }
{%  else %}
    if (strMsgName == "{{ybundle}}PB.{{modpbname}}.{{rpc.m_name|pbname}}") {
        {{ybundle}}PB::{{modpbname}}::{{rpc.m_name|pbname}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{rpc.m_name|pbname}}*>(pRpcPB.get());
        xmlNodePtr nodeRpc = xmlNewDocNode(yDoc, NULL, BAD_CAST "{{rpc.m_name}}", NULL);
        xmlDocSetRootElement(yDoc, nodeRpc);
        xmlNsPtr pNs = xmlNewNs(nodeRpc, BAD_CAST "{{rpc.m_namespace}}", NULL);
        xmlSetNs(nodeRpc, pNs);
        return 0;
    }
{%  endif %}

{%endfor %}
    return 0;
}

int {{modcppname}}::YRpcRetGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pPB)
{
    std::string strMsgName = pPB->GetTypeName();
{%for rpc in ymod.m_rpcs.values() %}
{%  if rpc.m_output %}
    if (strMsgName == "{{ybundle}}PB.{{modpbname}}.{{rpc.m_output|pbname}}") {
        {{ybundle}}PB::{{modpbname}}::{{rpc.m_output|pbname}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{rpc.m_output|pbname}}*>(pPB.get());

        return YPBGen((xmlNodePtr)yDoc, *pPtr);
    }

{%  endif %}
{%endfor %}
    return 0;
}

int {{modcppname}}::YNotifyGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pPB)
{
    std::string strMsgName = pPB->GetTypeName();
{%for notify in ymod.m_notifys.values() %}
{%  if notify.m_type %}
    if (strMsgName == "{{ybundle}}PB.{{modpbname}}.{{notify.m_type|pbname}}") {
        {{ybundle}}PB::{{modpbname}}::{{notify.m_type|pbname}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{notify.m_type|pbname}}*>(pPB.get());

        return YPBGen((xmlNodePtr)yDoc, *pPtr);
    }

{%  endif %}
{%endfor %}
    return 0;
}

int {{modcppname}}::YPBGen(xmlNodePtr yNode, YPK::YPBMessagePtr pModule)
{
    {{ybundle}}PB::{{modpbname}}::{{modpbtype}} *pPtr = dynamic_cast<{{ybundle}}PB::{{modpbname}}::{{modpbtype}}*>(pModule.get());
    return YPBGen(yNode, *pPtr);
}

{%for complextype in ymod.m_complex_types %}
{%set stmsg = 'st' + complextype.m_name_cpp %}

int {{modcppname}}::YXmlGen(const {{ybundle}}PB::{{modpbname}}::{{complextype.m_name_pb}} &{{stmsg}}, xmlNodePtr yNode)
{
    xmlNodePtr nodeLeaf = NULL;
  {% block mandgen scoped%}
  {% endblock %}

  {% block parentnoshared scoped%}
  {% endblock %}

  {% block xnode scoped%}
  {% endblock %}
    return 0;
}

int {{modcppname}}::YPBGen(xmlNodePtr yNode, {{ybundle}}PB::{{modpbname}}::{{complextype.m_name_pb}} &{{stmsg}})
{
    std::vector<xmlNodePtr> vecNodes;
    xmlNodePtr childNode;
{%  for field in complextype.m_fields %}
{%    if field.m_path and field.m_path[0] == '/' %}
{%      set fromself = 'true' %}
{%      set ypath = field.m_path[1:] %}
{%    else %}
{%      set fromself = 'false' %}
{%      set ypath = field.m_path %}
{%    endif %}
{%    if field.m_list %}
    YPK::selectNodes(yNode, "{{ypath}}", {{fromself}}, vecNodes);
    for (int i = 0; i < vecNodes.size(); i++) {
{%      if field.m_pbtype in ('int32', 'uint32', 'int64') %}
        {{stmsg}}.add_{{field.m_pbname}}(YInteger((const char*)getLeafNodeValue(vecNodes[i])));
{%      elif field.m_pbtype in ('uint64') %}
        {{stmsg}}.add_{{field.m_pbname}}(YUInteger((const char*)getLeafNodeValue(vecNodes[i])));
{%      elif field.m_pbtype == 'bytes' %}
        {{stmsg}}.add_{{field.m_pbname}}((const char*)getLeafNodeValue(vecNodes[i]));
{%      elif field.m_pbtype == 'enum' %}
        {{stmsg}}.add_{{field.m_pbname}}({{field.m_type | cppnormalize}}::value((const char*)getLeafNodeValue(vecNodes[i])));
{%      else %}
        xmlNodePtr xNode = vecNodes[i];
        YPBGen(xNode, *{{stmsg}}.add_{{field.m_pbname}}());
{%      endif %}
    }
{%    elif field.m_leaf %}
{%      if not ypath %}
    childNode = YPK::selectNode(yNode, "{{field.m_leafname}}", {{fromself}});
{%      elif ypath[-1] == '/' %}
    childNode = YPK::selectNode(yNode, "{{(ypath, field.m_leafname) | join}}", {{fromself}});
{%      else %}
    childNode = YPK::selectNode(yNode, "{{(ypath, '/', field.m_leafname) | join}}", {{fromself}});
{%      endif %}
    if (NULL != childNode) {
{%      if field.m_typename in ('int32', 'uint32', 'int64') %}
        {{stmsg}}.set_{{field.m_pbname}}(YInteger((const char*)getLeafNodeValue(childNode)));
{%      elif field.m_typename in ('uint64') %}
        {{stmsg}}.set_{{field.m_pbname}}(YUInteger((const char*)getLeafNodeValue(childNode)));
{%      elif field.m_typename == 'string' %}
        {{stmsg}}.set_{{field.m_pbname}}((const char*)getLeafNodeValue(childNode));
{%      elif field.m_typename == 'enum' %}
        {{stmsg}}.set_{{field.m_pbname}}({{field.m_type | cppnormalize}}::value((const char*)getLeafNodeValue(childNode)));
{%      else %}
    unkown leaf type {{field.m_typename}}
{%      endif %}
    }
{%    else %}
    childNode = selectNode(yNode, "{{ypath}}", {{fromself}});
    if (NULL != childNode) {
        YPBGen(childNode, *{{stmsg}}.mutable_{{field.m_pbname}}());
    }
{%    endif %}

{%  endfor %}
    return 0;
}

{%endfor %}


}
"""


CPP_YMOD_TEMPLATE = """{% extends 'cpp_ymod_base' %}

{% macro createrootnode(path, indent) %}
{% set createrootnode | indent(indent*4, True )%}
xmlNodePtr {{path|nodecppname }} = xmlNewChild(yNode, NULL, BAD_CAST "{{path|nodename}}", NULL);
      {% for prefix,ns in ymod.m_namespaces.items() %}
        {% if prefix == ''%}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs({{path|nodecppname}}, BAD_CAST "{{ns}}", NULL);
        {% else %}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs({{path|nodecppname}}, BAD_CAST "{{ns}}", BAD_CAST "{{prefix}}");
        {%endif %}
xmlSetNs({{path|nodecppname}}, {{prefix|nsprefix}});
      {% endfor %}
{% endset %}
{{createrootnode-}}
{% endmacro %}

{% macro createparentpriv(nodeparent, field, indent) %}
{% set createparentpriv | indent(indent*4, True)%}
{% for path in field.m_path_priv %}
  {% if loop.first %}
    {% if path[0] == '/' %}
      {{-createrootnode(path, 0)}}
    {% else %}
xmlNodePtr {{path|nodecppname}} = xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{path}}", NULL);
    {% endif %}
  {% else %}
xmlNodePtr {{path|nodecppname}} = xmlNewChild({{loop.previtem|nodecppname}}, NULL, BAD_CAST "{{path}}", NULL);
  {% endif %}

  {% if loop.last and not field.m_list and not field.m_leaf%}
    {% for prefix, ns in field.m_namespaces.items() %}
        {% if prefix == ''%}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs({{path|nodecppname}}, BAD_CAST "{{ns}}", NULL);
        {% else %}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs({{path|nodecppname}}, BAD_CAST "{{ns}}", BAD_CAST "{{prefix}}");
        {% endif %}
xmlSetNs({{path|nodecppname}}, {{prefix|nsprefix}});
    {% endfor %}
  {% endif %}
{% endfor %}
{% endset %}
{{createparentpriv-}}
{% endmacro %}

{% macro createkeyleaf(stmsg, field, nodeparent, indent) %}
{% set createkeyleaf | indent(indent*4, True)%}
{%if field.m_nodeopr or field.m_namespaces%}
nodeLeaf = {% endif -%}
{%if field.m_typename in ('int32', 'uint32', 'int64') -%}
if ({{stmsg}}.{{field.m_pbname}}() != 0)
{
	xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST YLexicalInteger({{stmsg}}.{{field.m_pbname}}()).c_str());
}
{%elif field.m_typename in ('uint64') -%}
xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST YLexicalUInteger({{stmsg}}.{{field.m_pbname}}()).c_str());
{%elif field.m_typename == 'string' -%}
if ({{stmsg}}.{{field.m_pbname}}().length() > 0)
{
	xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST {{stmsg}}.{{field.m_pbname}}().c_str());
}
{%elif field.m_typename == 'enum' -%}
xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST {{field.m_type | cppnormalize}}::name({{stmsg}}.{{field.m_pbname}}()));
{%else -%}
    unkown leaf type {{field.m_typename}}
{%endif -%}
{%if field.m_namespaces %}
{%  for prefix, ns in field.m_namespaces.items() %}
{%    if prefix == ''%}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs(nodeLeaf, BAD_CAST "{{ns}}", NULL);
{%    else %}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs(nodeLeaf, BAD_CAST "{{ns}}", BAD_CAST "{{prefix}}");
{%    endif %}
xmlSetNs(nodeLeaf, {{prefix|nsprefix}});
{%  endfor %}
{%endif %}
{%if field.m_nodeopr -%}
if ({{stmsg}}.{{field.m_name|pbname}}_opr() != YPK::EDataNodeOpr::NONE) {
    xmlSetProp(nodeLeaf, BAD_CAST NC_OPERATION, BAD_CAST YPK::EDataNodeOpr::name({{stmsg}}.{{field.m_name|pbname}}_opr()));
}
{%endif -%}
{%endset -%}
{{createkeyleaf-}}
{% endmacro %}

{% macro createkeyleaf_key(stmsg, field, nodeparent, indent) %}
{% set createkeyleaf_key | indent(indent*4, True)%}
{%if field.m_nodeopr or field.m_namespaces%}
nodeLeaf = {% endif -%}
{%if field.m_typename in ('int32', 'uint32', 'int64') -%}
if ({{stmsg}}.{{field.m_pbname}}() != 0) {
	xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST YLexicalInteger({{stmsg}}.{{field.m_pbname}}()).c_str());
}
{%elif field.m_typename in ('uint64') -%}
if ({{stmsg}}.{{field.m_pbname}}() != 0) {
	xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST YLexicalUInteger({{stmsg}}.{{field.m_pbname}}()).c_str());
}
{%elif field.m_typename == 'string' -%}
if (!{{stmsg}}.{{field.m_pbname}}().empty()) {
	xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST {{stmsg}}.{{field.m_pbname}}().c_str());
}
{%elif field.m_typename == 'enum' -%}
xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_leafname}}", BAD_CAST {{field.m_type | cppnormalize}}::name({{stmsg}}.{{field.m_pbname}}()));
{%else -%}
    unkown leaf type {{field.m_typename}}
{%endif -%}
{%if field.m_namespaces %}
{%  for prefix, ns in field.m_namespaces.items() %}
{%    if prefix == ''%}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs(nodeLeaf, BAD_CAST "{{ns}}", NULL);
{%    else %}
xmlNsPtr {{prefix|nsprefix}} = xmlNewNs(nodeLeaf, BAD_CAST "{{ns}}", BAD_CAST "{{prefix}}");
{%    endif %}
xmlSetNs(nodeLeaf, {{prefix|nsprefix}});
{%  endfor %}
{%endif %}
{%if field.m_nodeopr -%}
if ({{stmsg}}.{{field.m_name|pbname}}_opr() != YPK::EDataNodeOpr::NONE) {
    xmlSetProp(nodeLeaf, BAD_CAST NC_OPERATION, BAD_CAST YPK::EDataNodeOpr::name({{stmsg}}.{{field.m_name|pbname}}_opr()));
}
{%endif -%}
{%endset -%}
{{createkeyleaf_key-}}
{% endmacro %}

{% macro createleaf(stmsg, field, nodeparent, indent) %}
{% set createleaf | indent(indent*4, True) %}
if ({{stmsg}}.has_{{field.m_pbname}}()) {
{% if field.m_path_priv %}
    {{-createparentpriv(nodeparent, field, 1)}}
    {{-createkeyleaf(stmsg, field, field.m_path_priv[-1]|nodecppname, 1)}}
{% else %}
    {{-createkeyleaf(stmsg, field, nodeparent, 1)-}}
{% endif %}
}
{% endset %}
{{createleaf-}}
{% endmacro %}


{%macro createlisto(stmsg, field, nodeparent, indent) %}
{%set createlistoo | indent(indent*4, True) %}
{%set nodevarname = field.m_path_priv_list|nodecppname %}
for (int i = 0; i < {{stmsg}}.{{field.m_pbname}}_size(); i++) {
{% if field.m_pbtype == 'bytes' %}
    xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_path_priv_list}}", BAD_CAST {{stmsg}}.{{field.m_pbname}}(i).c_str());
{% elif field.m_pbtype in ('int32', 'uint32', 'int64') %}
    xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_path_priv_list}}", BAD_CAST YLexicalInteger({{stmsg}}.{{field.m_pbname}}(i)).c_str());
{% elif field.m_pbtype in ('uint64')%}
    xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_path_priv_list}}", BAD_CAST YLexicalUInteger({{stmsg}}.{{field.m_pbname}}(i)).c_str());
{% elif field.m_pbtype == 'enum' %}
    xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_path_priv_list}}", BAD_CAST {{field.m_type | cppnormalize}}::name({{stmsg}}.{{field.m_pbname}}(i)));
{% else %}
    const {{ybundle}}PB::{{modpbname}}::{{field.m_pbtype}} &st{{field.m_name|cppname}} = {{stmsg}}.{{field.m_pbname}}(i);
    xmlNodePtr {{nodevarname}} =  xmlNewChild({{nodeparent}}, NULL, BAD_CAST "{{field.m_path_priv_list}}", NULL);
{%  for prefix, ns in field.m_namespaces.items() %}
{%    if prefix == '' %}
    xmlNsPtr {{prefix|nsprefix}} = xmlNewNs({{nodevarname}}, BAD_CAST "{{ns}}", NULL);
{%    else %}
    xmlNsPtr {{prefix|nsprefix}} = xmlNewNs({{nodevarname}}, BAD_CAST "{{ns}}", BAD_CAST "{{prefix}}");
{%    endif %}
    xmlSetNs({{nodevarname}}, {{prefix|nsprefix}});
{%  endfor %}
{%  if field.m_type_obj.m_fields_key %}
    if (st{{field.m_name|cppname}}.listopr() != YPK::EDataNodeOpr::NONE) {
        xmlSetProp({{nodevarname}}, BAD_CAST NC_OPERATION, BAD_CAST YPK::EDataNodeOpr::name(st{{field.m_name|cppname}}.listopr()));
    }
{%  endif %}
    YXmlGen(st{{field.m_name|cppname}}, {{nodevarname}});
{%  endif %}
}
{% endset %}
{{createlistoo-}}
{% endmacro %}

{% macro createlist(stmsg, field, nodeparent, indent) %}
{% set createlist | indent(indent*4, True) %}
if ({{stmsg}}.{{field.m_pbname}}_size() > 0) {
  {% if field.m_path_priv %}
    {{-createparentpriv(nodeparent, field, 1)}}
    {{-createlisto(stmsg, field, field.m_path_priv[-1] | nodecppname, 1)}}
  {% else %}
    {{-createlisto(stmsg, field, nodeparent, 1)}}
  {% endif %}
}
{% endset %}
{{createlist-}}
{% endmacro %}

{% macro createcontainer(stmsg, field, nodeparent, indent)%}
{% set createcontainer | indent(indent*4, True) %}
if ({{stmsg}}.has_{{field.m_pbname}}()) {
{% if field.m_path_priv %}
{{ createparentpriv(nodeparent, field, 1) }}
  {% if field.m_nodeopr %}
    if ({{stmsg}}.{{field.m_name|pbname}}_opr() != YPK::EDataNodeOpr::NONE) {
        xmlSetProp({{field.m_path_priv[-1]|nodecppname}}, BAD_CAST NC_OPERATION, BAD_CAST YPK::EDataNodeOpr::name({{stmsg}}.{{field.m_name|pbname}}_opr()));
    }

    if ({{stmsg}}.{{field.m_name|pbname}}_opr() != YPK::EDataNodeOpr::REMOVE) {
        YXmlGen({{stmsg}}.{{field.m_pbname}}(), {{field.m_path_priv[-1]|nodecppname}});
    }
  {% else %}
    YXmlGen({{stmsg}}.{{field.m_pbname}}(), {{field.m_path_priv[-1]|nodecppname}});
  {% endif %}
{% else %}
  {% if field.m_nodeopr %}
    if ({{stmsg}}.{{field.m_name|pbname}}_opr() != YPK::EDataNodeOpr::NONE) {
        xmlSetProp({{nodeparent}}, BAD_CAST NC_OPERATION, BAD_CAST YPK::EDataNodeOpr::name({{stmsg}}.{{field.m_name|pbname}}_opr()));
    }
    if ({{stmsg}}.{{field.m_name|pbname}}_opr() != YPK::EDataNodeOpr::REMOVE) {
        YXmlGen({{stmsg}}.{{field.m_pbname}}(), {{nodeparent}});
    }
  {% else %}
    YXmlGen({{stmsg}}.{{field.m_pbname}}(), {{nodeparent}});
  {% endif %}
{% endif %}
}
{% endset %}
{{createcontainer-}}
{% endmacro %}


{% macro fieldset(stmsg, nodeparent, field, indent) %}
{% if field.m_list %}
  {{-createlist(stmsg, field, nodeparent, indent)}}
{% elif field.m_leaf %}
  {{-createleaf(stmsg, field, nodeparent, indent)}}
{% else %}
  {{-createcontainer(stmsg, field, nodeparent, indent)}}
{% endif %}
{% endmacro %}



{% block xnode %}
{% for xnode in complextype.m_xtree.m_xnodes.values() recursive %}
  {% if loop.depth == 1 and xnode.m_xname[0] == '/' %}
    {{-createrootnode(xnode.m_xname, 1)}}
  {% else %}
{{loop.depth | myindent-}}
xmlNodePtr {{xnode.m_xname|nodecppname}} = xmlNewChild({{xnode.m_xname_parent|nodecppname}}, NULL, BAD_CAST "{{xnode.m_xname}}", NULL);
  {% endif %}
{{loop.depth | myindent-}}
{
  {% set outer_loop = loop %}
  {% for field in xnode.m_fields %}
  {{-fieldset(stmsg, xnode.m_xname|nodecppname, field, outer_loop.depth + 1)-}}
  {% endfor %}

  {% if xnode.m_xnodes %}
    {{-loop(xnode.m_xnodes.values())-}}
  {% endif %}
{{loop.depth | myindent-}}
}
{% endfor %}
{% endblock %}

{% block mandgen %}
{% for key,field in complextype.m_fields_key|dictsort %}
	{{-createkeyleaf(stmsg, field, 'yNode', 1)-}}
{% endfor %}
{% if complextype.m_fields_key%}
	if ({{stmsg}}.listopr() == YPK::EDataNodeOpr::REMOVE) {
		return 0;
	}

{% endif %}
{% for field in complextype.m_fields_mandatory %}
    {{-createkeyleaf(stmsg, field, 'yNode', 1)-}}
{% endfor %}
{% endblock %}

{% block parentnoshared %}
{% for field in complextype.m_fields_noshared %}
    {{-fieldset(stmsg, 'yNode', field, 1)-}}
{% endfor %}
{% endblock %}

"""


H_BUNDLE_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com
#pragma once
#include "YPK.h"
{% for ymod in ymods %}
#include "{{ymod.m_modname|pbname}}.pb.h"
{% endfor %}
{% for ymod in ymods %}
#include "{{ymod.m_modname|ypkcppname}}.h"
{% endfor %}

namespace {{ybundle}}
{
int YPK_API YConfigGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc);
int YPK_API YFilterGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc);
int YPK_API YRpcGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc);
int YPK_API YRpcRetGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule);
int YPK_API YNotifyGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule);
int YPK_API YPBGen(xmlDocPtr yDoc, std::map<std::string, YPK::YPBMessagePtr> &mapModule);
int YPK_API YPBGen(xmlNodePtr xnode, YPBModuleMap &yPBModuleMap);
xmlDocPtr YPK_API ClearDocBlankNode(xmlDocPtr doc);
}
"""


CPP_BUNDLE_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com
#include <boost/make_shared.hpp>
#include "{{ybundle}}.h"

namespace {{ybundle}}
{

int YConfigGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc)
{
    std::auto_ptr<YPKBase> pYPK;
    std::string strMsgName = pModule->GetTypeName();
{% for mod in ymods %}
  {% if loop.first %}
    if (strMsgName == "{{ybundle}}PB.{{mod.m_modname|pbname}}.{{mod.m_modtype|pbname}}") {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
    }
  {% else %}
    else if (strMsgName == "{{ybundle}}PB.{{mod.m_modname|pbname}}.{{mod.m_modtype|pbname}}") {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
    }
  {% endif %}
{% endfor %}
    else {
        pYPK.reset(new YPKBase());
    }

    return pYPK->YConfigGen(pModule, yDoc);
}

int YFilterGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc)
{
    std::auto_ptr<YPKBase> pYPK;
    std::string strMsgName = pModule->GetTypeName();
{% for mod in ymods %}
  {% if loop.first %}
    if (strMsgName == "{{ybundle}}PB.{{mod.m_modname|pbname}}.{{mod.m_modtype|pbname}}") {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
    }
  {% else %}
    else if (strMsgName == "{{ybundle}}PB.{{mod.m_modname|pbname}}.{{mod.m_modtype|pbname}}") {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
    }
  {% endif %}
{% endfor %}
    else {
        pYPK.reset(new YPKBase());
    }

    return pYPK->YFilterGen(pModule, yDoc);
}

int YRpcGen(YPK::YPBMessagePtr pModule, xmlDocPtr yDoc)
{
    std::auto_ptr<YPKBase> pYPK;
    std::string strMsgName = pModule->GetTypeName();

    do {
{%for mod in ymods%}
{%  if mod.m_rpcs %}
      if (strMsgName.find("{{ybundle}}PB.{{mod.m_modname|pbname}}") == 0) {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
        break;
      }

{%  endif %}
{% endfor %}
        pYPK.reset(new YPKBase());
    } while (false);

    return pYPK->YRpcGen(pModule, yDoc);
}

int YRpcRetGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule)
{
    std::auto_ptr<YPKBase> pYPK;
    std::string strMsgName = pModule->GetTypeName();

    do {
{%for mod in ymods%}
{%  if mod.m_rpcs %}
      if (strMsgName.find("{{ybundle}}PB.{{mod.m_modname|pbname}}") == 0) {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
        break;
      }

{%  endif %}
{% endfor %}
        pYPK.reset(new YPKBase());
    } while (false);

    return pYPK->YRpcRetGen(yDoc, pModule);
}

int YPK_API YNotifyGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule)
{
    std::auto_ptr<YPKBase> pYPK;
    std::string strMsgName = pModule->GetTypeName();

    do {
{%for mod in ymods%}
{%  if mod.m_notifys %}
      if (strMsgName.find("{{ybundle}}PB.{{mod.m_modname|pbname}}") == 0) {
        pYPK.reset(new {{mod.m_modname | ypkcppname}}());
        break;
      }

{%  endif %}
{% endfor %}
        pYPK.reset(new YPKBase());
    } while (false);

    return pYPK->YNotifyGen(yDoc, pModule);
}

static int YPBGen(xmlNodePtr xnode, YPBModuleMap &yPBModuleMap)
{
    YPK::YPBMessagePtr pModule;

    xmlNsPtr pNs = xmlSearchNs(NULL, xnode, NULL);
    if (NULL == pNs) {
        return -1;
    }

    std::string strNs((char *) pNs->href);
{%for mod in ymods %}
    if (strNs == "{{mod.namespace}}") {
        if (yPBModuleMap.find("{{mod.m_modname}}") != yPBModuleMap.end()) {
            pModule = yPBModuleMap["{{mod.m_modname}}"];
        }
        else {
            pModule = boost::make_shared<{{ybundle}}PB::{{mod.m_modname | pbname}}::{{mod.m_modname | pbname}}>();
            yPBModuleMap["{{mod.m_modname}}"] = pModule;
        }

        {{mod.m_modname | ypkcppname}} ypk;
        ypk.YPBGen(xnode, pModule);
        return 0;
    }

{%endfor%}

    return -1;
}

int YPBGen(xmlDocPtr yDoc, YPBModuleMap &mapModule)
{
    int iRet = 0;

    xmlNodePtr xRoot = xmlDocGetRootElement(yDoc);
    if (NULL == xRoot) {
        return 0;
    }

    xmlNodePtr xnode;
    YPK::YPBMessagePtr pModule;
    for (xnode = xmlFirstElementChild(xRoot); NULL != xnode; xnode = xmlNextElementSibling(xnode)) {
        YPBGen(xnode, mapModule);
    }
}

static bool IsBlankNode(xmlNodePtr pNode)
{
    if (pNode == NULL)
    {
        return true;
    }

    if (pNode->type == XML_ELEMENT_NODE && pNode->children == NULL)
    {
        return true;
    }
    else
    {
        return false;
    }
}

static void RecursiveBrotherChild(xmlNodePtr pDstNode)
{
    if (!IsBlankNode(pDstNode->children))
    {
        RecursiveBrotherChild(pDstNode->children);
    }
    else
    {
        xmlNodePtr pEarseNode = pDstNode->children;
        xmlUnlinkNode(pEarseNode);
        xmlFreeNode(pEarseNode);
    }

    if (!IsBlankNode(pDstNode->next))
    {
        RecursiveBrotherChild(pDstNode->next);
    }
    else
    {
        xmlNodePtr pEarseNode = pDstNode->next;
        xmlUnlinkNode(pEarseNode);
        xmlFreeNode(pEarseNode);
    }
}

xmlDocPtr YPK_API ClearDocBlankNode(xmlDocPtr doc)
{
    xmlDocPtr pDstDoc = xmlCopyDoc(doc, 1);
    RecursiveBrotherChild(xmlDocGetRootElement(pDstDoc));
    return pDstDoc;
}

}
"""

CPP_YPK_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com
#include <sstream>
#include "YPK.h"

namespace YPK
{

long long YInteger(const char* value)
{
	long long llvalue;
	std::stringstream sStream;
	sStream << value;
	sStream	>> llvalue;
	return llvalue;
}

unsigned long long YUInteger(const char* value)
{
	unsigned long ulvalue;
	std::stringstream sStream;
	sStream << value;
	sStream	>> ulvalue;
	return ulvalue;
}

unsigned short YUShort(const char* value)
{
	unsigned short usvalue;
	std::stringstream sStream;
	sStream << value;
	sStream	>> usvalue;
	return usvalue;
}
std::string YLexicalInteger(long long llValue)
{
	std::stringstream sStream;
	sStream << llValue;
	return sStream.str();
}

std::string YLexicalUInteger(unsigned long long ullValue)
{
	std::stringstream sStream;
	sStream << ullValue;
	return sStream.str();
}


int selectNodes(xmlNodePtr xNode, const char* path, bool fromself, std::vector<xmlNodePtr> &vecNodes)
{
	if (NULL == xNode)
	{
		return 0;
	}
	vecNodes.clear();
	xmlNodePtr xnode = NULL;
	xnode = selectNode(xNode, path, fromself);
	while (NULL != xnode)
	{
		vecNodes.push_back(xnode);
		xmlNodePtr xnextNode = xmlNextElementSibling(xnode);
		if (NULL == xnextNode)
		{
			break;
		}
		xnode = selectNode(xnextNode, (char *)xnode->name, true);
	}
	return 0;
}

xmlNodePtr selectNode(xmlNodePtr xParent, const char* path,bool fromself)
{
	if (NULL == xParent)
	{
		return NULL;
	}

	/*ex:path=acl/time-range-cfgs/time-range-cfg;strPathFirstPart=acl;strPathSecondPart=time-range-cfgs/time-range-cfg*/
	std::string strPathFirstPart;
	std::string strPathSecondPart;
	if (std::string(path).npos != std::string(path).find("/"))
	{
		strPathFirstPart = std::string(path).substr(0,std::string(path).find("/"));
		strPathSecondPart = std::string(path).substr(std::string(path).find("/")+1,std::string(path).length()-1);
	}
	else
	{
		strPathFirstPart = std::string(path);
	}


	xmlNodePtr xnode = NULL;
	xmlNodePtr xnodeSelectRet = NULL;

	if (fromself)
	{
		std::string strSub;
		if (std::string((char *)xParent->name) != strPathFirstPart)
		{
      return NULL;
		}
		else
		{
			if (strPathSecondPart.empty())
			{
				return xParent;
			}
			else
			{
				if (std::string(strPathSecondPart).npos != std::string(strPathSecondPart).find("/"))
				{
					strPathFirstPart = std::string(strPathSecondPart).substr(0,std::string(strPathSecondPart).find("/"));
					strPathSecondPart = std::string(strPathSecondPart).substr(std::string(strPathSecondPart).find("/")+1,std::string(strPathSecondPart).length()-1);
				}
				else
				{
					strPathFirstPart = std::string(strPathSecondPart);
					strPathSecondPart = "";
				}
			}
		}
	}

	for (xnode = xmlFirstElementChild(xParent); NULL != xnode; xnode = xmlNextElementSibling(xnode))
	{
		if (std::string((char *)xnode->name) == strPathFirstPart)
		{
			if  (strPathSecondPart.empty())
			{
				return xnode;
			}
			else
			{
				xnodeSelectRet = selectNode(xnode, strPathSecondPart.c_str(), false);
			}
		}
	}

	return xnodeSelectRet;
}

xmlChar *getLeafNodeValue(const xmlNode *cur)
{
	if ((cur == NULL) || (XML_ELEMENT_NODE != cur->type))
	{
		return NULL;
	}
	char * CDefaultValue = "";
  if (cur->children != NULL && XML_TEXT_NODE == cur->children->type)
	{
		if (NULL != cur->children->content)
		{
			return cur->children->content;
		}
		else
		{
			return (xmlChar *)CDefaultValue;
		}
  }
	return (xmlChar *)CDefaultValue;
}

}

"""

H_YPK_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com
#pragma once
#include <vector>
#include <boost/shared_ptr.hpp>
#include <libxml/tree.h>
#include <google/protobuf/message.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/message.h>
#include <google/protobuf/compiler/importer.h>

#ifdef WIN32
#ifdef YPK_EXPORTS
#define YPK_API __declspec(dllexport)
#else
#define YPK_API __declspec(dllimport)
#endif
#else
#define YPK_API
#endif

namespace YPK
{

typedef boost::shared_ptr<google::protobuf::Message> YPBMessagePtr;
typedef std::vector<YPBMessagePtr> YPBMessagePtrVec;
typedef std::map<std::string, YPBMessagePtr> YPBModuleMap;



struct EDataNodeOpr
{
	enum {
		NONE,
	    REMOVE,
	    CREATE
	};

	static const char* name (int value) {
		switch (value) {
		case NONE:
			return "";
		case REMOVE:
		    return "remove";
		case CREATE:
		    return "create";
		default:
		    return "invalid";
		}
	}
};

static const char NC_OPERATION[] = "operation";

class YPK_API YPKBase
{
public:
	virtual int YConfigGen(YPBMessagePtr pModule, xmlDocPtr yDoc) {return 0;};
	virtual int YFilterGen(YPBMessagePtr pModule, xmlDocPtr yDoc) {return 0;};
	virtual int YRpcGen(YPBMessagePtr pModule, xmlDocPtr yDoc) {return 0;};
	virtual int YRpcRetGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule){return 0;};
	virtual int YNotifyGen(xmlDocPtr yDoc, YPK::YPBMessagePtr pModule) { return 0; };
	virtual int YPBGen(xmlNodePtr yNode, YPBMessagePtr pModule) {return 0;};
};

#define INCRE_OPTION_REMOVE_LEAF               0x01
#define INCRE_OPTION_REMOVE_LIST               0x02
#define INCRE_OPTION_REMOVE_CONTAINER          0x04
#define INCRE_OPTION_CLEAR_NOTCHG_LEAF         0x10
#define INCRE_OPTION_CLEAR_NOTCHG_LIST         0x20
#define INCRE_OPTION_CLEAR_NOTCHG_CONTAINER    0x40
#define INCRE_OPTION_LIST_REMOVE_FIRST         0x8000
#define INCRE_OPTION_NORMAL                    0x07
#define INCRE_OPTION_ALL                       0x8077

int YPK_API YExtPBMsgIncremental(google::protobuf::Message *pPBMsgPrev,
                         google::protobuf::Message *pPBMsg,
                         int option = INCRE_OPTION_NORMAL,
                         int maxLevel = -1);

int YPK_API YExtPBMsgIncremental_ChkDup(google::protobuf::Message *pPBMsgPrev,
                         google::protobuf::Message *pPBMsg,
                         int option,
                         int maxLevel, bool &bDup);


int YPK_API YExtPBMsgKeySort(google::protobuf::Message *pMsg, int option, int maxLevel = -1);

long long YInteger(const char* value);
unsigned long long YUInteger(const char* value);
std::string YLexicalInteger(long long llValue);
std::string YLexicalUInteger(unsigned long long ullValue);
unsigned short YUShort(const char* value);

int selectNodes(xmlNodePtr xNode,
		const char* path,
		bool fromself,
		std::vector<xmlNodePtr> &vecNodes);

xmlNodePtr selectNode(xmlNodePtr xNode, const char* path, bool fromself);

xmlChar * getLeafNodeValue(const xmlNode *cur);

}
"""

CPP_YPBINCREMENTAL_TEMPLATE = """//auto generated by xgen toolkit, bug mail to zengmao@fiberhome.com
#include "ypk.pb.h"
#include "YPK.h"

namespace YPK
{

int PBMsgIncremental(google::protobuf::Message *pMsgPrev,
	google::protobuf::Message *pMsg,
	int option, int level, int maxLevel);

int PBMsgIncremental_ChkDup(google::protobuf::Message *pMsgPrev,
	google::protobuf::Message *pMsg,
	int option, int level, int maxLevel,
	bool &bDup);

bool PBFieldHasNodeoprOption(const google::protobuf::FieldDescriptor* pField)
{
	if (pField->options().HasExtension(YPKPB::ynodeopr))
	{
		return true;
	}
	else
	{
		return false;
	}
}

int GetListKey(const google::protobuf::Descriptor *pDesc,
			   std::vector<const google::protobuf::FieldDescriptor*> &vecKeyFields)
{
	for (int i = 0; i < pDesc->field_count(); i++)
	{
		const google::protobuf::FieldDescriptor* pField = pDesc->field(i);

		if (!pField->is_required())
		{
			continue;
		}

		if (pField->options().HasExtension(YPKPB::ykey))
		{
			vecKeyFields.push_back(pField);
		}
	}

	assert(!vecKeyFields.empty());
	return 0;
}

int RemoveField(google::protobuf::Message *pMsg,
				google::protobuf::Message *pMsgPrev,
				const google::protobuf::FieldDescriptor *pField,
				int option)
{
	if (!(option & INCRE_OPTION_REMOVE_CONTAINER) &&
		pField->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
	{
		return 0;
	}

	if (!(option & INCRE_OPTION_REMOVE_LEAF))
	{
		return 0;
	}

	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();

	const google::protobuf::Descriptor* pDesc = pMsg->GetDescriptor();
	const google::protobuf::FieldDescriptor* pFieldOpr = pDesc->FindFieldByName(pField->name() + "_opr");
	pReflection->SetInt32(pMsg, pFieldOpr, EDataNodeOpr::REMOVE);

	switch(pField->cpp_type())
	{
	case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
		pReflection->SetInt32(pMsg, pField, pReflection->GetInt32(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
		pReflection->SetInt64(pMsg, pField, pReflection->GetInt64(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
		pReflection->SetUInt32(pMsg, pField, pReflection->GetUInt32(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
		pReflection->SetUInt64(pMsg, pField, pReflection->GetUInt64(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
		pReflection->SetFloat(pMsg, pField, pReflection->GetFloat(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
		pReflection->SetDouble(pMsg, pField, pReflection->GetDouble(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
		pReflection->SetString(pMsg, pField, pReflection->GetStringReference(*pMsgPrev, pField, NULL));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
		pReflection->SetBool(pMsg, pField, pReflection->GetBool(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
		pReflection->SetEnum(pMsg, pField, pReflection->GetEnum(*pMsgPrev, pField));
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
		pReflection->MutableMessage(pMsg, pField, NULL);
		break;
	default:
		assert(false);
		break;
	}

	return 0;
}

int ClearField(google::protobuf::Message *pMsg,
			   const google::protobuf::FieldDescriptor *pField,
			   int option)
{
	assert(!pField->is_repeated());

	//required remained
	if (pField->is_required())
	{
		return 0;
	}

	switch(pField->cpp_type())
	{
	case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
	case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
	case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
	case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
	case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
	case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
	case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
	case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
	case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
		if (!(option & INCRE_OPTION_CLEAR_NOTCHG_LEAF))
		{
			return 0;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
		if (!(option & INCRE_OPTION_CLEAR_NOTCHG_CONTAINER))
		{
			return 0;
		}
		break;
	default:
		assert(false);
		return 0;
	}

	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();
	pReflection->ClearField(pMsg, pField);

	return 0;
}

int LeafCompare(const google::protobuf::Message * const pMsgPrev,
				const google::protobuf::Message * const pMsg,
				const google::protobuf::FieldDescriptor* pField)
{
	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();
	switch(pField->cpp_type())
	{
	case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
		if (pReflection->GetInt32(*pMsgPrev, pField) < pReflection->GetInt32(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetInt32(*pMsgPrev, pField) > pReflection->GetInt32(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
		if (pReflection->GetInt64(*pMsgPrev, pField) < pReflection->GetInt64(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetInt64(*pMsgPrev, pField) > pReflection->GetInt64(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
		if (pReflection->GetUInt32(*pMsgPrev, pField) < pReflection->GetUInt32(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetUInt32(*pMsgPrev, pField) > pReflection->GetUInt32(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
		if (pReflection->GetUInt64(*pMsgPrev, pField) < pReflection->GetUInt64(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetUInt64(*pMsgPrev, pField) > pReflection->GetUInt64(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
		if (pReflection->GetFloat(*pMsgPrev, pField) < pReflection->GetFloat(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetFloat(*pMsgPrev, pField) > pReflection->GetFloat(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
		if (pReflection->GetDouble(*pMsgPrev, pField) < pReflection->GetDouble(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetDouble(*pMsgPrev, pField) > pReflection->GetDouble(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
		if (pReflection->GetStringReference(*pMsgPrev, pField, NULL) < pReflection->GetStringReference(*pMsg, pField, NULL))
		{
			return -1;
		}
		else if (pReflection->GetStringReference(*pMsgPrev, pField, NULL) > pReflection->GetStringReference(*pMsg, pField, NULL))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
		if (pReflection->GetBool(*pMsgPrev, pField) < pReflection->GetBool(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetBool(*pMsgPrev, pField) > pReflection->GetBool(*pMsg, pField))
		{
			return 1;
		}
		break;
	case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
		if (pReflection->GetEnum(*pMsgPrev, pField) < pReflection->GetEnum(*pMsg, pField))
		{
			return -1;
		}
		else if (pReflection->GetEnum(*pMsgPrev, pField) > pReflection->GetEnum(*pMsg, pField))
		{
			return 1;
		}
		break;
	default:
		assert(false);
		break;
	}

	return 0;
}

bool ListMessageNotChanged(const google::protobuf::Message * const pMsgPrev,
						   const google::protobuf::Message * const pMsg)
{
	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();
	std::vector<const google::protobuf::FieldDescriptor*> vecFields;
	pReflection->ListFields(*pMsg, &vecFields);



	for (int i = 0; i < vecFields.size(); i++)
	{
		const google::protobuf::FieldDescriptor* pField = vecFields[i];

		if (pField->is_repeated() || pField->is_optional())
		{
			return false;
		}

		if (pField->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
		{
			return false;
		}

		if (LeafCompare(pMsgPrev, pMsg, pField))
		{
			return false;
		}
	}

	return true;
}

int ListCompare(const google::protobuf::Message * const pMsgPrev,
				const google::protobuf::Message * const pMsg)
{
	int iRet;
	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();

	std::vector<const google::protobuf::FieldDescriptor*> vecKeyFields;
	GetListKey(pMsg->GetDescriptor(), vecKeyFields);
	if (vecKeyFields.empty())
	{
		return -1;
	}

	for (int i = 0; i < vecKeyFields.size(); i++)
	{
		const google::protobuf::FieldDescriptor* pField = vecKeyFields[i];
		iRet = LeafCompare(pMsgPrev, pMsg, pField);
		if (iRet)
		{
			return iRet;
		}
	}

	return 0;
}

struct ListMessageLess
{
	bool operator()(const google::protobuf::Message * const pMsgPrev,
		const google::protobuf::Message * const pMsg)
	{

		if (ListCompare(pMsgPrev, pMsg) < 0)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
};

bool ListMessageLesser(const google::protobuf::Message * const pMsgPrev,
					   const google::protobuf::Message * const pMsg)
{
	if (ListCompare(pMsgPrev, pMsg) < 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}


int ListKeyCompare(const google::protobuf::Message * const pMsgPrev,
				const google::protobuf::Message * const pMsg)
{
	int iRet;
	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();

	std::vector<const google::protobuf::FieldDescriptor*> vecKeyFields;
	GetListKey(pMsg->GetDescriptor(), vecKeyFields);
	if (vecKeyFields.empty())
	{
		return -1;
	}

	for (int i = 0; i < vecKeyFields.size(); i++)
	{
		const google::protobuf::FieldDescriptor* pField = vecKeyFields[i];
		iRet = LeafCompare(pMsgPrev, pMsg, pField);
		if (iRet)
		{
			return iRet;
		}
	}

	return 0;
}

struct ListMsgKey
{
	bool operator()(const google::protobuf::Message * const pMsgPrev,
		const google::protobuf::Message * const pMsg)
	{

		if (ListKeyCompare(pMsgPrev, pMsg) < 0)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
};


int ListIncremental(google::protobuf::Message *pMsgPrev,
					google::protobuf::Message *pMsg,
					const google::protobuf::FieldDescriptor *pField,
					int option, int level, int maxLevel)
{
	int iRet = 0;

	if (maxLevel >0 && level > maxLevel)
	{
		return 0;
	}

	assert(pField->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE);

	const google::protobuf::Reflection* pReflection = NULL;
	std::set<google::protobuf::Message *, ListMessageLess> setPrev;
	std::set<google::protobuf::Message *, ListMessageLess> setCurr;
	std::map<google::protobuf::Message*, int> mapIndex;
	if (pMsgPrev)
	{
		pReflection = pMsgPrev->GetReflection();
		for (int i = 0; i < pReflection->FieldSize(*pMsgPrev, pField);  i++)
		{
			setPrev.insert(pReflection->MutableRepeatedMessage(pMsgPrev, pField, i));
		}
	}

	if (pMsg)
	{
		pReflection = pMsg->GetReflection();
		for (int i = 0; i < pReflection->FieldSize(*pMsg, pField);  i++)
		{
			google::protobuf::Message* pRepatedMsg =
				pReflection->MutableRepeatedMessage(pMsg, pField, i);
			setCurr.insert(pRepatedMsg);
			mapIndex[pRepatedMsg] = i;
		}
	}

	assert(pReflection);

	std::set<google::protobuf::Message *, ListMessageLess>::iterator iterPrev = setPrev.begin();
	std::set<google::protobuf::Message *, ListMessageLess>::iterator iterCurr = setCurr.begin();

	std::set<int> setNotChangedIndex;
	while (iterPrev != setPrev.end())
	{
		if (iterCurr == setCurr.end() ||
			ListCompare(*iterPrev, *iterCurr) < 0)
		{
			const google::protobuf::Message *pRemove = *iterPrev;
			iterPrev++;

			if (!(option & INCRE_OPTION_REMOVE_LIST))
			{
				continue;
			}

			google::protobuf::Message *pRepeated = pReflection->AddMessage(pMsg, pField);
			pRepeated->CopyFrom(*pRemove);
			const google::protobuf::Descriptor* pDesc = pRepeated->GetDescriptor();
			const google::protobuf::FieldDescriptor* pFieldListopr = pDesc->FindFieldByName("listopr");
			pRepeated->GetReflection()->SetInt32(pRepeated, pFieldListopr, EDataNodeOpr::REMOVE);
			continue;
		}

		if (ListCompare(*iterPrev, *iterCurr) > 0)
		{
			iterCurr++;
			continue;
		}

		google::protobuf::Message *pRepeatedPrev = *iterPrev;
		google::protobuf::Message *pRepeatedCurr = *iterCurr;
		iterPrev++;
		iterCurr++;

		iRet = PBMsgIncremental(pRepeatedPrev, pRepeatedCurr, option, level + 1, -1);
		if (iRet)
		{
			return iRet;
		}

		if ((option & INCRE_OPTION_CLEAR_NOTCHG_LIST) &&
			ListMessageNotChanged(pRepeatedPrev, pRepeatedCurr))
		{
			setNotChangedIndex.insert(mapIndex[pRepeatedCurr]);
		}
	}

	if ((option & INCRE_OPTION_CLEAR_NOTCHG_LIST))
	{
		for (std::set<int>::reverse_iterator iter = setNotChangedIndex.rbegin(); iter != setNotChangedIndex.rend(); iter++)
		{
			int idx = *iter;
			int idxLast = pReflection->FieldSize(*pMsg, pField) - 1;
			if (idx != idxLast)
			{
				pReflection->SwapElements(pMsg, pField, idx, idxLast);
			}
			pReflection->RemoveLast(pMsg, pField);
		}
	}

	if ((option & INCRE_OPTION_LIST_REMOVE_FIRST))
	{
		pReflection = pMsg->GetReflection();
		int removeIdx = 0;
		for (int i = pReflection->FieldSize(*pMsg, pField) - 1; i > removeIdx; i--)
		{
			google::protobuf::Message* pRepeated =
				pReflection->MutableRepeatedMessage(pMsg, pField, i);
			const google::protobuf::Descriptor* pDesc = pRepeated->GetDescriptor();
			const google::protobuf::FieldDescriptor* pFieldListopr = pDesc->FindFieldByName("listopr");
			if (pRepeated->GetReflection()->HasField(*pRepeated, pFieldListopr) &&
				pRepeated->GetReflection()->GetInt32(*pRepeated, pFieldListopr) == EDataNodeOpr::REMOVE)
			{
				pReflection->SwapElements(pMsg, pField, removeIdx, i);
				removeIdx++;
			}
		}
	}
	return 0;
}

int ListIncremental_ChkDup(google::protobuf::Message *pMsgPrev,
					google::protobuf::Message *pMsg,
					const google::protobuf::FieldDescriptor *pField,
					int option, int level, int maxLevel, bool &bDup)
{
	int iRet = 0;

	if (maxLevel > 0 && level > maxLevel)
	{
		return -1;
	}

	if (pField->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
	{
		return -1;
	}

	const google::protobuf::Reflection* pReflection = NULL;
	std::set<google::protobuf::Message *, ListMessageLess> setPrev;
	std::set<google::protobuf::Message *, ListMessageLess> setCurr;
	std::map<google::protobuf::Message*, int> mapIndex;
	if (pMsgPrev)
	{
		pReflection = pMsgPrev->GetReflection();
		for (int i = 0; i < pReflection->FieldSize(*pMsgPrev, pField);  i++)
		{
			setPrev.insert(pReflection->MutableRepeatedMessage(pMsgPrev, pField, i));
		}
	}

	if (pMsg)
	{
		pReflection = pMsg->GetReflection();
		for (int i = 0; i < pReflection->FieldSize(*pMsg, pField);  i++)
		{
			google::protobuf::Message* pRepatedMsg =
				pReflection->MutableRepeatedMessage(pMsg, pField, i);
			setCurr.insert(pRepatedMsg);
			mapIndex[pRepatedMsg] = i;
		}
	}

	if (!pReflection)
	{
		return -1;
	}

	std::set<google::protobuf::Message *, ListMessageLess>::iterator iterPrev = setPrev.begin();
	std::set<google::protobuf::Message *, ListMessageLess>::iterator iterCurr = setCurr.begin();

	std::set<int> setNotChangedIndex;
	while (iterPrev != setPrev.end())
	{
		if (iterCurr == setCurr.end() ||
			ListCompare(*iterPrev, *iterCurr) < 0)
		{
			bDup = false;
			const google::protobuf::Message *pRemove = *iterPrev;
			iterPrev++;

			if (!(option & INCRE_OPTION_REMOVE_LIST))
			{
				continue;
			}

			google::protobuf::Message *pRepeated = pReflection->AddMessage(pMsg, pField);
			pRepeated->CopyFrom(*pRemove);
			const google::protobuf::Descriptor* pDesc = pRepeated->GetDescriptor();
			const google::protobuf::FieldDescriptor* pFieldListopr = pDesc->FindFieldByName("listopr");
			pRepeated->GetReflection()->SetInt32(pRepeated, pFieldListopr, EDataNodeOpr::REMOVE);
			continue;
		}

		if (ListCompare(*iterPrev, *iterCurr) > 0)
		{
			bDup = false;
			iterCurr++;
			continue;
		}

		google::protobuf::Message *pRepeatedPrev = *iterPrev;
		google::protobuf::Message *pRepeatedCurr = *iterCurr;
		iterPrev++;
		iterCurr++;

		bool bCurDup = true;
		iRet = PBMsgIncremental_ChkDup(pRepeatedPrev, pRepeatedCurr, option, level + 1, -1, bCurDup);
		if (iRet)
		{
			return iRet;
		}

		bDup &= bCurDup;
		if (bCurDup)
		{
			if (option & INCRE_OPTION_CLEAR_NOTCHG_LIST)
			{
				setNotChangedIndex.insert(mapIndex[pRepeatedCurr]);
			}
		}
	}

	if (iterCurr != setCurr.end())
	{
		bDup = false;
	}

	if ((option & INCRE_OPTION_CLEAR_NOTCHG_LIST))
	{
		for (std::set<int>::reverse_iterator iter = setNotChangedIndex.rbegin(); iter != setNotChangedIndex.rend(); iter++)
		{
			int idx = *iter;
			int idxLast = pReflection->FieldSize(*pMsg, pField) - 1;
			if (idx != idxLast)
			{
				pReflection->SwapElements(pMsg, pField, idx, idxLast);
			}
			pReflection->RemoveLast(pMsg, pField);
		}
	}

	if ((option & INCRE_OPTION_LIST_REMOVE_FIRST))
	{
		pReflection = pMsg->GetReflection();
		int removeIdx = 0;
		for (int i = pReflection->FieldSize(*pMsg, pField) - 1; i > removeIdx; i--)
		{
			google::protobuf::Message* pRepeated =
				pReflection->MutableRepeatedMessage(pMsg, pField, i);
			const google::protobuf::Descriptor* pDesc = pRepeated->GetDescriptor();
			const google::protobuf::FieldDescriptor* pFieldListopr = pDesc->FindFieldByName("listopr");
			if (pRepeated->GetReflection()->HasField(*pRepeated, pFieldListopr) &&
				pRepeated->GetReflection()->GetInt32(*pRepeated, pFieldListopr) == EDataNodeOpr::REMOVE)
			{
				pReflection->SwapElements(pMsg, pField, removeIdx, i);
				removeIdx++;
			}
		}
	}

	return 0;
}

int PBMsgIncremental(google::protobuf::Message *pMsgPrev,
					 google::protobuf::Message *pMsg,
					 int option, int level, int maxLevel)
{
	int iRet = 0;

	if (maxLevel > 0 && level > maxLevel)
	{
		return 0;
	}

	assert(pMsgPrev && pMsg && pMsgPrev->GetTypeName() == pMsg->GetTypeName());

	const google::protobuf::Reflection* pReflection = pMsgPrev->GetReflection();
	std::vector<const google::protobuf::FieldDescriptor*> vecFieldsPrev;
	//the field is ordered by field number
	pReflection->ListFields(*pMsgPrev, &vecFieldsPrev);

	std::vector<const google::protobuf::FieldDescriptor*> vecFields;
	pReflection->ListFields(*pMsg, &vecFields);


	for (int iPrev = 0, iCurr = 0; iPrev < vecFieldsPrev.size() || iCurr < vecFields.size();)
	{
		const google::protobuf::FieldDescriptor* pField = NULL;


		if  (iPrev < vecFieldsPrev.size())
		{
			if (iCurr >= vecFields.size() ||
				vecFieldsPrev[iPrev]->number() < vecFields[iCurr]->number())
			{
				pField = vecFieldsPrev[iPrev];
				iPrev++;

				if (pField->is_repeated())
				{
					ListIncremental(pMsgPrev, pMsg, pField, option, 1, 1);
					continue;
				}

				if (PBFieldHasNodeoprOption(pField))
				{
					RemoveField(pMsg, pMsgPrev, pField, option);
				}
				continue;
			}

		}

		if (iCurr < vecFields.size())
		{
			if (iPrev >= vecFieldsPrev.size() ||
				vecFields[iCurr]->number() < vecFieldsPrev[iPrev]->number())
			{
				iCurr++;
				continue;
			}
		}

		pField = vecFields[iCurr];
		iPrev++;
		iCurr++;


		//value comparing
		if (pField->is_repeated())
		{
			if (pField->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
			{
				//not support
				assert(false);
				return -1;
			}

			iRet = ListIncremental(pMsgPrev, pMsg, pField, option, level + 1, maxLevel);
			if (0 != iRet)
			{
				return iRet;
			}
		}
		else
		{
			switch(pField->cpp_type())
			{
			case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
				if (pReflection->GetInt32(*pMsgPrev, pField) == pReflection->GetInt32(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
				if (pReflection->GetInt64(*pMsgPrev, pField) == pReflection->GetInt64(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
				if (pReflection->GetUInt32(*pMsgPrev, pField) == pReflection->GetUInt32(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
				if (pReflection->GetUInt64(*pMsgPrev, pField) == pReflection->GetUInt64(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
				if (pReflection->GetFloat(*pMsgPrev, pField) == pReflection->GetFloat(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
				if (pReflection->GetDouble(*pMsgPrev, pField) == pReflection->GetDouble(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
				if (pReflection->GetStringReference(*pMsgPrev, pField, NULL) == pReflection->GetStringReference(*pMsg, pField, NULL))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
				if (pReflection->GetBool(*pMsgPrev, pField) == pReflection->GetBool(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
				if (pReflection->GetEnum(*pMsgPrev, pField) == pReflection->GetEnum(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
				iRet = PBMsgIncremental(pReflection->MutableMessage(pMsgPrev, pField),
					pReflection->MutableMessage(pMsg, pField),
					option, level + 1, maxLevel);
				if (iRet)
				{
					return iRet;
				}

				if (pReflection->MutableMessage(pMsg, pField)->ByteSize() == 0)
				{
					ClearField(pMsg, pField, option);
				}
				break;
			default:
				break;
			}
		}
	}

	return 0;
}

int PBMsgIncremental_ChkDup(google::protobuf::Message *pMsgPrev,
					 google::protobuf::Message *pMsg,
					 int option, int level, int maxLevel, bool &bDup)
{
	int iRet = 0;

	if (maxLevel > 0 && level > maxLevel)
	{
		return -1;
	}

	if (!(pMsgPrev && pMsg && pMsgPrev->GetTypeName() == pMsg->GetTypeName()))
	{
		return -1;
	}

	const google::protobuf::Reflection* pReflection = pMsgPrev->GetReflection();
	std::vector<const google::protobuf::FieldDescriptor*> vecFieldsPrev;
	//the field is ordered by field number
	pReflection->ListFields(*pMsgPrev, &vecFieldsPrev);

	std::vector<const google::protobuf::FieldDescriptor*> vecFields;
	pReflection->ListFields(*pMsg, &vecFields);


	for (int iPrev = 0, iCurr = 0; iPrev < vecFieldsPrev.size() || iCurr < vecFields.size();)
	{
		const google::protobuf::FieldDescriptor* pField = NULL;

		if  (iPrev < vecFieldsPrev.size())
		{
			if (iCurr >= vecFields.size() ||
				vecFieldsPrev[iPrev]->number() < vecFields[iCurr]->number())
			{
				bDup = false;
				pField = vecFieldsPrev[iPrev];
				iPrev++;

				if (pField->is_repeated())
				{
					ListIncremental_ChkDup(pMsgPrev, pMsg, pField, option, 1, 1, bDup);
					continue;
				}

				if (PBFieldHasNodeoprOption(pField))
				{
					RemoveField(pMsg, pMsgPrev, pField, option);
				}
				continue;
			}

		}

		if (iCurr < vecFields.size())
		{
			if (iPrev >= vecFieldsPrev.size() ||
				vecFields[iCurr]->number() < vecFieldsPrev[iPrev]->number())
			{
				bDup = false;
				iCurr++;
				continue;
			}
		}

		pField = vecFields[iCurr];
		iPrev++;
		iCurr++;


		//value comparing
		if (pField->is_repeated())
		{
			if (pField->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
			{
				//not support
				return -1;
			}

			iRet = ListIncremental_ChkDup(pMsgPrev, pMsg, pField,
				option, level + 1, maxLevel, bDup);
			if (0 != iRet)
			{
				return iRet;
			}
		}
		else
		{
			switch(pField->cpp_type())
			{
			case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
				if (pReflection->GetInt32(*pMsgPrev, pField)
					== pReflection->GetInt32(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
				if (pReflection->GetInt64(*pMsgPrev, pField)
					== pReflection->GetInt64(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
				if (pReflection->GetUInt32(*pMsgPrev, pField)
					== pReflection->GetUInt32(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
				if (pReflection->GetUInt64(*pMsgPrev, pField)
					== pReflection->GetUInt64(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
				if (pReflection->GetFloat(*pMsgPrev, pField)
					== pReflection->GetFloat(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
				if (pReflection->GetDouble(*pMsgPrev, pField)
					== pReflection->GetDouble(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
				if (pReflection->GetStringReference(*pMsgPrev, pField, NULL)
					== pReflection->GetStringReference(*pMsg, pField, NULL))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
				if (pReflection->GetBool(*pMsgPrev, pField)
					== pReflection->GetBool(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
				if (pReflection->GetEnum(*pMsgPrev, pField)
					== pReflection->GetEnum(*pMsg, pField))
				{
					ClearField(pMsg, pField, option);
				}
				else
				{
					bDup = false;
				}
				break;
			case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
				iRet = PBMsgIncremental_ChkDup(pReflection->MutableMessage(pMsgPrev, pField),
					pReflection->MutableMessage(pMsg, pField),
					option, level + 1, maxLevel, bDup);
				if (iRet)
				{
					return iRet;
				}

				if (pReflection->MutableMessage(pMsg, pField)->ByteSize() == 0)
				{
					ClearField(pMsg, pField, option);
				}
				break;
			default:
				break;
			}
		}
	}

	return 0;
}

int YExtPBMsgIncremental(google::protobuf::Message *pMsgPrev,
						 google::protobuf::Message *pMsg,
						 int option, int maxLevel)
{
	return PBMsgIncremental(pMsgPrev, pMsg, option, 1, maxLevel);
}

int YExtPBMsgIncremental_ChkDup(google::protobuf::Message *pPBMsgPrev,
     google::protobuf::Message *pPBMsg,
     int option, int maxLevel, bool &bDup)
{
	return PBMsgIncremental_ChkDup(pPBMsgPrev, pPBMsg, option, 1, maxLevel, bDup);
}

int PBMsgKeySort(google::protobuf::Message *pMsg, int option, int level, int maxLevel)
{
	int iRet = 0;

	if (maxLevel > 0 && level > maxLevel)
	{
		return 0;
	}

	assert(pMsg);

	const google::protobuf::Reflection* pReflection = pMsg->GetReflection();
	//the field is ordered by field number
	std::vector<const google::protobuf::FieldDescriptor*> vecFields;
	pReflection->ListFields(*pMsg, &vecFields);

	for (int iCurr = 0; iCurr < vecFields.size(); iCurr++)
	{
		const google::protobuf::FieldDescriptor* pField = NULL;
		pField = vecFields[iCurr];

		google::protobuf::FieldDescriptor::CppType fieldType = pField->cpp_type();
		if (fieldType != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
		{
			continue;
		}
		if (pField->is_repeated())
		{
			std::set<google::protobuf::Message *, ListMsgKey> setCurr;
			//std::map<google::protobuf::Message*, int> mapIndex;
			const google::protobuf::Reflection* pRefle = pMsg->GetReflection();
			int iSize = pRefle->FieldSize(*pMsg, pField);
			for (int i = 0; i < iSize;  i++)
			{
				google::protobuf::Message *pItem = pRefle->MutableRepeatedMessage(pMsg, pField, i);
				setCurr.insert(pItem);
				PBMsgKeySort(pItem, option, 1, maxLevel);
			}

			int iPos = 0;
			std::set<google::protobuf::Message *, ListMsgKey>::iterator it = setCurr.begin();
			for (int i = iPos; i < iSize;  i++)
			{
				google::protobuf::Message *pItem = pRefle->MutableRepeatedMessage(pMsg, pField, i);
				google::protobuf::Message *itt = *it;
				if(pItem == itt)
				{
					if(iPos != i)
					{
						pRefle->SwapElements(pMsg, pField, iPos, i);
					}
					i = iPos;
					iPos++;
					it++;
				}
			}
		}
		else
		{
			//pField->options().HasExtension(YPKPB::ykey);
			//bool dsd = pField->options().has_experimental_map_key();
			//if(dsd){
			//	const std::string dsdk = pField->options().experimental_map_key();
			//}
			google::protobuf::Message *ppt = pReflection->MutableMessage(pMsg, pField);
			PBMsgKeySort(ppt, option, 1, maxLevel);
		}

		//if (!pField->is_required())
		//{
		//	continue;
		//}

		//if (pField->options().HasExtension(YPKPB::ykey))
		//{
		//	google::protobuf::FieldDescriptor::CppType fieldType = pField->cpp_type();
		//	if(fieldType == google::protobuf::FieldDescriptor::CPPTYPE_INT32)
		//	{
		//		int iKey = pReflection->GetInt32(*pMsg, pField);
		//		FIELD_INFO obInfo;
		//		obInfo.iKey = iKey;
		//		obInfo.iIndex = iCurr;
		//		obInfo.pField = pField;
		//		sFiledInfo.insert(obInfo);
		//		pReflection->ClearField(pMsg, pField);
		//	}
		//}
	}



	//std::set<FIELD_INFO>::iterator it = sFiledInfo.begin();
	//for (int i=0; it != sFiledInfo.end(); i++, it++)
	//{
	//	//if(it.iIndex != )
	//	//pReflection->SwapElements(i,iSign);
	//	pReflection->AddMessage(pMsg, it->pField);
	//}
	//
	//vecFields.clear();
	//pReflection->ListFields(*pMsg, &vecFields);
	//for (int iCurr = 0; iCurr < vecFields.size(); iCurr++)
	//{
	//	const google::protobuf::FieldDescriptor* pField = NULL;
	//	pField = vecFields[iCurr];
	//	google::protobuf::FieldDescriptor::CppType fieldType = pField->cpp_type();
	//	if (fieldType == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
	//	{
	//		PBMsgKeySort(pReflection->MutableMessage(pMsg, pField), option, 1, maxLevel);
	//	}
	//}


				//if (pField->is_repeated())
				//{
				//	ListIncremental(pMsgPrev, pMsg, pField, option, 1, 1);
				//	continue;
				//}

				//if (PBFieldHasNodeoprOption(pField))
				//{
				//	RemoveField(pMsg, pMsgPrev, pField, option);
				//}
				//continue;




		////value comparing
		//if (pField->is_repeated())
		//{
		//	if (pField->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
		//	{
		//		//not support
		//		assert(false);
		//		return -1;
		//	}

		//	iRet = ListIncremental(pMsgPrev, pMsg, pField, option, level + 1, maxLevel);
		//	if (0 != iRet)
		//	{
		//		return iRet;
		//	}
		//}
		//else
		//{
		//	switch(pField->cpp_type())
		//	{
		//	case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
		//		if (pReflection->GetInt32(*pMsgPrev, pField) == pReflection->GetInt32(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
		//		if (pReflection->GetInt64(*pMsgPrev, pField) == pReflection->GetInt64(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
		//		if (pReflection->GetUInt32(*pMsgPrev, pField) == pReflection->GetUInt32(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
		//		if (pReflection->GetUInt64(*pMsgPrev, pField) == pReflection->GetUInt64(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
		//		if (pReflection->GetFloat(*pMsgPrev, pField) == pReflection->GetFloat(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
		//		if (pReflection->GetDouble(*pMsgPrev, pField) == pReflection->GetDouble(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
		//		if (pReflection->GetStringReference(*pMsgPrev, pField, NULL) == pReflection->GetStringReference(*pMsg, pField, NULL))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
		//		if (pReflection->GetBool(*pMsgPrev, pField) == pReflection->GetBool(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
		//		if (pReflection->GetEnum(*pMsgPrev, pField) == pReflection->GetEnum(*pMsg, pField))
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
		//		iRet = PBMsgIncremental(pReflection->MutableMessage(pMsgPrev, pField),
		//			pReflection->MutableMessage(pMsg, pField),
		//			option, level + 1, maxLevel);
		//		if (iRet)
		//		{
		//			return iRet;
		//		}

		//		if (pReflection->MutableMessage(pMsg, pField)->ByteSize() == 0)
		//		{
		//			ClearField(pMsg, pField, option);
		//		}
		//		break;
		//	default:
		//		break;
		//	}
		//}

	return 0;
}


int YExtPBMsgKeySort(google::protobuf::Message *pMsg, int option, int maxLevel)
{
	return PBMsgKeySort(pMsg, option, 1, maxLevel);
}

}
"""