#ifndef ESTR_H
#define ESTR_H

#include "eutils.h"

#include "evar_dec.h"

#include <stdarg.h>
#include <stdio.h>

#include <string.h>
#include <iostream>

#ifdef __APPLE__
 #include <Carbon/Carbon.h>
#elif defined(_MSC_VER)
#define snprintf sprintf_s
#endif


using namespace std;
class estrarray;
#ifdef EUTILS_HAVE_REGEX
class eregexp;
#endif

class estr
{
 private:
  void init(long s=255);
 public:
 char *_str;
 char *_astr;
 long int _strlen;
 long int _asize;
 
  estr(const estr &str);
  estr(const evar& var);

//#ifdef _CPP_STRING
  estr(const std::string& str);
//#endif
#ifdef __APPLE__
  estr(CFStringRef cfstr);
  estr& operator=(CFStringRef str);
#endif
  estr(const estrarray &strarr);
  estr(const unsigned long int i);
  estr(const unsigned int i);
  estr(const long int i);
  estr(const int i);
  estr(const float f);
  estr(const double d);
  estr(const char c);
  estr(const unsigned char c);
  estr(const char *str);
  estr(const char *str,int len);
  estr(bool b);
  estr(void *p);
#ifdef _WIN32
  estr(const wchar_t* str);
#endif
  estr();
  ~estr();

#ifdef __APPLE__
  inline CFStringRef cfstr() const { return(CFStringCreateWithCString(NULL,_str,kCFStringEncodingMacRoman)); }
#endif

  inline long int len() const { return(_strlen); }
  inline long int length() const { return(_strlen); }
  inline long int size() const { return(_strlen); }

  inline void clear() { _str=_astr; _str[0]=0x00; _strlen=0; }

  inline char &operator[](long int pos) { return( _str[pos] ); }
  inline const char operator[](long int pos) const { return( _str[pos] ); }


  inline bool icmp(const estr& str) const { return(_strlen==str._strlen && !strncasecmp(_str,str._str,_strlen)); }
  inline bool cmp(const estr& str,long int l=-1l) const { if (l<len() || l==-1l) l=len(); if (str.len()<l) l=str.len(); return(!memcmp(_str,str._str,l)); }

  inline bool operator>(const estr &str)  const { int tmpc=memcmp(_str,str._str,min(_strlen,str._strlen)); return(tmpc>0 || (tmpc==0 && _strlen>str._strlen)); }
  inline bool operator>=(const estr &str)  const { int tmpc=memcmp(_str,str._str,min(_strlen,str._strlen)); return(tmpc>0 || (tmpc==0 && _strlen>=str._strlen)); }
  inline bool operator<(const estr &str)  const { int tmpc=memcmp(_str,str._str,min(_strlen,str._strlen)); return(tmpc<0 || (tmpc==0 && _strlen<str._strlen)); }
  inline bool operator<=(const estr &str)  const { int tmpc=memcmp(_str,str._str,min(_strlen,str._strlen)); return(tmpc<0 || (tmpc==0 && _strlen<=str._strlen)); }
  inline bool operator==(const char *cstr) const { return(size_t(_strlen)==strlen(cstr) && !memcmp(_str,cstr,_strlen)); }
  inline bool operator==(const estr &str)  const { return(_strlen==str._strlen && !memcmp(_str,str._str,_strlen)); }
  inline bool operator!=(const char *cstr) const { return(size_t(_strlen)!=strlen(cstr) || memcmp(_str,cstr,_strlen)); }
  inline bool operator!=(const estr &str)  const { return(_strlen!=str._strlen || memcmp(_str,str._str,_strlen)); }
//  inline bool operator!=(const estr &str)  const { return(strcmp(_str,str._str)); }
 
  estr &operator =(const evar& var);
  estr &operator =(const estr &str);
  estr &operator =(const char *str);
  #ifdef _WIN32
  estr &operator =(const wchar_t* str);
  #endif
 
  inline estr &operator=(const int &val)    { return(*this=estr(val)); }
  inline estr &operator=(const float &val)  { return(*this=estr(val)); }
  inline estr &operator=(const double &val) { return(*this=estr(val)); }
  /////////////////

  estr &operator+=(const char *str);
  estr &operator+=(const estr &str);

  inline estr &operator+=(const char &val)   
    { _checkSize(_strlen+1);
      _str[_strlen] = val;
      _str[++_strlen] = 0x00;
      return(*this); }
  inline estr &operator+=(const long int &val)    { return(*this=*this+estr(val)); }
  inline estr &operator+=(const int &val)    { return(*this=*this+estr(val)); }
  inline estr &operator+=(const unsigned int &val)    { return(*this=*this+estr(val)); }
  inline estr &operator+=(const unsigned long int &val)    { return(*this=*this+estr(val)); }
  inline estr &operator+=(const float &val)  { return(*this=*this+estr(val)); }
  inline estr &operator+=(const double &val) { return(*this=*this+estr(val)); }
  ///////////////// 

  estr operator+ (const char *str) const;
  estr operator+ (const estr &str) const;

  inline estr operator+(const long int &val)    const { return(*this+estr(val)); }
  inline estr operator+(const long unsigned int &val)    const { return(*this+estr(val)); }
  inline estr operator+(const unsigned int &val)    const { return(*this+estr(val)); }
  inline estr operator+(const int &val)    const { return(*this+estr(val)); }
  inline estr operator+(const float &val)  const { return(*this+estr(val)); }
  inline estr operator+(const double &val) const { return(*this+estr(val)); }
  /////////////////

  int    h() const;
  int    i() const;
  long   l() const;
  float  f() const;
  double d() const;

  bool is_hex() const;
  bool is_int() const;
  bool is_float() const;
  bool is_num() const;
//  bool is_str() const;

  /////////////////

  inline bool reserve(long int size) { _checkSize(size); return(true); }
  void _checkNewSize(long int size);
  void _checkSize(long int size);

  const char *getline(long int &len,const char *eline="\n");
//  const char *getline();
  estr getline();
  bool getline(estr& line);

  estr& trim();
  estr& uppercase();
  estr& lowercase();
  estr hex() const;
  estr hex2bin() const;

  void remove_chars(const char *remove_chars="(){}[]'");
  void clean(const char *ignore_chars="(){}[]'\"\\/+=-_|:;<>,.?`~!@#$%^&*");
  void delstr(const char *str);

  estr &sprintf(estr format,...);

  estr &replace(const estr &pattern, const estr &replace);

  void append(const char *str,long int len);
  void insert(long int i,char c);
  void insert(long int i,const char *str);

  long int erase(long int i,long int len=-1);  
  inline long int rem(long int i,long int len=-1) { return(erase(i,len)); }
  inline long int remove(long int i,long int len=-1) { return(erase(i,len)); }
  inline long int del(long int i,long int len=-1) { return(erase(i,len)); }

  estr substr(long int i,long int len=-1) const;
  long int ifind(const estr &needle,long int i=0) const;
  long int find(const estr &needle,long int i=0) const;
  long findchr(const estr &chrs,long i=0l) const;
  long int count(const estr &needle,long int i=0) const;



  estrarray explode(const estr &seperator) const;
  estrarray grep(const estr& str,const estr& sep="\n") const;
#ifdef EUTILS_HAVE_REGEX  
  estrarray egrep(const eregexp& re,const estr& sep="\n") const;
  estrarray egrepo(const eregexp& re,const estr& sep="\n") const;
#endif

  inline int &operator>>(int &val) const
    { return(val=i()); }
  inline float &operator>>(float &val) const 
    { return(val=f()); }
  inline double &operator>>(double &val) const
    { return(val=d()); }
  inline estr &operator>>(estr &val) const
    { return(val=*this); }

  inline estr &operator<<(const int &val)
    { return(*this=val); }
  inline estr &operator<<(const float &val)
    { return(*this=val); }
  inline estr &operator<<(const double &val)
    { return(*this=val); }
  inline estr &operator<<(const estr &val)
    { return(*this=val); }


  void json_serial(estr &data) const;
  void serial(estr &data) const;
  size_t unserial(const estr &data,size_t i);
  void serial(const efile &f) const;
  bool unserial(const efile &f);

  friend ostream &operator<<(ostream &stream,const estr &str);
};


estr strprintf(estr format,...);

inline estr hex(unsigned char val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.2hhx",val);
  res._strlen=len;
  return(res);
}

inline estr hex(const estr& str)
{
  estr res;
  res.reserve(str.len()*2);
  for (int i=0; i<str.len(); ++i)
    res._strlen+=snprintf(&res._str[i*2],str.len()*2,"%.2hhx",str[i]);
  return(res);
}

inline estr hex(char val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.2hhx",val);
  res._strlen=len;
  return(res);
}

inline estr hex(unsigned short val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.4hx",val);
  res._strlen=len;
  return(res);
}

inline estr hex(short val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.4hx",val);
  res._strlen=len;
  return(res);
}

inline estr hex(unsigned int val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.8x",val);
  res._strlen=len;
  return(res);
}

inline estr hex(int val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.8x",val);
  res._strlen=len;
  return(res);
}

inline estr hex(unsigned long val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"0x%.16lx",val);
  res._strlen=len;
  return(res);
}

inline estr hex(long val)
{
  estr res;
  res.reserve(34);
  int len;
  len=snprintf(res._str,34,"%.16lx",val);
  res._strlen=len;
  return(res);
}


inline estr operator+(const char *str1,const estr &str2)
{ return(estr(str1)+str2); }

inline estr operator+(long int val,const estr &str2)
{ return(estr(val)+str2); }

inline estr operator+(unsigned long int val,const estr &str2)
{ return(estr(val)+str2); }

inline estr operator+(unsigned int val,const estr &str2)
{ return(estr(val)+str2); }

inline estr operator+(int val,const estr &str2)
{ return(estr(val)+str2); }

inline estr operator+(float val,const estr &str2)
{ return(estr(val)+str2); }

inline estr operator+(double val,const estr &str2)
{ return(estr(val)+str2); }

inline ostream &operator<<(ostream &stream,const estr &str){
  int i;
  for (i=0; i<str.len(); ++i)
    stream << str[i];
  return(stream);
}

#ifdef _WIN32
void wstr(wchar_t **lpcwstr,const estr& str);
#endif

#ifdef EUTILS_HAVE_ZLIB
estr gzcompress(const estr& input);
estr gzdecompress(const estr& input);
estr compress(const estr& input);
estr decompress(const estr& input);
#endif

#include "estrarray.h"

#endif

