#pragma once

#include <string>
#include <stdint.h>
#include "tinyxml2\tinyxml2.h"

namespace Tencent {

static const unsigned int kAesKeySize = 32;
static const unsigned int kAesIVSize = 16;
static const unsigned int kEncodingKeySize = 43;
static const unsigned int kRandEncryptStrLen = 16;
static const unsigned int kMsgLen = 4;
static const unsigned int kMaxBase64Size = 1000000000;
enum  WXBizMsgCryptErrorCode
{
    WXBizMsgCrypt_OK = 0,
    WXBizMsgCrypt_ValidateSignature_Error = -40001,
    WXBizMsgCrypt_ParseXml_Error = -40002,
    WXBizMsgCrypt_ComputeSignature_Error = -40003,
    WXBizMsgCrypt_IllegalAesKey = -40004,
    WXBizMsgCrypt_ValidateCorpid_Error = -40005,
    WXBizMsgCrypt_EncryptAES_Error = -40006,
    WXBizMsgCrypt_DecryptAES_Error = -40007,
    WXBizMsgCrypt_IllegalBuffer = -40008,
    WXBizMsgCrypt_EncodeBase64_Error = -40009,
    WXBizMsgCrypt_DecodeBase64_Error = -40010,
    WXBizMsgCrypt_GenReturnXml_Error = -40011,
};

class WXBizMsgCrypt
{
public:
    //¹¹Ô캯Êý
    // @param sToken: Æóҵ΢Ðźǫ́£¬¿ª·¢ÕßÉèÖõÄToken
    // @param sEncodingAESKey: Æóҵ΢Ðźǫ́£¬¿ª·¢ÕßÉèÖõÄEncodingAESKey
    // @param sCorpid: ÆóÒµºÅµÄcorpid
    WXBizMsgCrypt(const std::string &sToken, 
                    const std::string &sEncodingAESKey, 
                    const std::string &sCorpid)
                    :m_sToken(sToken), m_sEncodingAESKey(sEncodingAESKey),m_sCorpid(sCorpid)
                    {   }
	//ÑéÖ¤URL
	// @param sMsgSignature: Ç©Ãû´®£¬¶ÔÓ¦URL²ÎÊýµÄmsg_signature
	// @param sTimeStamp: ʱ¼ä´Á£¬¶ÔÓ¦URL²ÎÊýµÄtimestamp
	// @param sNonce: Ëæ»ú´®£¬¶ÔÓ¦URL²ÎÊýµÄnonce
	// @param sEchoStr: Ëæ»ú´®£¬¶ÔÓ¦URL²ÎÊýµÄechostr
	// @param sReplyEchoStr: ½âÃÜÖ®ºóµÄechostr£¬µ±return·µ»Ø0ʱÓÐЧ
	// @return£º³É¹¦0£¬Ê§°Ü·µ»Ø¶ÔÓ¦µÄ´íÎóÂë
	int VerifyURL(const std::string& sMsgSignature,
					const std::string& sTimeStamp,
					const std::string& sNonce,
					const std::string& sEchoStr,
					std::string& sReplyEchoStr);
    
    
    // ¼ìÑéÏûÏ¢µÄÕæÊµÐÔ£¬²¢ÇÒ»ñÈ¡½âÃܺóµÄÃ÷ÎÄ
    // @param sMsgSignature: Ç©Ãû´®£¬¶ÔÓ¦URL²ÎÊýµÄmsg_signature
    // @param sTimeStamp: ʱ¼ä´Á£¬¶ÔÓ¦URL²ÎÊýµÄtimestamp
    // @param sNonce: Ëæ»ú´®£¬¶ÔÓ¦URL²ÎÊýµÄnonce
    // @param sPostData: ÃÜÎÄ£¬¶ÔÓ¦POSTÇëÇóµÄÊý¾Ý
    // @param sMsg: ½âÃܺóµÄÔ­ÎÄ£¬µ±return·µ»Ø0ʱÓÐЧ
    // @return: ³É¹¦0£¬Ê§°Ü·µ»Ø¶ÔÓ¦µÄ´íÎóÂë
    int DecryptMsg(const std::string &sMsgSignature,
                    const std::string &sTimeStamp,
                    const std::string &sNonce,
                    const std::string &sPostData,
                    std::string &sMsg);
            
            
    //½«Æóҵ΢ÐŻظ´Óû§µÄÏûÏ¢¼ÓÃÜ´ò°ü
    // @param sReplyMsg:Æóҵ΢ÐÅ´ý»Ø¸´Óû§µÄÏûÏ¢£¬xml¸ñʽµÄ×Ö·û´®
    // @param sTimeStamp: ʱ¼ä´Á£¬¿ÉÒÔ×Ô¼ºÉú³É£¬Ò²¿ÉÒÔÓÃURL²ÎÊýµÄtimestamp
    // @param sNonce: Ëæ»ú´®£¬¿ÉÒÔ×Ô¼ºÉú³É£¬Ò²¿ÉÒÔÓÃURL²ÎÊýµÄnonce
    // @param sEncryptMsg: ¼ÓÃܺóµÄ¿ÉÒÔÖ±½Ó»Ø¸´Óû§µÄÃÜÎÄ£¬°üÀ¨msg_signature, timestamp, nonce, encryptµÄxml¸ñʽµÄ×Ö·û´®,
    //                      µ±return·µ»Ø0ʱÓÐЧ
    // return£º³É¹¦0£¬Ê§°Ü·µ»Ø¶ÔÓ¦µÄ´íÎóÂë
    int EncryptMsg(const std::string &sReplyMsg,
                    const std::string &sTimeStamp,
                    const std::string &sNonce,
                    std::string &sEncryptMsg);
					
	int GetXmlField(const std::string & sPostData, const std::string & sField,std::					string &sEncryptMsg);
private:
    std::string m_sToken;
    std::string m_sEncodingAESKey;
    std::string m_sCorpid;

private:
    // AES CBC
    int AES_CBCEncrypt( const char * sSource, const uint32_t iSize,
            const char * sKey, unsigned int iKeySize, std::string * poResult );
    
    int AES_CBCEncrypt( const std::string & objSource,
            const std::string & objKey, std::string * poResult );
    
    int AES_CBCDecrypt( const char * sSource, const uint32_t iSize,
            const char * sKey, uint32_t iKeySize, std::string * poResult );
    
    int AES_CBCDecrypt( const std::string & objSource,
            const std::string & objKey, std::string * poResult );
    
    //base64
    int EncodeBase64(const std::string sSrc, std::string & sTarget);
    
    int DecodeBase64(const std::string sSrc, std::string & sTarget);
    
    //genkey
    int GenAesKeyFromEncodingKey( const std::string & sEncodingKey, std::string & sAesKey);
    
    //signature
    int ComputeSignature(const std::string sToken, const std::string sTimeStamp, const std::string & sNonce,
        const std::string & sMessage, std::string & sSignature);
    
    int ValidateSignature(const std::string &sMsgSignature, const std::string &sTimeStamp, 
        const std::string &sNonce, const std::string & sEncryptMsg);  

    //get , set data
    void GenRandStr(std::string & sRandStr, uint32_t len);

    void GenNeedEncryptData(const std::string &sReplyMsg,std::string & sNeedEncrypt );



    int SetOneFieldToXml(tinyxml2::XMLDocument * pDoc, tinyxml2::XMLNode* pXmlNode, const char * pcFieldName, 
        const std::string & value, bool bIsCdata);

    int GenReturnXml(const std::string & sEncryptMsg, const std::string & sSignature, const std::string & sTimeStamp, 
        const std::string & sNonce, std::string & sResult);


};

}