#ifndef _STR_H
#define _STR_H

#include <string>
#include <sstream>
#include <cctype>
#include <cstring>
#include "base64.h"

namespace string_tools {

using namespace std;

class str_exception {
   const char * message;

public:
   str_exception(const char * message) {
      this->message = message;
   }

   const char * get_message() const {  
      return message;
   }
};

inline
int
x2c(const string & hex0)
{
   const char h[16] = { '0', '1', '2', '3', '4', '5', '6',
                        '7', '8', '9', 'A', 'B', 'C', 'D',
                        'E', 'F' };
   const int ih[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
   const int ih2[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
                         0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
   int ret = 0;
   for(int i = 0; i < 16; i++) {
      if(h[i] == toupper(hex0[0])) {
         if(ret == 0 && ih2[i] != 0) ret = 1;
         if(ih2[i] != 0) ret *= ih2[i];
      }
      if(h[i] == toupper(hex0[1])) {
         if(ret == 0 && ih[i] != 0) ret = 1;
         if(ih[i] != 0) ret *= ih[i];
      }
   }
   return ret;
}

inline
string 
not_null(const char * value) 
{
   string ret;
   if(value != 0)
      ret = value;
   return ret;
}


inline
string 
csv_encode(const string & str) 
{
   string ret;
   for(size_t i = 0; i < str.size(); i++) {
      if(str[i] == '\"') {
         ret += "\"\"";
      }
      else {
         ret += str[i];
      }
   }
   return ret;
}


inline 
string
str_right(const string & str, size_t n) 
{
   string ret;
   if(n < str.size()) {
      ret = str.substr(str.size()-1-n);
   }
   else if(n == str.size()) {
      ret = str;
   }
   return ret;
}

inline
string
str_left(const string & str, size_t n)
{
   string ret;
   if(n < str.size()) {
      ret = str.substr(0,n-1);
   }
   else if(n == str.size()) {
      ret = str;
   }
   return ret;
}

inline
string
str_mid(const string & str, size_t index, size_t n)
{
   string ret;
   if(n < str.size()) {
      ret = str.substr(index, n);
   }
   else if(n == str.size()) {
      ret = str;
   }
   return ret;
}

inline
string
str_repeat(const char ch, const size_t n)
{
   string str;
   for(size_t i = 0; i < n; i++) 
      str += ch;
   return str;
}

inline
string
str_reverse(const string & str)
{
   string ret;
   for(size_t i = 0; i < str.size(); i++) {
      ret = str[i] + ret;
   }
   return ret;
}

inline
string
base64_encode(const string & str)
{
   string ret;
   ret = b64encode(str.c_str(), str.size());
   return ret;
}

inline
string
base64_decode(const string & str)
{
   string ret;
   ret = b64decode(str.c_str(), str.size());
   return ret;
}

inline
string
uuencode(const string & str)
{
   string ret;
   return ret;
}

inline
string
uudecode(const string & str)
{
   string ret;
   return ret;
}

inline
bool
is_file_ext(const string & file_name,
            const string & filter)
{
   size_t size = filter.size()+1;
   char * buffer = new char[size];
   memset(buffer, 0, size);
   strcpy(buffer, filter.c_str());
   char * ptr = strtok(buffer, "|");
   size_t len;
   bool ret = false;
   while(ptr) {
      len = strlen(ptr);

      if(len < file_name.size()) {
         if(strncmp(file_name.c_str()+file_name.size()-len, ptr, len) == 0) {
            ret = true;
            break;
         }
      }

      ptr = strtok(NULL, "|");
   }
   delete [] buffer;
   return ret;
}


inline
string replace(const string & buffer, const string & str, const string & rep)
{
   string ret = buffer;
   string::size_type p;

   while((p=ret.find(str)) != string::npos) {
      ret = ret.substr(0, p) + rep + ret.substr(p+str.size());
   }

   return ret;
}

template< class T >
inline
string to_string(const T & t)
{
   stringstream ss;
   ss << t;
   string temp;
   ss >> temp;
   return temp;
}

inline
long to_long(const string & temp)
{
   return atol(temp.c_str());
}

inline
double to_double(const string & temp)
{
   return atof(temp.c_str());
}

inline
bool to_bool(const string & temp) 
{
   bool ret;
   if(temp == "true") 
      ret = true;
   else if(temp == "false")
      ret = false;
      throw str_exception("can't convert to bool data type...");
   return ret;
}

inline
bool ends_with(const string & str, const string & end) {
   bool ret = false;
   string::size_type ptr = str.rfind(end);
   if(ptr != string::npos) {
      string temp = str.substr(ptr);
      if(temp == end) {
         ret = true;
      }
   }
   return ret;
}

inline
bool starts_with(const string & str, const string & end) {
   bool ret = false;
   if(str.find(end) == 0) {
      ret = true;
   }
   return ret;
}

inline
string trim(const string & str)
{
   string ret,temp;
   stringstream s;
   s << str;
   while(s >> temp) {
      if(ret.size() && temp != ",") 
         ret += " ";
      ret += temp;
   }
   return ret;
}

template< class T >
inline
string to_hex(const T & val)
{
   stringstream s;
   s << hex << val;
   string ret;
   s >> ret;
   return ret;
}

inline
string url_escape(const string & str)
{
   string ret;
   stringstream s;
   string table = "abcdefhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
   for(size_t i = 0; i < str.size(); i++) {
      if(str[i] == ' ') 
         s << "+";
      else if(table.find(str[i]) != string::npos)
         s << str[i];
      else
         s << "%" << hex << (int)str[i]; 
   }
   ret = s.str();
   return ret;
}

inline
string strip_html(const string & html) {
   string ret;
   bool in = false;
   for(size_t i = 0; i < html.size(); i++) {
      if(html[i] == '<') 
         in = true;
      else if(html[i] == '>') {
         in = false;
         ret += ' ';
         continue;
      }
      if(!in) {
         ret += html[i];
      }
   }
   return ret;
}

inline
string 
page_encode(const string & str)
{
   stringstream ss;
   for(size_t i = 0; i < str.size(); i++) {
      if(str[i] == '<') {
         ss << "&lt;";
      }
      else if(str[i] == '>') {
         ss << "&gt;";
      }
      else if(str[i] == '&') {
         ss << "&amp;";
      }
      else if(str[i] == '\"') {
         ss << "&quot;";
      }
      else if(str[i] == ';') {
         ss << "&semi;";
      }
      else {
         ss << str[i];
      }
   }
   return ss.str();
}

inline
string to_lower(const string & str) 
{
   string ret;
   for(size_t i = 0; i < str.size(); i++) {
     ret += tolower(str[i]);
   }
   return ret;
}

inline
string csv_escape(const string & str) 
{
   string ret;
   for(size_t i = 0; i < str.size(); i++) {
      if(str[i] == '\"') {
         ret += "\"\"";
      }
      else {
         ret += str[i];
      }
   }
   return ret;
}

inline
string clean_text(const string & str) {
   string ret;
   for(size_t i = 0; i < str.size(); i++) {
      if(ispunct(str[i]) || isalnum(str[i]) || isspace(str[i])) {
         ret += str[i];
      }
   }
   return ret;
}

inline
bool is_digit(char ch)
{
   bool ret = false;
   const char * table = "0123456789";
   if(strchr(table, ch) != 0) 
      ret = true;
   return ret;
}

inline
bool is_int(const string & str)
{
   bool ret = false;
   for(size_t i = 0; i < str.size(); i++) {
      if(is_digit(str[i])) {
         ret = true;
      }
      else {
         ret = false;
         break;
      }
   }
   return ret;
}

inline
bool is_float(const string & str)
{
   bool ret = false;
   for(size_t i = 0; i < str.size(); i++) {
      if(is_digit(str[i]) || str[i] == '.') {
         ret = true;
      }
      else {
         ret = false;
         break;
      }
   }
   return ret;
}



}


#endif /* _STR_H */
