#ifndef DataTableH
#define DataTableH

#include <list>
#include <vector>
#include "util/Pointers.h"
#include "util/Cloneable.h"
#include "util/AgObject.h"
#include "util/simpleobject/AgString.h"
#include "util/simpleobject/AgDate.h"
#include <boost/enable_shared_from_this.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

class DataTable: public Cloneable, public Comparable, public AgObject, public boost::enable_shared_from_this<DataTable>
{

private:
    std::vector<DataRecordPtr> records;

    void init();
    void init(const AgString &data, ClassicEncodingSettingsPtr settings, bool validate);
    static TableFormatPtr initDEFAULT_FORMAT();

protected:
    int64_t  id;
    TableFormatPtr format;
    AgString invalidationMessage;

    AgDatePtr timestamp;
    int quality;

    static const char ELEMENT_FORMAT    = 'F';
    static const char ELEMENT_FORMAT_ID = 'D';
    static const char ELEMENT_RECORD = 'R';
    static const char ELEMENT_INVALIDATOR = 'I';
    static const char ELEMENT_TIMESTAMP = 'T';
    static const char ELEMENT_QUALITY = 'Q';
    static const char ELEMENT_FIELD_NAME = 'N';


    EvaluatorPtr namingEvaluator;

    void addRecordImpl(boost::shared_ptr<int> index, DataRecordPtr record);
    void removeRecordImpl(int index);
    AgString toDefaultString();
    ExpressionPtr getNamingExpression();
    EvaluatorPtr ensureEvaluator();
    void checkOrSetFormat(DataRecordPtr record);

public:
    static TableFormatPtr DEFAULT_FORMAT;

    DataTable();
    DataTable(TableFormatPtr format);
    DataTable(TableFormatPtr format, int emptyRecords);
    DataTable(TableFormatPtr format, bool createEmptyRecords);
    DataTable(DataRecordPtr record);
    DataTable(TableFormatPtr format, const AgString &dataString, ClassicEncodingSettingsPtr settings);
    DataTable(TableFormatPtr format, std::list<AgObjectPtr> firstRowData);
    DataTable(const AgString & data);
    DataTable(const AgString & data, bool validate);
    DataTable(const AgString & data, ClassicEncodingSettingsPtr settings, bool validate);

    int getRecordCount();
    int getFieldCount();
    TableFormatPtr getFormat();
    FieldFormat* getFormat(int field);
    FieldFormat* getFormat(const AgString & name);
    int64_t  getId();
    DataTable& setFormat(TableFormatPtr format);
    void setId(int64_t id);
    bool hasField(const AgString & field);
    void setInvalidationMessage(const AgString & invalidationMessage);

    DataTable& addRecord(DataRecordPtr record);
    DataRecordPtr addRecord(int cnt, ...);
    DataTable& addRecord(int index, DataRecordPtr record);
    DataRecordPtr addRecord();

	void validate();
    void validateRecord(DataRecordPtr record);
    DataTable& setRecord(int index, DataRecordPtr record);
    void swapRecords(int index1, int index2);
    std::vector<DataRecordPtr>&  getRecords();
    bool isInvalid();
    AgString getInvalidationMessage();
    AgDatePtr getTimestamp();
    void setTimestamp(AgDatePtr _timestamp);
    int getQuality();
    void setQuality(int _quality);
    DataRecordPtr getRecord(int number);
    DataRecordPtr getRecordById(const AgString &id);

    void removeRecord(int index);
    void removeRecords(DataRecordPtr rec);
    void reorderRecord(DataRecordPtr record, int index);
    virtual bool equals(AgObject* obj);
    AgString getEncodedData(ClassicEncodingSettingsPtr settings);
    AgString encode();
    AgString encode(bool useVisibleSeparators);
    AgString encode(ClassicEncodingSettingsPtr settings);
    virtual AgString toString();
    AgString getDescription();

    void fixRecords();
    AgString dataAsString();
    AgString dataAsString(bool showFieldNames, bool showHiddenFields);
    bool isOneCellTable();
    bool conform(TableFormatPtr rf);
    AgString conformMessage(TableFormatPtr rf);
    std::list<DataRecordPtr>  selectAll(DataTableQueryPtr query);
    boost::shared_ptr<int> findIndex(DataTableQueryPtr query);

    DataRecordPtr select(DataTableQueryPtr query);
    DataRecordPtr select(const AgString & field, AgObjectPtr value);
    boost::shared_ptr<int>  findIndex(const AgString & field, AgObjectPtr value);
    void sort(const AgString & field, bool ascending);
    void sort(DataTableSorterPtr sorter);

    DataRecordPtr rec();
    AgObjectPtr get();
    void splitFormat();
    void joinFormats();

    std::vector<DataRecordPtr>::iterator iteratorBegin();
    std::vector<DataRecordPtr>::iterator iteratorEnd();
    void removeIterator(std::vector<DataRecordPtr>::iterator it);

    virtual DataTable* clone();

    void append(DataTablePtr src);

    virtual int compareTo(Comparable *obj);
    virtual std::string getClass();
    virtual int hashCode();
};


#endif
