#pragma once
 #define BOOST_THREAD_USE_LIB
#include <list>
#include "util/simpleobject/AgString.h"
#include "datatable/converter/FormatConverter.h"
#include "util/Pointers.h"
#include <boost/thread/thread.hpp>

class DataTable;

class DataTableConversion
{
private:
    std::vector< FormatConverterPtr >  FORMAT_CONVERTERS;
    boost::mutex FORMAT_CONVERTERS_LOCK;
    DataTableConversion();

public:
    static DataTableConversion &instance()
    {
        static DataTableConversion dataTableConversion;
        return dataTableConversion;
    }

    DataTablePtr beanToTable(AgObject* bean, TableFormatPtr format, bool setReadOnlyFields = true, bool ignoreErrors = false);
    DataTablePtr beansToTable(AgObjectPtr beans, TableFormatPtr format, bool setReadOnlyFields = true);

    AgObjectPtr beanFromTable(DataTablePtr table, const std::string& beanClass, TableFormatPtr format, bool setReadOnlyFields = true);
    std::vector<AgObjectPtr> beansFromTable(DataTablePtr table, const std::string& beanClass, TableFormatPtr format, bool setReadOnlyFields = true);

    AgObjectPtr beanFromRecord(DataRecordPtr rec, const std::string& beanClass, TableFormatPtr format, bool setReadOnlyFields);

    void populateBeanFromRecord(AgObject* bean, DataRecordPtr rec, TableFormatPtr format, bool setReadOnlyFields);
    void populateBeanFromRecord(AgObjectPtr bean, DataRecordPtr rec, TableFormatPtr format, bool setReadOnlyFields, std::list<AgString> fieldsToSkip);

    DataRecordPtr beanToRecord(AgObject* bean, TableFormatPtr format, bool setReadOnlyFields, bool ignoreErrors);
    DataRecordPtr beanToRecord(AgObjectPtr bean, TableFormatPtr format, bool setReadOnlyFields, bool ignoreErrors, const std::list<AgString> &fieldsToSkip);

    AgObjectPtr convertValueToField(FieldFormat* ff, AgObjectPtr value, const std::string& requiredClass);
    AgObjectPtr convertValueFromField(AgObjectPtr value);
    AgObjectPtr convertValueFromField(AgObjectPtr value, const std::string& requiredClass);
    AgObjectPtr convertValueToField(FieldFormat* ff, AgObjectPtr value);

    void registerFormatConverter(FormatConverterPtr converter);
    FormatConverterPtr getFormatConverter(const std::string& valueClass);

    static FieldFormat* createFieldFormat(const AgString &name, AgObjectPtr value);
    static FieldFormat* createFieldFormat(const AgString &name, const std::string& valueClassName);

    FieldFormat* createTableField(const AgString & name, TableFormatPtr format);
    FieldFormat* createTableField(const AgString & name, const AgString &description, TableFormatPtr format);

    AgObjectPtr createAggreGateBean(AgObjectPtr value, const std::string& requiredClass);

private:
    TableFormatPtr getFormatFromDefaultValue(FieldFormat* ff);
    AgObjectPtr createArray(FieldFormat* ff, AgObjectPtr value);
    std::vector<AgObjectPtr> createList(AgObjectPtr bean, DataRecordPtr rec, bool setReadOnlyFields, FieldFormat* ff);
    DataTablePtr convertList(AgObjectPtr bean, AgObjectPtr value, bool setReadOnlyFields, FieldFormat* ff);
    DataTablePtr convertArray(FieldFormat* ff, AgObjectPtr value);
};
