// 
// This file is part of MolMeccano, a cross-platform C++ chemical library.
//
// Copyright (C) 2001-2007 Alexey Nikitin
//
#ifdef WIN32
#pragma warning (disable : 4996)
#endif

#include "Text.h"

#include "Flaw.h"

#include <stdio.h>
#include <string.h>
#include <locale>
#include <string>

#ifdef QT_DLL
#include <QObject>
#include <QString>
#include <QTextCodec>
#endif


namespace MM
{
#ifdef QT_DLL
Text::Text (QString text)
{
    if (text.isEmpty())
    {
        buf_size_ = 0;
        buf_ = new char[ 1 ];
        buf_[0] = '\0';
    }
    else
    {
        //QByteArray   ba  = text.toLatin1();
        //QByteArray   ba  = text.toLocal8Bit();
        //QByteArray   ba  = text.toUtf8();
        //QByteArray   ba  = text.toAscii();

        QTextCodec * codec = QTextCodec::codecForLocale ();
        //QTextCodec * codec = QTextCodec::codecForName ("KOI8-R");
        //QTextCodec * codec = QTextCodec::codecForName ("Windows-1251");
        if (codec == 0)
            return;
        QTextCodec::setCodecForTr(codec);
        QByteArray   ba  = codec->fromUnicode (text);

        const char * str = ba.data ();

        ////std::string string = text.toStdString ();
        ////const char * str = string.c_str();
        //std::wstring wstring = text.toStdWString ();
        //std::string string;
        //string.assign (wstring.begin(), wstring.end());
        //const char * str = string.c_str();

        buf_size_ = text.size ();
        buf_ = new char [buf_size_ + 1];
        strcpy (buf_, str);
    }
}

Text:: operator QString () const
{
    //return QString (QLatin1String (c_str ()));
    return QString (QObject::tr(c_str ()));
    //return QString (QObject::trUtf8(c_str ()));
}
#endif

Text::~Text ()
{
    delete [] buf_;
    buf_ = 0;
    buf_size_ = 0;
}

Text::Text()
: 
    buf_size_(0)
{
    buf_ = new char[ 1 ];
    buf_[0] = '\0';
}

Text::Text (Text const & text)
: 
    buf_size_(text.buf_size_)
{
    buf_ = new char [buf_size_ + 1];
    strcpy (buf_, text.buf_);
}

Text::Text (const char *text)
{
    //REQUIRE( "Text exist.", text != 0 );
    #ifndef NDEBUG
    if (text == 0) FLAW ("Text does not exist.");
    #endif

    buf_size_ = strlen (text);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, text);
}

Text::Text (bool text)
{
    char buffer[20];
    if (text)  sprintf (buffer, "true");
    else       sprintf (buffer, "false");
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (char text)
{
    buf_size_ = 1;
    buf_  = new char [buf_size_ + 1];
    buf_[0] = text;
    buf_[1] = '\0';
}

Text::Text (short text)
{
    char buffer[20];
    sprintf (buffer, "%hi", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (int text)
{
    char buffer[20];
    sprintf (buffer, "%i", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (long text)
{
    char buffer[20];
    sprintf (buffer, "%li", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (unsigned short text)
{
    char buffer[20];
    sprintf (buffer, "%hu", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (unsigned int text)
{
    char buffer[20];
    sprintf (buffer, "%u", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (unsigned long text)
{
    char buffer[20];
    sprintf (buffer, "%lu", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (float text)
{
    char buffer[20];
    sprintf (buffer, "%g", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (double text)
{
    char buffer[20];
    sprintf (buffer, "%lg", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (double text, int precision)
{
    char buffer[40];
    Text format_specification = "%.";
    format_specification += precision;
    format_specification += "lg";
    sprintf (buffer, format_specification.c_str(), text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (long double text)
{
    char buffer[40];
    sprintf (buffer, "%Lg", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

Text::Text (void *text)
{
    char buffer[20];
    sprintf (buffer, "%p", text);
    buf_size_ = strlen (buffer);
    buf_  = new char [buf_size_ + 1];
    strcpy (buf_, buffer);
}

bool Text::
is_empty () const
{
//    bool result = (strtok (NULL, " \t\n") == NULL);
//    return result;

    using namespace std;

    string text (buf_);
    string::size_type start = text.find_first_not_of (" \t\n");
   
    return start == string::npos;  
}

int Text::
size (void) const
{
    return strlen (buf_);
}

int Text::
length (void) const
{
    return strlen (buf_);
}

const Text & Text::
operator = (const Text & text)
{
    if (this != &text)
    {
        if (buf_size_ < text.size())  
            realloc (text.buf_size_); //fix buf_size_ or size();
        strcpy (buf_, text.buf_);
    }
    return  *this;
}

const Text & Text::
operator += (const Text & text)
{
    int s  = size();
    int texts = text.size();
    if (buf_size_ < (s + texts))  realloc (s + texts);
    strcat (buf_, text.buf_);
    return *this;
}

bool operator == (const Text & l, const Text & r)
{
    return  strcmp (l.buf_, r.buf_) == 0;
}

bool operator != (const Text & l, const Text & r)
{
    return  strcmp (l.buf_, r.buf_) != 0;
}

bool operator < (const Text & l, const Text & r)
{
    return  strcmp (l.buf_, r.buf_) < 0;
}

bool operator > (const Text & l, const Text & r)
{
    return  strcmp (l.buf_, r.buf_) > 0;
}

char Text::
operator [] (int i) const
{
    //REQUIRE( "In range.", i >= 0 && i < size() );
    #ifndef NDEBUG
    if (i < 0 || i >= size()) 
        FLAW ("Out of range.");
    #endif

    return buf_[i];
}

char & Text::
operator [] (int i)
{
    //REQUIRE( "In range.", i >= 0 && i < size() );
    #ifndef NDEBUG
    if (i < 0 || i >= size()) 
        FLAW ("Out of range.");
    #endif

    return buf_[i];
}

const char * Text::
c_str() const
{
    return buf_;
}

Text Text::
to_upper() const
{
    Text result = *this;
//fix U    std::ctype<char> ct;
//fix U    ct.toupper (result.buf_, result.buf_+result.buf_size_);
    for (int i=0;  i<size();  ++i)
        result.buf_[i] = toupper (buf_[i]);
    return result;
}

Text Text::
to_lower() const
{
    Text result = *this;
//fix U    std::ctype<char> ct;
//fix U    ct.tolower (result.buf_, result.buf_+result.buf_size_);
    for (int i=0;  i<size();  ++i)
        result.buf_[i] = tolower (buf_[i]);
    return result;
}

int Text::
to_int () const
{
    int result;
    sscanf (buf_, "%i", &result);
    return result;
}

double Text::
to_double () const
{
    double result;
    sscanf (buf_, "%lg", &result);
    return result;
}


void    Text::
clear()
{
    strcpy (buf_, "");
}

void  Text::
realloc (int new_size)
{
    char *tmp = new char [new_size + 1];
    if (new_size >= size())  strcpy (tmp, buf_);
    delete [] buf_;
    buf_ = tmp;
    buf_size_ = new_size;
}

}//MM


