#include "DataTableUtils.h"
#include "datatable/FieldFormat.h"
#include "datatable/DataTable.h"
#include "datatable/encoding/TransferEncodingHelper.h"
#include "datatable/field/DateFieldFormat.h"
#include "datatable/field/LongFieldFormat.h"
#include "datatable/field/StringFieldFormat.h"
#include "datatable/field/ColorFieldFormat.h"
#include "datatable/field/DataFieldFormat.h"
#include "datatable/TableFormat.h"
#include "datatable/DataRecord.h"
#include "datatable/DataTableConversion.h"
#include "datatable/DataTableReplication.h"
#include "datatable/DataTableBindingProvider.h"
#include "util/simpleobject/AgString.h"
#include "expression/Evaluator.h"
#include "expression/ReferenceResolver.h"
#include "Cres.h"
#include "AggreGateException.h"
#include "IllegalArgumentException.h"
#include "binding/DefaultBindingProcessor.h"
#include "GlobalVars.h"

std::map<AgString, AgString> DataTableUtils::EDITOR_SELECTION_VALUES = DataTableUtils::initMap();

std::map<AgString, AgString> DataTableUtils::initMap()
{
    std::map<AgString, AgString> es;
    es[AgString()] = Cres::get()->getString("default");

    es[AGG_GLOBAL.EDITOR_LIST] = Cres::get()->getString("dtEditorList");
    es[AGG_GLOBAL.EDITOR_DATE] = Cres::get()->getString("date");
    es[AGG_GLOBAL.EDITOR_TIME] = Cres::get()->getString("time");
    es[AGG_GLOBAL.EDITOR_BAR] = Cres::get()->getString("dtEditorBar");
    es[AGG_GLOBAL.EDITOR_BYTES] = Cres::get()->getString("dtEditorBytes");
    es[AGG_GLOBAL.EDITOR_PERIOD] = Cres::get()->getString("dtEditorPeriod");
    es[AGG_GLOBAL.EDITOR_EXPRESSION] = Cres::get()->getString("expression");
    es[AGG_GLOBAL.EDITOR_PASSWORD] = Cres::get()->getString("password");
    es[AGG_GLOBAL.EDITOR_TEXT] = Cres::get()->getString("dtEditorTextEditor");
    es[AGG_GLOBAL.EDITOR_HTML] = Cres::get()->getString("dtEditorHtml");
    es[AGG_GLOBAL.EDITOR_TEXT_AREA] = Cres::get()->getString("dtEditorTextArea");
    es[AGG_GLOBAL.EDITOR_EMBEDDED_TEXT_AREA] = Cres::get()->getString("dtEditorEmbeddedTextArea");
    es[AGG_GLOBAL.EDITOR_CONTEXT] = Cres::get()->getString("context");
    es[AGG_GLOBAL.EDITOR_CONTEXT_MASK] = Cres::get()->getString("conContextMask");
    es[AGG_GLOBAL.EDITOR_FONT] = Cres::get()->getString("font");
    es[AGG_GLOBAL.EDITOR_IP] = Cres::get()->getString("dtEditorIp");
    es[AGG_GLOBAL.EDITOR_BOX] = Cres::get()->getString("dtEditorBox");
    es[AGG_GLOBAL.EDITOR_IMAGE] = Cres::get()->getString("image");
    es[AGG_GLOBAL.EDITOR_SOUND] = Cres::get()->getString("sound");
    es[AGG_GLOBAL.EDITOR_HEX] = Cres::get()->getString("dtEditorHex");

    es[AGG_GLOBAL.EDITOR_ACTIVATOR] = Cres::get()->getString("activator");
    es[AGG_GLOBAL.EDITOR_CODE] = Cres::get()->getString("dtEditorCodeEditor");

    return es;
}


AgString DataTableUtils::transferDecode(AgString value)
{
    try
    {
        AgString s = TransferEncodingHelper::decode(value);

        return s;
    }
    catch (AggreGateException ex)
    {
        throw IllegalArgumentException("Error decoding string value \'" + value + "\'", ex.getDetails());
    }
}

AgString DataTableUtils::transferEncode(AgString value)
{
    return TransferEncodingHelper::encode(value);
}

void DataTableUtils::inlineData(DataTablePtr table, ContextManager* cm, CallerControllerPtr cc)
{
    if (table.get() == NULL)
    {
        return;
    }

    std::vector<FieldFormat*> &fields = table->getFormat()->getFields();
    std::vector<DataRecordPtr> &records = table->getRecords();

    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if ((*ff)->getType() == AGG_GLOBAL.DATA_FIELD)
        {
            for (std::vector<DataRecordPtr>::iterator rec = records.begin(); rec != records.end(); ++rec)
            {
                DataPtr data = (*rec)->getData((*ff)->getName());
                if (data.get() != NULL)
                {
                    data->fetchData(cm, cc);
                    data->setId(0);
                }
            }
        }

        if ((*ff)->getType() == AGG_GLOBAL.DATATABLE_FIELD)
        {
            for (std::vector<DataRecordPtr>::iterator rec = records.begin(); rec != records.end(); ++rec)
            {
                DataTablePtr dt = (*rec)->getDataTable((*ff)->getName());
                inlineData(dt, cm, cc);
            }
        }
    }
}

std::map<AgString, AgString> &DataTableUtils::getEditorSelectionValues()
{
    return EDITOR_SELECTION_VALUES;
}

DataTablePtr DataTableUtils::wrapToTable(const std::vector<AgObjectPtr>& values)
{
    std::map<AgString, AgObjectPtr> tableSource;
    for (unsigned int i = 0; i < values.size(); i++)
    {
        tableSource[AgString::fromInt(i)] = values[i];
    }
    return DataTableUtils::wrapToTable(tableSource);
}

DataTablePtr DataTableUtils::wrapToTable(std::map<AgString, AgObjectPtr> &values)
{
    TableFormatPtr rf = TableFormatPtr(new TableFormat());

    for (std::map<AgString, AgObjectPtr>::iterator field = values.begin(); field != values.end(); ++field)
    {
        AgObjectPtr value = field->second;
        rf->addField(DataTableConversion::createFieldFormat(field->first, value));
    }

    DataRecordPtr result = DataRecordPtr(new DataRecord(rf));

    for (std::map<AgString, AgObjectPtr>::iterator field = values.begin(); field != values.end(); ++field)
    {
         result->addValue(field->second);
    }

    return result->wrap();
}

std::list<AgString> DataTableUtils::findDifferingFields(DataTablePtr first, DataTablePtr second)
{
    UNUSED(first);
    UNUSED(second);
    //not used
    assert(0);
    return std::list<AgString>();
}

DataTablePtr DataTableUtils::makeSubtable(DataTablePtr table, std::list<AgString> fields)
{
    TableFormatPtr rf = TableFormatPtr(new TableFormat(table->getFormat()->getMinRecords(), table->getFormat()->getMaxRecords()));

    for (std::list<AgString>::iterator field = fields.begin(); field != fields.end(); ++field)
    {
        FieldFormat* ff = table->getFormat(*field);
        if (ff != NULL)
        {
            rf->addField(ff->clone());
        }
    }

    DataTablePtr result = DataTablePtr(new DataTable(rf));

    DataTableReplication::copyWithoutKeyFields(*table, result, true, true, true, true, true, std::list<AgString>());

    return result;
}

EvaluatorPtr DataTableUtils::createEvaluator(DataTablePtr dataTable, ContextManager* contextManager, ContextPtr context)
{
    UNUSED(dataTable);
    UNUSED(contextManager);
    UNUSED(context);
    //not used
    assert(0);
    return EvaluatorPtr();
}

AgString DataTableUtils::fieldValueToString(FieldFormat* ff, AgObjectPtr value)
{
    UNUSED(ff);
    UNUSED(value);
    //not used
    assert(0);
    return AgString();
}

AgString DataTableUtils::createRecordKeyString(DataRecordPtr record, int rowNumber, AgString keyField)
{
    UNUSED(record);
    UNUSED(rowNumber);
    UNUSED(keyField);
    //not used
    assert(0);
    return AgString();
}

DataTablePtr DataTableUtils::processBindings(DataTablePtr table, EvaluatorPtr evaluator)
{
    return processBindings(table, evaluator, ErrorCollectorPtr(), false);
}

DataTablePtr DataTableUtils::processBindings(DataTablePtr table, EvaluatorPtr evaluator, ErrorCollectorPtr errorCollector)
{
    return processBindings(table, evaluator, errorCollector, false);
}

DataTablePtr DataTableUtils::processBindings(DataTablePtr table, EvaluatorPtr evaluator, ErrorCollectorPtr errorCollector, bool split)
{
    if (table.get() == NULL)
    {
        return table;
    }

    if (table->getFormat()->getBindings().size() == 0)
    {
        return table;
    }

    DataTablePtr result;
    if (split)
    {
        result = DataTablePtr(table->clone());
        result->splitFormat();
    }
    else
    {
        result = table;
    }

    evaluator->getDefaultResolver()->setDefaultTable(result);

    //todo DefaultBindingProcessorPtr
    assert(0);
    DefaultBindingProcessorPtr processor = DefaultBindingProcessorPtr(new DefaultBindingProcessor(DataTableBindingProviderPtr(new DataTableBindingProvider(result, errorCollector)), evaluator));

    processor->start();

    return result;
}

FieldFormat* DataTableUtils::createTableField(const AgString &name, TableFormatPtr format)
{
    FieldFormat* ff = FieldFormat::create(name, AGG_GLOBAL.DATATABLE_FIELD);
    ff->setDefault(DataTablePtr(new DataTable(format, true)));
    return ff;
}

