#include "Logger/LoggerMacroses.h"
#include "Utils.h"

#include <syncml/core/ComplexData.h>
#include <syncml/core/Meta.h>
#include <syncml/core/Target.h>

#define NONCE_LENGTH    7
const char NonceChars[] = "ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";


namespace NS_DM_Client
{
    Funambol::NextNonce * CreateNonce()
    {
        char nonce[NONCE_LENGTH];
        memset(nonce, '\0', NONCE_LENGTH);
        int count = sizeof(NonceChars)/sizeof(NonceChars[0]);
        for (int i=0; i<NONCE_LENGTH; ++i)
            nonce[i] = NonceChars[rand() % count];

        return new Funambol::NextNonce(nonce, NONCE_LENGTH);
    }
        
        
    bool IsBooleanTrue(const String &value)
    {
        return  !value.compare("true")      || 
                !value.compare("TRUE")      || 
                !value.compare("true\n")    || 
                !value.compare("TRUE\n")    || 
                !value.compare("1")         || 
                !value.compare("1\n");
    }


    void PrintMessage(const char * logger, const char * prefix, const char * msg)
    {
        GLDEBUG(logger, "print message, size is %d [%p]", msg ? strlen(msg) : 0, msg);

        // the aim of this routine is to find and shorten possibly too large Data section
        char * message = NULL;
        if (msg && msg[0])
        {
            message = Funambol::stringdup(msg);
        }
        
        // delete all Data sections larger than 64 bytes
        const char * datab = "<Data>";
        const char * datae = "</Data>";

        if (message && message[0])
        {
            char * pDataB = message;
            char * pDataE = NULL;
            do
            {
                pDataB = strstr(pDataB, datab);
    ///         GLDEBUG(logger, "sdsdsd     %s", pDataB);
                if (pDataB)
                {
                    pDataB += strlen(datab);
                    pDataE = strstr(pDataB, datae);
                    
                    int datasize = pDataE - pDataB;
                    const char * expand_pattern = "(..., %d bytes data section)";
                    if (datasize > (int)(64 + strlen(expand_pattern) + 16))
                    {
                        char sizestr[128] = {0};
                        __sprintf(sizestr, expand_pattern, datasize);

                        char * tail = new char[strlen(message)];
                        memset(tail, 0, strlen(message));
                        __strcpy(tail, pDataE);

                        __strcpy(pDataB+64, sizestr);
                        __strcpy(pDataB+64+strlen(sizestr), tail);

                        pDataB = pDataB+64+strlen(sizestr)+strlen(pDataE);
                        SAFE_DELETE_ARR(tail);
                    }
                }
            }
            while(pDataB);
        }

        GLDEBUG(logger, "%s [%d bytes]\n\n%s\n", prefix, msg ? strlen(msg) : 0, message ? message : "NULL");
        SAFE_DELETE_ARR(message);
    }


    String ToString(int value)
    {
        const int maxSize = 1024;
        char buffer[maxSize];
        memset(buffer, '\0', maxSize);
        __sprintf(buffer, "%i", value);
        //_itoa(value, buffer, 10);
        return buffer;
    }

    static inline char* char2hex(char c, char* buf)
    {
        static const char bits2char[] = "0123456789ABCDEF";
        buf[0] = bits2char [((unsigned char)c) >> 4];
        buf[1] = bits2char [((unsigned char)c) & 0xF];
        buf[2] = 0;
        return buf;
    }


    const char* Utils::ToAsciiHex(String& dest, const void* data, size_t dataSize, char byteSeparator)
    {
        const size_t byte2asciiSize = 2;
        const size_t reserveSize = dataSize * (byte2asciiSize + (byteSeparator == 0) ? 0 : 1);

        dest.clear();
        dest.reserve(reserveSize);

        char separ[2];
        memset(separ, '\0', 2);
        separ[0] = byteSeparator;
////        separ[1] = 0;

        char buf[4];
        memset(buf, '\0', 4);
        const char* ptr = static_cast<const char*>(data);
        while (dataSize--)
        {
            dest += char2hex(*ptr++, buf);
            dest += separ;
        }

        return dest.c_str();
    }

    void Utils::ConstructItem(Funambol::Item &item, const URI &target, cstr data)
    {
        ConstructItem(item, target, data, "chr", "text/plain");
    }
    
    void Utils::ConstructItem(Funambol::Item &item, const URI &target, cstr data, cstr format, cstr typ)
    {
        if (target.size())
        {
            Funambol::Target t(target.c_str());
            item.setTarget(&t);
        }
        
        if (data && data[0])
        {
            Funambol::ComplexData cdata(data);
            item.setData(&cdata);
        }

        if ((format && format[0]) || (typ && typ[0]))
        {
            Funambol::Meta meta;
            meta.setFormat(format);
            meta.setType(typ);
            item.setMeta(&meta);
        }
    }

    
    bool __fopen(const char* name, const char* mode, FILE*& file)
    {
    #if defined(PLATFORM_WINDOWS)
        return (fopen_s(&file, name, mode) == 0);
    #else
        return ((file = fopen(name, mode)) != 0);
    #endif
    }

    void trim(String &str)
    {
        String::size_type pos = str.find_last_not_of(' ');
        if(pos != String::npos)
        {
            str.erase(pos + 1);
            pos = str.find_first_not_of(' ');
            if (pos != String::npos)
                str.erase(0, pos);
        }
        else
            str.erase(str.begin(), str.end());
    }
}
