#pragma once

#include "data/Data.h"
#include "datatable/DataTable.h"
#include "datatable/TableFormat.h"
#include "datatable/QueryCondition.h"

#include "util/Cloneable.h"
#include "util/simpleobject/AgDate.h"
#include "util/Pointers.h"

#include <string>
#include <map>
#include <boost/enable_shared_from_this.hpp>

class DataRecord : public Cloneable, public AgObject, public boost::enable_shared_from_this<DataRecord>
{   
private:
    static AgString ELEMENT_ID() { return "I"; }
    std::map<AgString, AgObjectPtr> data;
    TableFormatPtr format;
    DataTable *table;
    AgString id;

    void setData(const AgString &dataString, ClassicEncodingSettingsPtr settings, bool validate, std::vector<AgString> fieldNamesInData);
    void checkNumberOfDataFieldsSet(AgObjectPtr value);
    int findIndex(const AgString &name);
    AgObjectPtr getValue(FieldFormat* ff);
    DataRecord &setValue(int index, AgObjectPtr value, bool validate);
    void init(TableFormatPtr tableFormat);

public:
	
    DataRecord();
    DataRecord(TableFormatPtr tableFormat);
    DataRecord(TableFormatPtr tableFormat, std::list<AgObjectPtr>& data);
    DataRecord(TableFormatPtr tableFormat, AgObjectPtr data);
    DataRecord(TableFormatPtr tableFormat, const AgString& dataString, ClassicEncodingSettingsPtr settings, bool validate, std::vector<AgString> fieldNamesInData);
    DataRecord(TableFormatPtr tableFormat, const AgString& dataString);

    int getFieldCount();
    TableFormatPtr getFormat();
    FieldFormat* getFormat(int index);
    FieldFormat* getFormat(const AgString& name);
    AgString getId();
    DataTable* getTable();
    AgString encode(bool useVisibleSeparators);
    AgString encode(ClassicEncodingSettingsPtr settings);

    DataRecord &addInt(int val);
    DataRecord &addString(const AgString& val);
    DataRecord &addBoolean(bool val);
    DataRecord &addLong(int64_t val);
    DataRecord &addFloat(float val);
    DataRecord &addDouble(double val);
    DataRecord &addDate(AgDate val);
    DataRecord &addDataTable(DataTablePtr val);
    DataRecord &addColor(AgColorPtr val);
    DataRecord &addData(DataPtr val);
    DataRecord &setValue(int index, AgObjectPtr value);
    DataRecord &setValue(const AgString &name, AgObjectPtr value);
    DataRecord &setValue(const AgString &name, AgObjectPtr value, bool validate);

    DataRecord &setValueSmart(int index, AgObjectPtr value);
    DataRecord &setValueSmart(const AgString& name, AgObjectPtr value);
    DataRecord &addValue(AgObjectPtr value);

    AgString getString(const AgString& name);
    AgString getString(int index);
    int getInt(const AgString& name);
    int getInt(int index);
    bool getBoolean(const AgString& name);
    bool getBoolean(int index);
    int64_t getLong(const AgString& name);
    int64_t getLong(int index);
    float getFloat(const AgString& name);
    float getFloat(int index);
    double getDouble(const AgString& name);
    double getDouble(int index);
    AgDate getDate(const AgString& name);
    AgDate getDate(int index);
    DataTablePtr getDataTable(const AgString& name);
    DataTablePtr getDataTable(int index);
    AgColor getColor(const AgString& name);
    AgColor getColor(int index);
    DataPtr getData(const AgString& name);
    DataPtr getData(int index);

    AgObjectPtr getValue(int index);
    AgObjectPtr getValue(const AgString& name);
    AgString getValueDescription(const AgString& name);
    AgString getValueAsString(const AgString& name);
    AgString getValueAsString(int index);
    DataRecord &setId(const AgString& id);
    void setFormat(TableFormatPtr format);

    bool hasField(const AgString& name);

    void cloneFormatFromTable();
    AgString dataAsString(bool showFieldNames, bool showHiddenFields);
    AgString valueAsString(const AgString& name);
    AgString toString();
    DataTablePtr wrap();
    virtual  DataRecord *clone();

    bool equals(AgObjectPtr obj);

    void setTable(DataTable *table);

    bool meetToCondition(QueryConditionPtr cond);
};
