#include "datatable/field/DataFieldFormat.h"
#include "data/Data.h"
#include "util/StringUtils.h"
#include "AggreGateException.h"
#include "datatable/DataTableUtils.h"
#include "util/simpleobject/AgString.h"
#include <sstream>
#include "datatable/TableFormat.h"
#include "datatable/DataTable.h"
#include "datatable/DataRecord.h"
#include "GlobalVars.h"

TableFormatPtr DataFieldFormat::EXTENSIONS_FORMAT;
TableFormatPtr DataFieldFormat::DATA_EDITOR_OPTIONS_FORMAT;

DataFieldFormat::DataFieldFormat(const AgString &name) : FieldFormat(name)
{
    setTransferEncode(true);
}

char DataFieldFormat::getType()
{
    return AGG_GLOBAL.DATA_FIELD;
}

std::string DataFieldFormat::getFieldClass()
{
    return typeid(Data).name();
}

std::string DataFieldFormat::getFieldWrappedClass()
{
    return typeid(Data).name();
}

AgObjectPtr DataFieldFormat::getNotNullDefault()
{
    return AgObjectPtr(new Data());
}

AgObjectPtr DataFieldFormat::valueFromString(const AgString &value, ClassicEncodingSettingsPtr /*settings*/, bool /*validate*/)
{
    try
    {
        Data *data = new Data();
        std::vector<AgString> parts = StringUtils::split(value, SEPARATOR, 5);
        // parts.get(0) will return transcoder version, currently ignored

        if (parts[1] != AgString(DataTableUtils::DATA_TABLE_NULL))
        {
            data->setId(parts[1].toInt64());
        }
        if (parts[2] != AgString(DataTableUtils::DATA_TABLE_NULL))
        {
            data->setName(parts[2]);
        }

        int previewLen = parts[3].toInt();
        if (previewLen != -1)
        {
            AgString tempStr = parts[5].substr(0, previewLen);
            std::vector<unsigned char> tempVec = tempStr.getBytes(ASCII_CHARSET);
            data->setPreview(tempVec);
        }

        int dataLen = parts[4].toInt();
        if (dataLen != -1)
        {
            AgString str5 = parts[5].substr(previewLen <= 0 ? 0 : previewLen);
            std::vector<unsigned char> dv = str5.getBytes(ASCII_CHARSET);
            data->setData(dv);
        }

        return AgObjectPtr(data);
    }
    catch(...)
    {
        throw AggreGateException("Invalid data block, DataFieldFormat::valueFromString");
    }
}

AgString DataFieldFormat::valueToString(AgObjectPtr value, ClassicEncodingSettingsPtr settings)
{
    UNUSED(settings);

    if (value.get() == NULL)
        return "";

    Data *data = dynamic_cast<Data *> (value.get());
    if (!data)
    {
        return "";
    }

    AgString buf;
    buf += AgString::fromInt(TRANSCODER_VERSION);
    buf += SEPARATOR;

    if (data->getId() != 0)
        buf +=  AgString::fromInt64(data->getId());
    else
        buf += DataTableUtils::DATA_TABLE_NULL;

    buf += SEPARATOR;

    if (data->getName().length() != 0)
        buf += data->getName();
    else
        buf +=  DataTableUtils::DATA_TABLE_NULL;

    buf += SEPARATOR;

    std::vector<unsigned char> p = data->getPreview();
    AgString previewStr = AgString::fromBytes(p, ASCII_CHARSET);
    if (previewStr.length() != 0)
    {
        buf += AgString::fromInt(previewStr.length());
    }
    else
    {
        buf += AgString::fromInt(-1);
    }
    buf += SEPARATOR;

    AgString dataStr = AgString::fromBytes(data->getData(), ASCII_CHARSET);
    if (dataStr.length() != 0)
    {
        buf += AgString::fromInt(dataStr.length());
    }
    else
    {
        buf += AgString::fromInt(-1);
    }

    buf += SEPARATOR;

    if (previewStr.length())
    {
        buf += previewStr;
    }

    if (dataStr.length())
    {
        buf += dataStr;
    }

    return buf;
}

AgString DataFieldFormat::encodeTextEditorOptions(const AgString &mode)
{
    return encodeTextEditorOptions(mode, "", "", std::list<AgString>());
}

AgString DataFieldFormat::encodeTextEditorOptions(const AgString &extensionsDescription, const AgString &folder, std::list<AgString> extensions)
{
    return encodeTextEditorOptions("", extensionsDescription, folder, extensions);
}

AgString DataFieldFormat::encodeTextEditorOptions(const AgString &mode, const AgString &extensionsDescription, const AgString &folder, std::list<AgString> extensions)
{
    // init variables
    if (EXTENSIONS_FORMAT.get() == NULL)
    {
        EXTENSIONS_FORMAT = TableFormatPtr(new TableFormat());
        DATA_EDITOR_OPTIONS_FORMAT = TableFormatPtr(new TableFormat(1, 1));

        FieldFormat* modeF = FieldFormat::create(MODE_FIELD(), AGG_GLOBAL.STRING_FIELD);
        modeF->setNullable(true);

        FieldFormat* edF = FieldFormat::create(EXTENSIONS_DESCR_FIELD(), AGG_GLOBAL.STRING_FIELD);
        edF->setNullable(true);

        // Default value for 'extensions' field
        FieldFormat* extF = FieldFormat::create(EXTENSION_FIELD(), AGG_GLOBAL.STRING_FIELD);
        EXTENSIONS_FORMAT->addField(extF);
        DataTable *dt = new DataTable(EXTENSIONS_FORMAT);
        AgObjectPtr dtobject = AgObjectPtr(dt);

        FieldFormat* extsF = FieldFormat::create(EXTENSIONS_FIELD(), AGG_GLOBAL.DATATABLE_FIELD);
        extsF->setDefault(dtobject);
        extsF->setNullable(true);

        FieldFormat* folderF = FieldFormat::create(FOLDER_FIELD(), AGG_GLOBAL.STRING_FIELD);
        folderF->setNullable(true);

        DATA_EDITOR_OPTIONS_FORMAT->addField(modeF);
        DATA_EDITOR_OPTIONS_FORMAT->addField(edF);
        DATA_EDITOR_OPTIONS_FORMAT->addField(extsF);
        DATA_EDITOR_OPTIONS_FORMAT->addField(folderF);
    }

    DataTablePtr esdt = DataTablePtr();
    if (extensions.size() != 0)
    {
        esdt = DataTablePtr(new DataTable(EXTENSIONS_FORMAT));
        for (std::list<AgString>::iterator it = extensions.begin(); it != extensions.end(); ++it)
        {
            DataRecordPtr dr = esdt->addRecord();
            dr->setValue(EXTENSION_FIELD(), AgObjectPtr(new AgString(*it)));
        }
    }
    DataTablePtr eodt = DataTablePtr(new DataTable(DATA_EDITOR_OPTIONS_FORMAT));
    DataRecordPtr dr = eodt->addRecord();

    dr->setValue(MODE_FIELD(), AgObjectPtr(new AgString(mode)));
    dr->setValue(FOLDER_FIELD(), AgObjectPtr(new AgString(folder)));
    dr->setValue(EXTENSIONS_DESCR_FIELD(), AgObjectPtr(new AgString(extensionsDescription)));
    dr->setValue(EXTENSIONS_FIELD(), esdt);

    return eodt->encode();
}

std::list<AgString> DataFieldFormat::getSuitableEditors()
{
    std::list<AgString> list;
    list.push_back(AGG_GLOBAL.EDITOR_LIST);
    list.push_back(EDITOR_TEXT());
    list.push_back(AGG_GLOBAL.EDITOR_IMAGE);
    list.push_back(AGG_GLOBAL.EDITOR_SOUND);
    list.push_back(AGG_GLOBAL.EDITOR_HEX);
    list.push_back(EDITOR_REPORT());
    return list;
}
