#include "datatable/field/DataTableFieldFormat.h"
#include "datatable/DataTable.h"
#include "datatable/TableFormat.h"
#include "datatable/DataTableReplication.h"
#include "datatable/encoding/ClassicEncodingSettings.h"
#include "AggreGateException.h"
#include "GlobalVars.h"

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

    fieldValidator = FieldValidatorPtr(new LocalFieldValidator(this));
    addValidator(fieldValidator);
}

char DataTableFieldFormat::getType()
{
    return AGG_GLOBAL.DATATABLE_FIELD;
}

std::string DataTableFieldFormat::getFieldClass()
{
    return typeid(DataTable).name();
}

std::string DataTableFieldFormat::getFieldWrappedClass()
{
    return typeid(DataTable).name();
}

AgObjectPtr DataTableFieldFormat::getNotNullDefault()
{
    return AgObjectPtr(new DataTable());
}

AgObjectPtr DataTableFieldFormat::valueFromString(const AgString &value, ClassicEncodingSettingsPtr settings, bool validate)
{
    try
    {
        AgObjectPtr obj = getDefaultValue();
        DataTable *defaultValue = NULL;

        if (obj != NULL)
        {
            defaultValue = dynamic_cast<DataTable *>(obj.get());
            assert(defaultValue);
        }

        bool tempEncodeFieldNames = false;
        TableFormatPtr oldFormat;

        if (settings.get() != NULL)
        {
            oldFormat = settings->getFormat();
            if (defaultValue != NULL)
            {
                settings->setFormat(defaultValue->getFormat());
            }
            tempEncodeFieldNames = settings->isEncodeFieldNames();
        }
        else
        {
            settings = ClassicEncodingSettingsPtr(new ClassicEncodingSettings(false));
            tempEncodeFieldNames = false;
        }

        DataTablePtr res = DataTablePtr(new DataTable(value, settings, validate));

        if (defaultValue != NULL && defaultValue->getFieldCount() > 0 && !res->getFormat()->extend(defaultValue->getFormat()))
        {
            DataTablePtr newRes = DataTablePtr(defaultValue->clone());
            DataTableReplication::copy(*res, newRes, true, true, true);
            res = newRes;
        }

        // todo need check try/finally from java
        if (validate)
        {
            res->validate();
        }

        if (settings.get() != NULL)
        {
            settings->setFormat(oldFormat);
            if (tempEncodeFieldNames)
            {
                settings->setEncodeFieldNames(tempEncodeFieldNames);
            }
        }

        return res;

    }
    catch (...)
    {
        throw AggreGateException("Error constructing value of field, DataTableFieldFormat::valueFromString()");
    }
}

AgString DataTableFieldFormat::valueToString(AgObjectPtr value, ClassicEncodingSettingsPtr settings)
{
    if (value.get() == NULL)
    {
        return "";
    }

    bool oldEncodeFormat = settings.get() != NULL ? settings->isEncodeFormat() : false;

    if (settings.get() != NULL)
    {
        settings->setEncodeFormat(true);
    }

    try
    {
        DataTable *dt = dynamic_cast<DataTable *>(value.get());
        // assert(dt);

        return dt->encode(settings);
    }
    catch(...) {}

    if (oldEncodeFormat != false)
        settings->setEncodeFormat(oldEncodeFormat);

    return "";
}

AgString DataTableFieldFormat::encodeEditorOptions(bool showTableData)
{
    return showTableData ? "1" : "0";
}

AgObjectPtr DataTableFieldFormat::LocalFieldValidator::validate(AgObjectPtr value)
{
    AgObjectPtr obj = ff->getDefaultValue();
    DataTablePtr def = boost::dynamic_pointer_cast<DataTable>(obj);

    if (def == NULL || def->getFieldCount() == 0)
    {
        return value;
    }

    DataTable *dt = dynamic_cast<DataTable *>(value.get());
    if (dt == NULL)
    {
        return value;
    }
    AgString msg = dt->getFormat()->extendMessage(def->getFormat());
    if (msg.length())
    {
        DataTablePtr newValue = DataTablePtr(def->clone());
        DataTableReplication::copy(*dt, newValue, true, true, true);
        return newValue;
    }

    return value;
}

DataTableFieldFormat::LocalFieldValidator *DataTableFieldFormat::LocalFieldValidator::clone()
{
    return new LocalFieldValidator(ff);
}

