//----------------------------------------------------------------------------
// string functions
//----------------------------------------------------------------------------

#ifndef AT_STRINGFUNCTIONS_H
#define AT_STRINGFUNCTIONS_H

#include "base/at_types.h"

#include <string>
#include <stdio.h>

namespace UTL_String
{
    #define ALL_STRING "**"
    #define DEFAULT_TRIM " \0\t\r\n"
    
    // case-insensitive search
    struct ic
    {
      ic(uint) {}
      inline bool operator()
        (char s1, char s2)
      { return toupper(s1) == toupper(s2); };
    };

    #define ILLEGAL_WINFILE_CHARS "/\:*?\"<>|"

    byte * GetToken(byte * str, uint & len, const byte * sep);
    
    uint ReplaceFromList(std::string & w, const byte * replace_list,
        const byte rplace_char = 0, uint stop_len = 0);
    uint RemoveFromList(std::string & w, const byte * replace_list, uint stop_len = 0);

    uint ReplaceStrFromDelimList(std::string & w, const byte * delim_list,
        const byte * list_sep, const byte * rplace_str = 0);
    uint RemoveStrFromDelimList(std::string & w, const byte * replace_list,
        const byte * list_sep);

    uint FindInStrFromDelimList(std::string & w, const byte * delim_list,
        const byte * list_sep, uint pos = 0);
    uint FindInStr(std::string & w, const byte * str, uint pos = 0);
    uint CountInStr(std::string & w, const byte * str, uint pos = 0);

    uint GetSubStrRight(const std::string & w, const byte * find, std::string & res);
    uint RGetSubStrRight(const std::string & w, const byte * find, std::string & res);
    uint GetSubStrLeft(const std::string & w, const byte * find, std::string & res);
    uint RGetSubStrLeft(const std::string & w, const byte * find, std::string & res);
    uint GetTokBetween(uint pos, const std::string & w, const byte * delims,
        const byte * between, std::string & res);
    uint InsertBefore(std::string & w, const byte * sbefore, const byte * s, const byte * sep = NULL);
    uint RInsertBefore(std::string & w, const byte * sbefore, const byte * s, const byte * sep = NULL);
    void CheckPath(std::string & path);
    std::string CheckPath(const byte * path);
    bool GetBool(const byte * str);
    uint GetFullPathNameStr(std::string & fname);

    bool IsNumeric(const byte * str);
    bool IsBool(const byte * str);
    inline bool IsBlank(const byte ch)
        { return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; }
    
    uint RTrim(std::string & w, const byte * ignore_chars = NULL);
    uint LTrim(std::string & w, const byte * ignore_chars = NULL);
    uint Trim(std::string & w, const byte * ignore_chars = NULL);

    const byte * LTrim(const byte *in, uint *out_len, uint in_len, const byte * ignore_chars = NULL);
    const byte * RTrim(const byte *in, uint *out_len, uint in_len, const byte * ignore_chars = NULL);
    const byte * Trim(const byte *in, uint *out_len, uint in_len, const byte * ignore_chars = NULL);

    inline const byte * GetRTrim(std::string & w, const byte * ignore_chars = NULL)
        { RTrim(w, ignore_chars); return (const byte*) w.c_str(); }
    inline const byte * GetLTrim(std::string & w, const byte * ignore_chars = NULL)
        { LTrim(w, ignore_chars); return (const byte*) w.c_str(); }
    inline const byte * GetTrim(std::string & w, const byte * ignore_chars = NULL)
        { Trim(w, ignore_chars); return (const byte*) w.c_str(); }

    inline bool CheckString(const byte * str) { return str && *str; }
    inline bool CheckString(const char * str) { return CheckString((const byte *)str); }
    inline bool CheckString(std::string & str) { return CheckString(str.c_str()); }

    inline bool CmpString(const byte * str1, const byte * str2) {
        if(!CheckString(str1) || !CheckString(str2)) return false;
        return !_stricmp((char *)str1, (char *)str2); }
    inline bool CmpString(const char * str1, const char * str2) {
        return CmpString((const byte *)str1, (const byte *)str2); }

    inline bool CmpString(std::string & str1, std::string & str2) {
        return CmpString(str1.c_str(), str2.c_str()); }
    bool ParseEnvLine(byte * line, byte *& key, byte *& val);
    uint FindKey(const std::string * senv, uint sz, const byte * key);
    uint FindKey(const byte ** senv, uint sz, const byte * key);
    inline bool CmpEnv(const byte * env, const byte * key);
    uint PrintToString(std::string & str, const byte * fmt, ...);
    inline bool IsAllString(const byte * str)
        { return str ? !strcmp((const char*) str, ALL_STRING) : false; }

    byte * CheckName(const byte * name, uint max_len, byte q,
        const char * illigalchars, const byte * sep, byte * buf);
};

#endif
