#include "datatable/TableFormat.h"

#include "datatable/encoding/ClassicEncodingSettings.h"
#include "datatable/FieldFormat.h"
#include "datatable/DataTable.h"
#include "datatable/validator/TableValidator.h"
#include "datatable/validator/RecordValidator.h"
#include "datatable/validator/TableKeyFieldsValidator.h"
#include "datatable/validator/TableExpressionValidator.h"
#include "datatable/validator/KeyFieldsValidator.h"
#include "util/StringUtils.h"
#include "util/simpleobject/AgString.h"
#include "util/simpleobject/AgBoolean.h"
#include "AggreGateException.h"
#include "binding/Binding.h"
#include "IllegalArgumentException.h"
#include "IllegalStateException.h"
#include "util/Util.h"
#include "expression/Reference.h"
#include "expression/Expression.h"

TableFormat::TableFormat()
{
    init();
}

TableFormat::~TableFormat()
{
    for (std::vector<FieldFormat*>::iterator it = fields.begin(); it != fields.end(); ++it)
    {
        delete *it;
    }
}

void TableFormat::init()
{
    minRecords = DEFAULT_MIN_RECORDS;
    maxRecords = DEFAULT_MAX_RECORDS;
    reorderable = false;
    unresizable = false;
    bindingsEditable = false;
    immutable = false;
    immutabilizer = NULL;
}

TableFormat::TableFormat(bool reorderable)
{
    init();
    setReorderable(reorderable);
}

void TableFormat::init(int minRecords, int maxRecords)
{
    init();
    setMinRecords(minRecords);
    setMaxRecords(maxRecords);
}

TableFormat::TableFormat(int minRecords, int maxRecords)
{
    init(minRecords, maxRecords);
}

TableFormat::TableFormat(FieldFormat* ff)
{
    init();
    addField(ff);
}

TableFormat::TableFormat(const AgString &format, ClassicEncodingSettingsPtr settings, bool validate)
{
    init();
    if (format.length() == 0)
    {
        return;
    }

    ElementListPtr els = StringUtils::elements(format, settings->isUseVisibleSeparators());

    for (std::vector<Element *>::iterator el = els->elements.begin(); el != els->elements.end(); ++el)
    {
        if ((*el)->getName().length() == 0)
        {
            int index = fields.size();
            FieldFormat* ff = FieldFormat::create((*el)->getValue(), settings, validate);
            fields.push_back(ff);
            getFieldLookup()[ff->getName()] = index;
            continue;
        }
        if ((*el)->getName() == ELEMENT_FLAGS())
        {
            AgString flags = (*el)->getValue();
            setReorderable(flags.find(REORDERABLE_FLAG) != AgString::npos ? true : false);
            setUnresizable(flags.find(UNRESIZEBLE_FLAG) != AgString::npos ? true : false);
            setBindingsEditable(flags.find(BINDINGS_EDITABLE_FLAG) != AgString::npos ? true : false);
            continue;
        }
        if ((*el)->getName() == ELEMENT_MIN_RECORDS())
        {
            minRecords = (*el)->getValue().toInt();
            continue;
        }
        if ((*el)->getName() == ELEMENT_MAX_RECORDS())
        {
            maxRecords = (*el)->getValue().toInt();
            continue;
        }
        if ((*el)->getName() == ELEMENT_TABLE_VALIDATORS())
        {
            createTableValidators((*el)->getValue(), settings);
            continue;
        }
        if ((*el)->getName() == ELEMENT_RECORD_VALIDATORS())
        {
            createRecordValidators((*el)->getValue(), settings);
            continue;
        }
        if ((*el)->getName() == ELEMENT_BINDINGS())
        {
            createBindings((*el)->getValue(), settings);
            continue;
        }
        if ((*el)->getName() == ELEMENT_NAMING())
        {
            createNaming((*el)->getValue(), settings);
            continue;
        }
    }
}

TableFormat::TableFormat(int minRecords, int maxRecords, const AgString& fieldFormat): minRecords(DEFAULT_MIN_RECORDS), maxRecords(DEFAULT_MAX_RECORDS), reorderable(false),
    unresizable(false), bindingsEditable(false), immutable(false), immutabilizer(NULL)
{
    init(minRecords, maxRecords);
    addField(fieldFormat);
}

TableFormat::TableFormat(int minRecords, int maxRecords, FieldFormat* fieldFormat): minRecords(DEFAULT_MIN_RECORDS), maxRecords(DEFAULT_MAX_RECORDS), reorderable(false),
    unresizable(false), bindingsEditable(false), immutable(false), immutabilizer(NULL)
{
    init(minRecords, maxRecords);
    addField(fieldFormat);
}

void TableFormat::encAppend(AgString &buffer, const AgString &name, const AgString &value, ClassicEncodingSettingsPtr settings)
{
    if (value.length() > 0)
    {
        buffer += (Element(name, value).encode(settings->isUseVisibleSeparators()));
    }
}

void TableFormat::createTableValidators(const AgString &source, ClassicEncodingSettingsPtr settings)
{
    if (source.length() == 0)
    {
        return;
    }

    ElementListPtr validatorsData = StringUtils::elements(source, settings->isUseVisibleSeparators());

    for (std::vector<Element *>::iterator el = validatorsData->elements.begin(); el != validatorsData->elements.end(); ++el)
    {
        AgChar validatorType = (*el)->getName()[0];
        AgString validatorParams = (*el)->getValue();

        switch (validatorType)
        {
            case TABLE_VALIDATOR_KEY_FIELDS:
                addTableValidator(TableValidatorPtr(new TableKeyFieldsValidator(validatorParams)));
                break;

            case TABLE_VALIDATOR_EXPRESSION:
                addTableValidator(TableValidatorPtr(new TableExpressionValidator(validatorParams)));
                break;
        }
    }
}

void TableFormat::createRecordValidators(const AgString &source, ClassicEncodingSettingsPtr settings)
{
    if (source.length() == 0)
    {
        return;
    }

    ElementListPtr validatorsData = StringUtils::elements(source, settings->isUseVisibleSeparators());

    for (std::vector<Element *>::iterator el = validatorsData->elements.begin(); el != validatorsData->elements.end(); ++el)
    {
        AgChar validatorType = (*el)->getName()[0];
        AgString validatorParams = (*el)->getValue();

        switch (validatorType)
        {
            case RECORD_VALIDATOR_KEY_FIELDS:
                addRecordValidator(RecordValidatorPtr(new KeyFieldsValidator(validatorParams)));
                break;
        }
    }
}

void TableFormat::createBindings(const AgString &source, ClassicEncodingSettingsPtr settings)
{
    if (source.length() == 0)
    {
        return;
    }

    ElementListPtr bindingsData = StringUtils::elements(source, settings->isUseVisibleSeparators());

    for (std::vector<Element *>::iterator el = bindingsData->elements.begin(); el != bindingsData->elements.end(); ++el)
    {
        bindings.push_back(BindingPtr(new Binding(ReferencePtr(new Reference((*el)->getName())),ExpressionPtr(new Expression((*el)->getValue())))));
    }
}

void TableFormat::createNaming(const AgString &source, ClassicEncodingSettingsPtr settings)
{
    UNUSED(settings);

    if (source.length() == 0)
    {
        return;
    }

    namingExpression = ExpressionPtr(new Expression(source));
}

AgString TableFormat::getEncodedFlags()
{
    AgString buf;
    if (isReorderable())
    {
        buf += REORDERABLE_FLAG;
    }
    if (isUnresizable())
    {
        buf += UNRESIZEBLE_FLAG;
    }
    if (isBindingsEditable())
    {
        buf += BINDINGS_EDITABLE_FLAG;
    }
    return buf;
}

AgString TableFormat::getEncodedTableValidators(ClassicEncodingSettingsPtr settings)
{
    AgString enc;

    for (std::list<TableValidatorPtr>::iterator tv = tableValidators.begin(); tv != tableValidators.end(); ++tv)
    {
        AgString str;
        str += (*tv)->getType();
        enc += (Element( str, (*tv)->encode()).encode(settings->isUseVisibleSeparators()));
    }

    return enc;
}

AgString TableFormat::getEncodedRecordValidators(ClassicEncodingSettingsPtr settings)
{
    AgString enc;

    for (std::list<RecordValidatorPtr>::iterator rv = recordValidators.begin(); rv != recordValidators.end(); ++rv)
    {
        AgString str;
        str += (*rv)->getType();
        enc += (Element(str, (*rv)->encode()).encode(settings->isUseVisibleSeparators()));
    }

    return enc;
}

AgString TableFormat::getEncodedBindings(ClassicEncodingSettingsPtr settings)
{
    AgString enc;

    for (std::list<BindingPtr>::iterator bin = bindings.begin(); bin != bindings.end(); ++bin)
    {
        enc += (Element((*bin)->getReference()->getImage(), (*bin)->getExpression()->getText()).encode(settings->isUseVisibleSeparators()));
    }

    return enc;
}

TableFormatPtr TableFormat::getEMPTY_FORMAT()
{
    return TableFormatPtr(new TableFormat(0, 0));
}

TableFormat& TableFormat::addFields(std::list<FieldFormat*> &fieldFormats)
{
    for (std::list<FieldFormat*>::const_iterator each = fieldFormats.begin(); each != fieldFormats.end(); ++each)
    {
        this->addField(*each);
    }
    return *this;
}

TableFormat& TableFormat::addField(FieldFormat* ff)
{
    return addField(ff, fields.size());
}

TableFormat& TableFormat::addField(const AgString &encodedFormat)
{
    return addField(FieldFormat::create(encodedFormat));
}

void TableFormat::addField(char type, const AgString &name)
{
    addField(type, name, fields.size());
}

TableFormat& TableFormat::addField(char type, const AgString &name, const AgString &description)
{
    addField(FieldFormat::create(name, type, description));
    return *this;
}

TableFormat& TableFormat::addField(char type, const AgString &name, const AgString &description, AgObjectPtr defaultValue)
{
    addField(FieldFormat::create(name, type, description, defaultValue));
    return *this;
}

TableFormat& TableFormat::addField(char type, const AgString &name, const AgString &description, AgObjectPtr defaultValue, const AgString &group)
{
    addField(FieldFormat::create(name, type, description, defaultValue, group));
    return *this;
}

TableFormat& TableFormat::addField(char type, const AgString &name, const AgString &description, AgObjectPtr defaultValue, bool nullable)
{
    addField(FieldFormat::create(name, type, description, defaultValue, nullable));
    return *this;
}

TableFormat& TableFormat::addField(char type, const AgString &name, const AgString &description, AgObjectPtr defaultValue, bool nullable, const AgString &group)
{
    addField(FieldFormat::create(name, type, description, defaultValue, nullable, group));
    return *this;
}

TableFormat& TableFormat::addField(FieldFormat* ff, int index)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    FieldFormat* existing = getField(ff->getName());

    if (existing != NULL)
    {
        if (!ff->extend(existing))
        {
            throw IllegalArgumentException("Field \'" + ff->getName() + "\' already exist in format");
        }
        else
        {
            return *this;
        }
    }

    for (unsigned int i = index; i < fields.size(); i++)
    {
        AgString fn = fields[i]->getName();

        if (getFieldLookup().find(fn) == getFieldLookup().end())
        {
            throw IllegalStateException("Null lookup index for field " + AgString::fromInt(i) + " (" + fn + ")");
        }

        getFieldLookup()[fn] = getFieldLookup()[fn] + 1;
    }

    fields.insert(fields.begin() + index, ff);

    getFieldLookup()[ff->getName()] = index;
    return *this;
}

TableFormat& TableFormat::addField(char type, const AgString &name, int index)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    return addField(FieldFormat::create(name, type), index);
}

TableFormat& TableFormat::removeField(const AgString &name)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    std::map<AgString, int>::iterator it = getFieldLookup().find(name);

    if (it != getFieldLookup().end())
    {
        unsigned int index = getFieldLookup()[name];
        getFieldLookup().erase(it);

        delete *(fields.begin() + index);
        fields.erase(fields.begin() + index);
        for (unsigned int i = index; i < fields.size(); i++)
        {
            AgString fn = fields[i]->getName();
            getFieldLookup()[fn] = getFieldLookup()[fn] - 1;
        }
    }

    return *this;
}

TableFormat& TableFormat::renameField(const AgString &oldName, const AgString &newName)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    FieldFormat* ff = getField(oldName);

    if (ff == NULL)
    {
        return *this;
    }

    ff->setName(newName);

    std::map<AgString, int>::iterator it = getFieldLookup().find(oldName);
    if (it != getFieldLookup().end())
    {
        int index = getFieldLookup()[oldName];
        getFieldLookup().erase(it);
        getFieldLookup()[newName] = index;
    }

    return *this;
}

char TableFormat::getFieldType(int index)
{
    return fields[index]->getType();
}

AgString TableFormat::getFieldName(int index)
{
    return fields[index]->getName();
}

int TableFormat::getFieldIndex(const AgString &name)
{
    std::map<AgString, int>::iterator it = getFieldLookup().find(name);
    if (it != getFieldLookup().end())
    {
        int index = getFieldLookup()[name];
        return index;
    }
    else
    {
        return -1;
    }
}

int TableFormat::getFieldCount()
{
    return fields.size();
}


TableFormat *TableFormat::clone()
{
    TableFormat *tf = new TableFormat();

    tf->minRecords = minRecords;
    tf->maxRecords = maxRecords;

    tf->reorderable = reorderable;
    tf->unresizable = unresizable;
    tf->bindingsEditable = bindingsEditable;

    for (std::vector<FieldFormat *>::iterator it = fields.begin(); it != fields.end(); ++it)
    {
        FieldFormat* ff = (*it)->clone();
        tf->fields.push_back(ff);
    }

    tf->fieldLookup = fieldLookup;

    for (std::list<RecordValidatorPtr>::iterator it = recordValidators.begin(); it != recordValidators.end(); ++it)
    {
        RecordValidatorPtr rv = RecordValidatorPtr(dynamic_cast<RecordValidator *>((*it)->clone()));
        tf->recordValidators.push_back(rv);
    }

    for (std::list<TableValidatorPtr>::iterator it = tableValidators.begin(); it != tableValidators.end(); ++it)
    {
        TableValidatorPtr tv = TableValidatorPtr(dynamic_cast<TableValidator *>((*it)->clone()));
        tf->tableValidators.push_back(tv);
    }

    for (std::list<BindingPtr>::iterator it = bindings.begin(); it != bindings.end(); ++it)
    {
        BindingPtr tv = BindingPtr(dynamic_cast<Binding *>((*it)->clone()));
        tf->bindings.push_back(tv);
    }

    tf->immutable = false;

    return tf;
}

int TableFormat::compareTo(Comparable* /*obj*/)
{
    assert(0);
    return 0;
}

std::string TableFormat::getClass()
{
    return typeid(TableFormat).name();
}

std::vector<FieldFormat*> &TableFormat::getFields()
{
    return fields;
}

std::list<RecordValidatorPtr> TableFormat::getRecordValidators()
{
    return recordValidators;
}

std::list<TableValidatorPtr> TableFormat::getTableValidators()
{
    return tableValidators;
}

int TableFormat::getMaxRecords()
{
    return maxRecords;
}

int TableFormat::getMinRecords()
{
    return minRecords;
}

bool TableFormat::isReorderable()
{
    return reorderable;
}

bool TableFormat::isUnresizable()
{
    return unresizable;
}

void TableFormat::setUnresizable(bool unresizable)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->unresizable = unresizable;
}

bool TableFormat::isBindingsEditable()
{
    return bindingsEditable;
}

void TableFormat::setBindingsEditable(bool bindingsEditable)
{
    // Bindings Editable flag only affects visual editing of the table, so there's no need to condider immutability here
    this->bindingsEditable = bindingsEditable;
}

std::list<BindingPtr> &TableFormat::getBindings()
{
    return bindings;
}

void TableFormat::addBinding(BindingPtr binding)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    bindings.push_back(binding);
}

void TableFormat::addBinding(ReferencePtr target, ExpressionPtr expression)
{
    addBinding(BindingPtr(new Binding(target, expression)));
}

void TableFormat::addBinding(const AgString &target, const AgString &expression)
{
    addBinding(BindingPtr(new Binding(ReferencePtr(new Reference(target)), ExpressionPtr(new Expression(expression)))));
}

void TableFormat::removeBinding(BindingPtr binding)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    std::list<BindingPtr>::iterator it = find(bindings.begin(), bindings.end(), binding);
    bindings.erase(it);
}

void TableFormat::setBindings(std::list<BindingPtr> in_bindings)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    bindings = in_bindings;
}

ExpressionPtr TableFormat::getNamingExpression()
{
    return namingExpression;
}

AgString TableFormat::encode(bool useVisibleSeparators)
{
    return encode(ClassicEncodingSettingsPtr(new ClassicEncodingSettings(useVisibleSeparators)));
}

AgString TableFormat::encode(ClassicEncodingSettingsPtr settings)
{
    AgString formatString;

    for (unsigned int i = 0; i < fields.size(); i++)
    {
        formatString += (Element(AgString(), getField(i)->encode(settings)).encode(settings->isUseVisibleSeparators()));
    }

    if (minRecords != DEFAULT_MIN_RECORDS)
    {
        formatString += (Element(ELEMENT_MIN_RECORDS(), AgString::fromInt(minRecords)).encode(settings->isUseVisibleSeparators()));
    }

    if (maxRecords != DEFAULT_MAX_RECORDS)
    {
        formatString += (Element(ELEMENT_MAX_RECORDS(), AgString::fromInt(maxRecords)).encode(settings->isUseVisibleSeparators()));
    }

    if (tableValidators.size() > 0)
    {
        formatString += (Element(ELEMENT_TABLE_VALIDATORS(), getEncodedTableValidators(settings)).encode(settings->isUseVisibleSeparators()));
    }

    if (recordValidators.size() > 0)
    {
        formatString += (Element(ELEMENT_RECORD_VALIDATORS(), getEncodedRecordValidators(settings)).encode(settings->isUseVisibleSeparators()));
    }

    if (bindings.size() > 0)
    {
        formatString += (Element(ELEMENT_BINDINGS(), getEncodedBindings(settings)).encode(settings->isUseVisibleSeparators()));
    }

    if (namingExpression.get() != NULL)
    {
        formatString += (Element(ELEMENT_NAMING(), namingExpression.get() == NULL ? "" : namingExpression->getText()).encode(settings->isUseVisibleSeparators()));
    }

    encAppend(formatString, ELEMENT_FLAGS(), getEncodedFlags(), settings);

    return formatString;
}

std::map<AgString, int> &TableFormat::getFieldLookup()
{
    if (fieldLookup.size() == 0)
    {
        for (unsigned int i = 0; i < fields.size(); i++)
        {
            FieldFormat* field = fields[i];
            fieldLookup[field->getName()] = i;
        }
    }
    return fieldLookup;
}

AgString TableFormat::toString()
{
    return encode(ClassicEncodingSettingsPtr(new ClassicEncodingSettings(true)));
}

FieldFormat* TableFormat::getField(int index)
{
    return fields[index];
}

FieldFormat* TableFormat::getField(const AgString &fieldName)
{
    int index = getFieldIndex(fieldName);
    if (index != -1)
    {
        return getField(index);
    }
    else
    {
        return NULL;
    }
}

bool TableFormat::hasField(const AgString &name)
{
    return getFieldIndex(name) != -1;
}

bool TableFormat::hasFields(char type)
{
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if ((*ff)->getType() == type)
        {
            return true;
        }
    }

    return false;
}

bool TableFormat::hasReadOnlyFields()
{
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if ((*ff)->isReadonly())
        {
            return true;
        }
    }

    return false;
}

std::list<AgString> TableFormat::getKeyFields()
{
    std::list<AgString> list;
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if ((*ff)->isKeyField())
        {
            list.push_back((*ff)->getName());
        }
    }
    return list;
}

bool TableFormat::extend(TableFormatPtr other)
{
    return extendMessage(other).length() == 0;
}

AgString TableFormat::extendMessage(TableFormatPtr other)
{
    if (this == other.get())
    {
        return AgString();
    }

    if (equals(other.get()))
    {
        return AgString();
    }

    if (!isReorderable() && other->isReorderable())
    {
        return "Different reorderable flags: need " + AgBoolean(isReorderable()).toString() + ", found " + AgBoolean(other->isReorderable()).toString();
    }

    if (!isUnresizable() && other->isUnresizable())
    {
        return "Different unresizable flags: need " + AgBoolean(isUnresizable()).toString() + ", found " + AgBoolean(other->isUnresizable()).toString();
    }

    ExpressionPtr ne = getNamingExpression();
    ExpressionPtr one = other->getNamingExpression();

    if (!Util::equals(ne, one))
    {
        return "Different naming expressions: need " + (getNamingExpression().get() ? getNamingExpression()->toString() : "null") + ", found "
                                                + (other->getNamingExpression().get() ? other->getNamingExpression()->toString() : "null");
    }

    for (std::list<BindingPtr>::iterator otherBinding = other->getBindings().begin(); otherBinding != other->getBindings().end(); ++otherBinding)
    {
        std::list<BindingPtr>::iterator it = find(getBindings().begin(), getBindings().end(), *otherBinding);
        if (it == getBindings().end())
        {
            //todo getBindings() to string
            return "Different bindings";//: need " + getBindings() + ", found " + other.getBindings();
        }
    }

    for (std::vector<FieldFormat*>::iterator otherFormat = other->fields.begin(); otherFormat != other->fields.end(); ++otherFormat)
    {
        FieldFormat* ownFormat = getField((*otherFormat)->getName());

        if (ownFormat == NULL)
        {
            if ((*otherFormat)->isOptional())
            {
                continue;
            }
            else
            {
                return "Required field doesn't exist: " + (*otherFormat)->getName();
            }
        }

        AgString fieldExtendMessage = ownFormat->extendMessage(*otherFormat);
        if (fieldExtendMessage.length() != 0)
        {
            return "Incorrect format of field '" + (*otherFormat)->getName() + "': " + fieldExtendMessage;
        }
    }

    return AgString();
}

void TableFormat::addTableValidator(TableValidatorPtr tv)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    tableValidators.push_back(tv);
}

void TableFormat::addRecordValidator(RecordValidatorPtr rv)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    recordValidators.push_back(rv);
}

bool TableFormat::isReplicated()
{
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if (!(*ff)->isNotReplicated())
        {
            return true;
        }
    }
    return false;
}

bool TableFormat::isReadonly()
{
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if (!(*ff)->isReadonly())
        {
            return false;
        }
    }
    return true;
}

bool TableFormat::isGrouped()
{
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if ((*ff)->getGroup().length() != 0)
        {
            return true;
        }
    }
    return false;
}

bool TableFormat::isAdvanced()
{
    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        if ((*ff)->isAdvanced())
        {
            return true;
        }
    }
    return false;
}

bool TableFormat::isSingleRecord()
{
    return minRecords == 1 && maxRecords == 1;
}

bool TableFormat::isSingleField()
{
    return getFieldCount() == 1;
}

bool TableFormat::isSingleCell()
{
    return isSingleRecord() && isSingleField();
}

bool TableFormat::isEmpty()
{
    return minRecords == 0 && maxRecords == 0 && getFieldCount() == 0;
}

bool TableFormat::isImmutable()
{
    return immutable;
}

TableFormat& TableFormat::resetAllowedRecords()
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->minRecords = DEFAULT_MIN_RECORDS;
    this->maxRecords = DEFAULT_MAX_RECORDS;

    return *this;
}

TableFormat& TableFormat::setMaxRecords(int maxRecords)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->maxRecords = maxRecords;

    return *this;
}

TableFormat& TableFormat::setMinRecords(int minRecords)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->minRecords = minRecords;

    return *this;
}

TableFormat& TableFormat::setReorderable(bool reorderable)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->reorderable = reorderable;

    return *this;
}

TableFormat& TableFormat::setNamingExpression(ExpressionPtr namingExpression)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->namingExpression = namingExpression;

    return *this;
}

TableFormat& TableFormat::setNamingExpression(const AgString &namingExpression)
{
    setNamingExpression(ExpressionPtr(new Expression(namingExpression)));
    return *this;
}

int TableFormat::getFieldsHashCode()
{
    int res = 0;
    for (std::vector<FieldFormat*>::iterator it = fields.begin(); it != fields.end(); ++it)
    {
        res += (*it)->hashCode();
    }
    return res;
}

int TableFormat::hashCode()
{
//    const int prime = 31;
    int result = 1;
    assert(0);
    /*result = prime * result + maxRecords;
    result = prime * result + minRecords;
    result = prime * result + getFieldsHashCode();
    result = prime * result + ((namingExpression == null) ? 0 : namingExpression.hashCode());
    result = prime * result + ((recordValidators == null) ? 0 : recordValidators.hashCode());
    result = prime * result + ((tableValidators == null) ? 0 : tableValidators.hashCode());
    result = prime * result + (reorderable ? 1231 : 1237);
    result = prime * result + (unresizable ? 1231 : 1237);
    result = prime * result + ((bindings == null) ? 0 : bindings.hashCode());

    if (result < 0)
    {
        result = INT_MAX + result;
    }*/
    return result;
}

void TableFormat::makeImmutable(DataTable *immutabilizer)
{
    if (immutable)
    {
        return;
    }

    immutable = true;

    this->immutabilizer = immutabilizer;

    for (std::vector<FieldFormat*>::iterator ff = fields.begin(); ff != fields.end(); ++ff)
    {
        (*ff)->makeImmutable();
    }
}

void TableFormat::fixRecords(DataTable* table)
{
    if (immutable && immutabilizer != table)
    {
        throw IllegalStateException("Format was not made immutable by this table");
    }

    minRecords = table->getRecordCount();
    maxRecords = table->getRecordCount();
}

bool TableFormat::equals(AgObject* obj)
{
    if (this == obj)
    {
        return true;
    }
    if (obj == NULL)
    {
        return false;
    }
    if (getClass() != obj->getClass())
    {
        return false;
    }

    TableFormat *other = dynamic_cast<TableFormat *> (obj);
    assert(other);
    if (maxRecords != other->maxRecords)
    {
        return false;
    }
    if (minRecords != other->minRecords)
    {
        return false;
    }
    if (fields.size() == 0)
    {
        if (other->fields.size() != 0)
        {
            return false;
        }
    }
    else
    {
        if (fields.size() != other->fields.size())
        {
            return false;
        }

        std::vector<FieldFormat*>::iterator it1 = fields.begin();
        std::vector<FieldFormat*>::iterator it2 = other->fields.begin();
        while (it1 != fields.end())
        {
            if (!(*it1)->equals(*it2))
            {
                return false;
            }

            ++it1;
            ++it2;
        }
    }

    if (namingExpression.get() == NULL)
    {
        if (other->namingExpression.get() != NULL)
        {
            return false;
        }
    }
    else if (!namingExpression->equals(other->namingExpression.get()))
    {
        return false;
    }
    if (recordValidators.size() == 0)
    {
        if (other->recordValidators.size() != 0)
        {
            return false;
        }
    }
    else if (recordValidators != other->recordValidators)
    {
        return false;
    }
    if (tableValidators.size() == 0)
    {
        if (other->tableValidators.size() != 0)
        {
            return false;
        }
    }
    else if (tableValidators != other->tableValidators)
    {
        return false;
    }
    if (reorderable != other->reorderable)
    {
        return false;
    }
    if (unresizable != other->unresizable)
    {
        return false;
    }
    if (bindings.size() == 0)
    {
        if (other->bindings.size() != 0)
        {
            return false;
        }
    }
    else if (bindings != other->bindings)
    {
        return false;
    }
    return true;
}
