//
//  StringUtils.hpp
//  qlibc++
//
//  Created by 胡涛 on 2017/11/16.
//  Copyright © 2017年 胡涛. All rights reserved.
//

#ifndef StringUtils_hpp
#define StringUtils_hpp

#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#ifdef __GNUC__
#include <unordered_map>
#else
#include <unordered_map>
#endif
#include <string>
#include <vector>
#include <json/json.h>

#include <jebase/config.h>
#include <regex>
#include <unordered_set>

typedef std::vector<std::string> str_vector;
typedef std::vector<std::string> QStringList;
typedef std::unordered_set<std::string> QStringSet;

#ifdef __GNUC__
namespace __gnu_cxx {
    struct strHash {
        size_t operator()(const std::string &str) const {
            unsigned long __h = 0;
            for (size_t i = 0; i < str.size(); i++)
                __h = 107 * __h + str[i];
            return size_t(__h);
        }
    };

    struct strEqual {
        bool operator()(const std::string &s1, const std::string &s2) const {
            return s1 == s2;
        }
    };
}
#endif

#ifdef __GNUC__
typedef std::unordered_map<std::string, std::string> QStringMap;
#else
typedef std::unordered_map<std::string,std::string> QStringMap;
#endif

using QStringPMap = std::unordered_map<std::string, std::string*>;

#ifdef __GNUC__
typedef std::unordered_map<std::string, bool, __gnu_cxx::strHash, __gnu_cxx::strEqual> QBoolMap;
#else
typedef std::unordered_map<std::string,bool> QBoolMap;
#endif

#define MAX_STR_BUFF_SIZE 65536

#define IS_JSON_OBJ(__k) \
    (__k.size()>1 && (__k[0]=='[' || __k[0]=='{'))

#define IS_JSON_BOOL(__k) \
    (__k == "true" || __k == "false")

#define IS_JSON_OBJ_HAS_STRMEMBER(_o,_k) \
    ((_o).isMember(_k) && (_o).operator[](_k).isString() && strlen((_o).operator[](_k).asCString()) != 0)

class JE_API StringUtils{

public:
    static  bool isEmptyOrWhitespaceOnly(const std::string &str);
    static  bool isNotValidStr(const std::string& str);
    static  bool isValidStr(const std::string& str);

    static  std::string randomChars(int c, bool  upper = false);
    static  std::string randomNumChars(int c);
    static  std::string randomXNumChars(int c);

    static  std::string dupChar(char chr, std::size_t copy);
    static  std::string& dupChar(std::string& target, char chr, std::size_t copy);

    static  char randomChar(bool  upper = false);

    static  std::string valueToJsonString(const Json::Value& obj);
    static  void valueToJsonString(const Json::Value& obj, std::string& ret);
    static  bool stringFromStringValue(const Json::Value& obj, std::string& ret);
    static  void valueToJsonStringByOrderedKeys(std::string& output, const Json::Value& val, const char* keylists[], bool ret = true, int level = 0);
    static  std::string valueToJsonStringByOrderedKeys(const Json::Value& val, const char* keylists[], bool ret = true);

    static  void SplitString(const std::string& s, const std::string& c,str_vector &v);
    static  str_vector SplitString(const std::string& s, const std::string& c);
    static  void SplitString(const std::string& s, const std::string& c,int& count, std::string* cc[]);

    static void QuoteSplit(const std::string& TargetStr, const std::string& SplitIndex, char QuoteChar, QStringList& strlist, bool skipSpace = true);

    static void sortStringList(QStringList& kl);
    static void removeDuplicated(QStringList& kl);
private:
    static void
    makeValidQuoteSplitStr(std::string& Split_sub, const std::string& targetStr,
                           char QuoteChar, int lastBegin, int nextIdx, bool transed);

public:
    static  size_t makeStrHash(const std::string& str);

    static  bool startsWith(const std::string& base, const char *substr);
    static  bool endsWith(const std::string& base, const char *substr);

    static  bool startsWithNoCase(const std::string& base, const char *substr);
    static  bool endsWithNoCase(const std::string& base, const char *substr);

    static  int  indexOf(const std::string& base, char c);

    static  void replace(std::string& str, const std::string& substr, const std::string& deststr);
    static  const std::string& replaceAll(std::string& str, const std::string& rule, const std::string& deststr);

    static  std::string toParaString(Json::Value& value, const std::string &keylist);
    static  std::string toParaString(Json::Value& value);

    static  std::string getUrlAddr(const std::string& url);
    static  std::string getUrlParam(const std::string& url);

    static  std::string getUrlMethod(const std::string& url, bool userSubhost = true);	//截取主机地址
    static  std::string getUrlBase(const std::string& url, bool userSubhost = true);			//截取请求方法

    static  std::string getParaValue(const std::string& urlParam, const std::string& valkey);

    static  bool contains(const std::string& src, const std::string& dest);

    static  bool isParamStr(const std::string& str);
    static  std::string intToString(int i);
    static  std::string uintToString(unsigned int i);
    static  std::string longToString(long i);
    static  std::string ulongToString(unsigned long i);
    static  std::string ulongToXString(unsigned long i);

    static  std::string getMD5(const std::string& str);

    static  std::string getTarget(const std::string& params);

    static  std::string getSplitBlockIndex(const std::string &srcStr, char divider, int blockIndex);
    static  std::string getSplitBlockRest(const std::string& srcStr, char indexChar, int indexOfBlock);

    static  bool parseJson(const std::string &srcstr, Json::Value &dstVal, bool failIfExtra = true);
    static  void setParseJsonErr(bool open = false);
    static  Json::Value parseJson(const std::string& srcstr, bool failIfExtra = true);
    static  Json::Value parseFromFile(const std::string &fn);
    static  void parseFromFile(const std::string &fn, Json::Value& dstVal);

    static  void writeToFile(const std::string &filename, const Json::Value& value);
    static  void writeToFile(const std::string &filename, const std::string& value);

    static  void writeToFile(const std::string &filename, const QStringList& value);

    static  void appendToFile(const std::string &filename, const std::string& value);

    static  std::string appendInt(std::string& target, int val);
    static  std::string appendFloat(std::string& target, float val);
    static  std::string appendBool(std::string& target, bool val);
    static  bool isValidJsonString(const std::string &srcstr);

    static  int readLinesFromFile(const std::string &fn,  int lineSize , std::vector<std::string>& targetList);
    static  int readLinesFromFile(const std::string &fn,  std::vector<std::string>& targetList);

    static  std::string & toLowerCase(std::string &str);
    static  std::string & toUpperCase(std::string &str);

    static  std::string toLowerCase(const std::string &str);
    static  std::string toUpperCase(const std::string &str);

    static  std::string & trimString(std::string &str);
    static  std::string & leftTrim(std::string &str);
    static  std::string & rightTrim(std::string &str);

    static  std::string trimString(const std::string &str);
    static  std::string leftTrim(const std::string &str);
    static  std::string rightTrim(const std::string &str);

    static void formatString(std::string& str, const char *fmt, ...);
    static std::string formatString(const char *fmt, ...);

    static  bool checkPatten(const std::string& target, const char *pattern);

    static  bool checkPatten(const std::string& target, std::regex& reg);


    /**
     * 	查找第n个字符,    n>0从左边计数，  n<0从右边计数， n=0时返回控，若分割符数量始终超过最大数量时 始终返回整串
     * @param str
     * @param target
     * @param cnt
     * @return
     */
    static  long findCharPos(const std::string &str, char target, long cnt);

    static  std::string getSubStrBetween(const std::string &str, char fc, long cntOfFc , char ec, long cntOfEc);

    static  std::string getSubStrAfter(const std::string &str, char target, long cnfOfChar);

    static  std::string getSubStrBefore(const std::string &str, char target, long cnfOfChar);


    /**
     * 	查找第n个子串,    n>0从左边计数，  n<0从右边计数,  n=0时 始终返回空串
     * @param str
     * @param target
     * @param cnt
     * @return
     */
    static  long findCharPos(const std::string &str, const std::string& target, long cnt) ;

    static  std::string getSubStrBetween(const std::string &str, const std::string& fc, long cntOfFc , const std::string& ec, long cntOfEc);

    static  std::string getSubStrAfter(const std::string &str, const std::string& target, long cnfOfChar);

    static  std::string getSubStrBefore(const std::string &str, const std::string& target, long cnfOfChar);

//    static std::string ListToString(QStringList strs, const char splitChar);

//    static std::string ListToString(QStringList strs, const char splitChar, int max);

    static QStringList toStringList(const char *strArray[]);

    //用指定字符填充一个指定宽度的字符串，内容居中或
    static std::string fillFixWidthString(const std::string &str, int width, char fillChar = '-', int align = -1);
    static void fillFixWidthString(std::string& target, const std::string &str, int width, char fillChar='-', int align = -1);

    static void getSubKey(const std::string &src, char devider, std::string &first, std::string &left);

    static std::string randomUUID();

    static std::string randomName();

    //是否为数字开头但并不是数字的字符串
    static bool isNumberStartMixStr(const std::string &str);

    static bool isNumbericStr(const std::string &str);

    static bool isHexString(const std::string &str, bool fullFix = true);

    static std::string removeChar(const std::string& s, unsigned char c);

    static std::string fromStringList(QStringList &strList, const std::string& devChar = ",");

    static bool allCharQuotted(std::string &str, char targetChar, char quoteChar);

    static void removeQuote(std::string &str, char quoteChar);

    static void setToJsonString(std::string& greppedKeys, const std::unordered_set<std::string> &set, const std::string& sep = " ");

    static bool stringInList(const std::string &target, const QStringList& list);

    static void listToJsonArray(const QStringList &list, Json::Value &array);
};

#define FmtStr(fmt, ...)\
    StringUtils::formatString(fmt,##__VA_ARGS__)


#define VAL_CONSTR(v,len) \
    StringUtils::valueToJsonString(v).substr(0,len).c_str()


#define IS_JSON_NUMBERIC(__k) \
    (!__k.empty() && (StringUtils::isNumbericStr(__k)))

#endif /* StringUtils_hpp */
