/*
*/

#include "dpstring.h"
#include <dpuser_utils.h>
#include <stdio.h>
#include <stdarg.h>

#ifdef WIN
#pragma warning (disable: 4018) // disable warning for comparing signed and unsigned
#pragma warning (disable: 4244) // disable warning for conversion from double to float
#include <direct.h>
#else
#include <unistd.h>
#endif

//#include <regex/regex.h>
#include <regex/regex_sr.h>

using std::string;

long numberOfdpString = 0;

dpString::dpString()
		: string() {
    numberOfdpString++;
//    printf("dpString constructor: Number of dpString: %i\n", numberOfdpString);
}

dpString::dpString(const char *s) 
		: string(s) {
    numberOfdpString++;
//    printf("dpString constructor: Number of dpString: %i\n", numberOfdpString);
}

dpString::dpString(const string &s)
		: string(s) {
    numberOfdpString++;
//    printf("dpString constructor: Number of dpString: %i\n", numberOfdpString);
}

dpString::dpString(const dpString &s)
		: string(s) {
    numberOfdpString++;
//    printf("dpString constructor: Number of dpString: %i\n", numberOfdpString);
}

dpString::~dpString() {
    numberOfdpString--;
//    printf("dpString destructor: Number of dpString: %i\n", numberOfdpString);
}

void dpString::operator +=(const dpString &s) {
	append(s);
}

void dpString::operator +=(const char *s) {
	append(s);
}

void dpString::operator +=(const char c) {
	append(&c, 1);
}

const char *dpString::to_c_str() const {
    return c_str();
}

dpString dpString::mid(dpint64 begin, dpint64 length) const {
	return dpString(substr(begin, length));
}

dpString &dpString::remove(dpint64 begin, dpint64 length) {
	erase(begin, length);
	return *this;
}

dpString dpString::number(const long n) {
	char num[256];

	::sprintf(num, "%li", n);

	return dpString(num);
}

int dpString::contains(const char c) {
	int rv = 0, i;

	for (i = 0; i < size(); i++) if (c_str()[i] == c) rv++;

	return rv;
}

int dpString::contains(const char *s) {
	dpint64 pos = 0;
	dpint64 n = strlen(s);
	int rv = 0;

	while (pos < npos) {
		pos = find(s, pos);
		if (pos < npos) {
			pos += n;
			rv++;
		}
	}
	return rv;
}

dpString dpString::simplifyWhiteSpace() {
	dpString rv;
	char _tmp[2];
	rv = stripWhiteSpace();

	_tmp[1] = 0;
	_tmp[0] = 9;
	rv.replace(dpString(_tmp), dpString(" "));
	_tmp[0] = 10;
	rv.replace(dpString(_tmp), dpString(" "));
	_tmp[0] = 11;
	rv.replace(dpString(_tmp), dpString(" "));
	_tmp[0] = 12;
	rv.replace(dpString(_tmp), dpString(" "));
	_tmp[0] = 13;
	rv.replace(dpString(_tmp), dpString(" "));

	while (rv.find("  ") < npos) rv.replace(dpString("  "), dpString(" "));

	return rv;
}

dpString dpString::stripWhiteSpace() {
	dpString rv(*this);

    if (rv.size() > 0) {

	while ((rv[0] == 9)
		|| (rv[0] == 10)
		|| (rv[0] == 11)
		|| (rv[0] == 12)
		|| (rv[0] == 13)
		|| (rv[0] == 32)) rv.erase(0, 1);
	while ((rv[rv.size()-1] == 9)
		|| (rv[rv.size()-1] == 10)
		|| (rv[rv.size()-1] == 11)
		|| (rv[rv.size()-1] == 12)
		|| (rv[rv.size()-1] == 13)
		|| (rv[rv.size()-1] == 32)) rv.erase(rv.size()-1, 1);

    }
	return rv;
}

dpString & dpString::strtrim(int flag) {
	if ((flag == 1) || (flag == 2)) {
		while (((*this)[0] == 9)
			|| ((*this)[0] == 10)
			|| ((*this)[0] == 11)
			|| ((*this)[0] == 12)
			|| ((*this)[0] == 13)
			|| ((*this)[0] == 32)) erase(0, 1);
	}
	if ((flag == 0) || (flag == 2)) {
		while (((*this)[size()-1] == 9)
			|| ((*this)[size()-1] == 10)
			|| ((*this)[size()-1] == 11)
			|| ((*this)[size()-1] == 12)
			|| ((*this)[size()-1] == 13)
			|| ((*this)[size()-1] == 32)) erase(size()-1, 1);
	}

	return *this;
}

bool dpString::isEmpty() const {
    return length() == 0;
}


dpString dpString::right(const dpint64 length) const {
	dpString rv;

	if (length >= size()) rv = *this;
	else rv = substr(size() - length, length);

	return rv;
}

dpString dpString::left(const dpint64 length) const {
	dpString rv;

	if (length >= size())
      rv = *this;
	else
      rv = substr(0, length);

	return rv;
}

dpString dpString::upper() {
	dpString rv(*this);
	dpint64 i;

	for (i = 0; i < length(); i++) rv[i] = toupper(rv.c_str()[i]);
	return rv;
}

dpString dpString::lower() {
	dpString rv(*this);
	dpint64 i;

	for (i = 0; i < length(); i++) rv[i] = tolower(rv.c_str()[i]);
	return rv;
}

void dpString::setNum(const double d) {
	char num[256];

	::sprintf(num, "%g", d);

	*this = num;
}

void dpString::setNum(const long l) {
	char _tmp[256];

	::sprintf(_tmp, "%li", l);

	*this = _tmp;
}

void dpString::truncate(dpint64 length) {
	erase(length, size() - length);
}

float dpString::toFloat(bool *ok) {
	float rv;
        char *end;

        rv = (float)strtod(c_str(), &end);

	if (ok != NULL) {
                *ok = (c_str() != end);
	}

	return rv;
}

double dpString::toDouble() {
	return atof(c_str());
}

void dpString::sprintf(const char *fmt, ...) {
	char _tmp[1024];
	va_list args;

	va_start(args, fmt);
#ifdef WIN
	_vsnprintf(_tmp, 1023, fmt, args);
#else
	vsnprintf(_tmp, 1023, fmt, args);
#endif
	va_end(args);

	*this = _tmp;
}

dpString &dpString::replace(dpint64 one, dpint64 two, const char *str) {
	string::replace(one, two, str);

	return *this;
}

dpString &dpString::replace(const dpString &before, const dpString &after) {
	dpint64 pos = 0;
	dpint64 n0 = before.size();
	dpint64 n1 = after.size();
	dpint64 n = (n0 > n1 ? n0 : n1);

	while (pos < npos) {
		pos = find(before, pos);
		if (pos < npos) {
			string::replace(pos, n0, after);
			pos += n;
		}
	}
	return *this;
}
                 
dpString &dpString::replace(const dpRegExp &searchExpr, const dpString &replaceExpr) {
    int nPos = 0;
    CRegExp r;
    char* replaceStr = NULL;
    int replaceLen = 0;
    int foundLen = 0;
    int curPos = 0;

    try {
        // setup regular expression
        if (r.RegComp(searchExpr.c_str()) != NULL) {
            // search first occurence
            nPos = r.RegFind(c_str());
            replaceStr = (char*)replaceExpr.c_str();
            replaceLen = strlen(replaceExpr.c_str());
            foundLen = r.GetFindLen();
            if (searchExpr.find('\\', 0) == 0)
                foundLen -= 1;

            // search further occurences
            if (replaceLen > foundLen) {
                // move nPos forward if length of replacement string is longer than search string (to avoid recursion!)        
                curPos = 0;
                while((nPos != -1) && (nPos <= strlen(c_str()))) {
                    curPos = nPos;
            
                    erase(nPos, r.GetFindLen());
                    insert(nPos, replaceStr);
                    
                    curPos += replaceLen;
                    nPos = r.RegFind(c_str() + curPos);
    
                    if (nPos != -1)
                        nPos += curPos;
                }
            } else {
                while((nPos != -1) && (nPos <= strlen(c_str()))) {
                    erase(nPos, r.GetFindLen());
                    insert(nPos, replaceStr);
                    
                    nPos = r.RegFind(c_str());
                }
            }
        }
        return *this;
    }
    catch (std::exception e)
    {
        dp_output(">>> %s\n", e.what());
        throw;
    }
}

long dpString::strpos(dpString &seek, const bool cs) {
	long rv = -1;
	if (cs) {
		rv = find(seek);
	} else {
		dpString source, sseek;
		source = lower();
		sseek = seek.lower();
		rv = source.find(sseek);
	}
	if (rv >= size()) rv = -1;

	return rv;
}

