#include "FieldFormat.h"
#include "util/simpleobject/AgInteger.h"
#include "util/simpleobject/AgString.h"
#include "util/simpleobject/AgBoolean.h"
#include "util/simpleobject/AgLong.h"
#include "util/simpleobject/AgFloat.h"
#include "util/simpleobject/AgDouble.h"
#include "util/simpleobject/AgColor.h"
#include "data/Data.h"
#include "IllegalArgumentException.h"
#include "IllegalStateException.h"
#include "ValidationException.h"
#include "datatable/DataTable.h"
#include "datatable/TableFormat.h"
#include "datatable/field/IntFieldFormat.h"
#include "datatable/field/StringFieldFormat.h"
#include "datatable/field/BooleanFieldFormat.h"
#include "datatable/field/LongFieldFormat.h"
#include "datatable/field/FloatFieldFormat.h"
#include "datatable/field/DoubleFieldFormat.h"
#include "datatable/field/DataFieldFormat.h"
#include "datatable/field/DataTableFieldFormat.h"
#include "datatable/field/DateFieldFormat.h"
#include "datatable/field/ColorFieldFormat.h"
#include "util/StringUtils.h"
#include "util/Util.h"
#include "util/CloneUtils.h"
#include "util/MessageFormat.h"
#include "datatable/encoding/ClassicEncodingSettings.h"
#include "context/ContextException.h"
#include "datatable/validator/LimitsValidator.h"
#include "datatable/validator/RegexValidator.h"
#include "datatable/validator/NonNullValidator.h"
#include "datatable/validator/IdValidator.h"
#include "Cres.h"
#include "GlobalVars.h"

FieldFormat* FieldFormat::create(const AgString &name, const AgString &valueClass)
{
    std::map<AgString, char>::iterator it = AGG_GLOBAL.CLASS_TO_TYPE.find(valueClass);
    if (it != AGG_GLOBAL.CLASS_TO_TYPE.end())
    {
        char type = it->second;
        return create(name, type);
    }
    else
    {
        throw IllegalArgumentException("Unknown field class: " + valueClass);
    }
}

FieldFormat* FieldFormat::create(const AgString &name, char type)
{
    if (type == AGG_GLOBAL.INTEGER_FIELD)
        return new IntFieldFormat(name);
    else if (type == AGG_GLOBAL.STRING_FIELD)
        return new StringFieldFormat(name);
    else if (type == AGG_GLOBAL.BOOLEAN_FIELD)
        return new BooleanFieldFormat(name);
    else if (type == AGG_GLOBAL.LONG_FIELD)
        return new LongFieldFormat(name);
    else if (type == AGG_GLOBAL.FLOAT_FIELD)
        return new FloatFieldFormat(name);
    else if (type == AGG_GLOBAL.DOUBLE_FIELD)
        return new DoubleFieldFormat(name);
    else if (type == AGG_GLOBAL.DATE_FIELD)
        return new DateFieldFormat(name);
    else if (type == AGG_GLOBAL.DATATABLE_FIELD)
        return new DataTableFieldFormat(name);
    else if (type == AGG_GLOBAL.COLOR_FIELD)
        return new ColorFieldFormat(name);
    else if (type == AGG_GLOBAL.DATA_FIELD)
        return new DataFieldFormat(name);
    else
        throw IllegalArgumentException("Unknown field type: " + AgString(type));
}

FieldFormat* FieldFormat::create(const AgString &name, char type, const AgString &description)
{
    FieldFormat* ff = create(name, type);
    ff->setDescription(description);
    return ff;
}

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

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

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

FieldFormat* FieldFormat::create(const AgString &name, char type, const AgString &description, AgObjectPtr defaultValue, bool nullable, const AgString &group)
{
    FieldFormat* ff = create(name, type, description);
    ff->setNullable(nullable);
    ff->setDefault(defaultValue);
    ff->setGroup(group);
    return ff;
}

FieldFormat* FieldFormat::create(const AgString &format, ClassicEncodingSettingsPtr settings)
{
    return create(format, settings, true);
}

FieldFormat* FieldFormat::create(const AgString &format, ClassicEncodingSettingsPtr settings, bool validate)
{
    ElementListPtr els = StringUtils::elements(format, settings->isUseVisibleSeparators());

    AgString name;
    char type;

    if (els->elements.size() >= 2)
    {
        name = els->elements[0]->getValue();
        type = (char)els->elements[1]->getValue()[0];
    }
    else
    {
        throw IllegalArgumentException("Illegal alrgument, format was \'" + format + "\'");
    }


    FieldFormat* ff = create(name, type);
    Element *el = els->getElement(AGG_GLOBAL.ELEMENT_FLAGS);

    if (el != NULL)
    {
        AgString flags = el->getValue();
        ff->setNullable(flags.find(AGG_GLOBAL.NULLABLE_FLAG) != AgString::npos ? true : false);
        ff->setOptional(flags.find(AGG_GLOBAL.OPTIONAL_FLAG) != AgString::npos ? true : false);
        ff->setExtendableSelectionValues(flags.find(AGG_GLOBAL.EXTENDABLE_SELECTION_VALUES_FLAG) != AgString::npos ? true : false);
        ff->setReadonly(flags.find(AGG_GLOBAL.READ_ONLY_FLAG) != AgString::npos ? true : false);
        ff->setNotReplicated(flags.find(AGG_GLOBAL.NOT_REPLICATED_FLAG) != AgString::npos ? true : false);
        ff->setHidden(flags.find(AGG_GLOBAL.HIDDEN_FLAG) != AgString::npos ? true : false);
        ff->setKeyField(flags.find(AGG_GLOBAL.KEY_FIELD_FLAG) != AgString::npos ? true : false);
        ff->setInlineData(flags.find(AGG_GLOBAL.INLINE_DATA_FLAG) != AgString::npos ? true : false);
        ff->setAdvanced(flags.find(AGG_GLOBAL.ADVANCED_FLAG) != AgString::npos ? true : false);
        ff->setDefaultOverride(flags.find(AGG_GLOBAL.DEFAULT_OVERRIDE) != AgString::npos ? true : false);
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_DEFAULT_VALUE);

     if (el != NULL)
     {
        ff->setDefaultFromString(el->getValue(), settings, validate);
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_DESCRIPTION);

     if (el != NULL)
     {
        ff->setDescription(DataTableUtils::transferDecode(el->getValue()));
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_HELP);

     if (el != NULL)
     {
        ff->setHelp(DataTableUtils::transferDecode(el->getValue()));
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_SELECTION_VALUES);

     if (el != NULL)
     {
        ff->createSelectionValues(el->getValue(), settings);
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_VALIDATORS);

     if (el != NULL)
     {
        ff->createValidators(el->getValue(), settings);
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_EDITOR);

     if (el != NULL)
     {
        ff->setEditor(DataTableUtils::transferDecode(el->getValue()));
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_EDITOR_OPTIONS);

     if (el != NULL)
     {
        ff->setEditorOptions(DataTableUtils::transferDecode(el->getValue()));
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_ICON);

     if (el != NULL)
     {
        ff->setIcon(DataTableUtils::transferDecode(el->getValue()));
     }

     el = els->getElement(AGG_GLOBAL.ELEMENT_GROUP);

     if (el != NULL)
     {
        ff->setGroup(DataTableUtils::transferDecode(el->getValue()));
     }

     return ff;
}

FieldFormat* FieldFormat::create(const AgString &format)
{
    return create(format, ClassicEncodingSettingsPtr(new ClassicEncodingSettings(true)), true);
}

FieldFormat *FieldFormat::clone()
{
    FieldFormat *cl = FieldFormat::create(name, getType());

    cl->nullable = nullable;
    cl->optional = optional;
    cl->extendableSelectionValues = extendableSelectionValues;
    cl->readonly = readonly;
    cl->notReplicated = notReplicated;
    cl->hidden = hidden;
    cl->keyField = keyField;
    cl->inlineData = inlineData;
    cl->advanced = advanced;
    cl->defaultOverride = defaultOverride;
    cl->defaultValue = CloneUtils::genericClone(getDefaultValue());
    cl->description = description;
    cl->help = help;
    cl->group = group;
    cl->editor = editor;
    cl->editorOptions = editorOptions;

    for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator it = selectionValues.begin(); it != selectionValues.end(); ++it)
    {
        AgObjectPtr obj = CloneUtils::genericClone(it->first);
        cl->selectionValues.push_back( std::make_pair(obj, it->second));
    }

    for (std::list<FieldValidatorPtr>::iterator it = validators.begin(); it != validators.end(); ++it)
    {
        FieldValidatorPtr fv = FieldValidatorPtr(dynamic_cast<FieldValidator *>((*it)->clone()));
        cl->validators.push_back(fv);
    }

    cl->icon = icon;
    cl->transferEncode = transferEncode;
    cl->cachedDefaultDescription = cachedDefaultDescription;

    cl->immutable = false;
    return cl;
}

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

    std::vector< std::pair<AgObjectPtr,AgString> > values;

    ElementListPtr els = StringUtils::elements(source, settings->isUseVisibleSeparators());
    for (std::vector<Element *>::iterator el = els->elements.begin(); el != els->elements.end(); ++el)
    {
        AgString valueSource = (*el)->getValue();

        AgObjectPtr selectionValue = valueFromEncodedString(valueSource, settings, true);

        AgString desc = (*el)->getName().length() != 0 ? (*el)->getName() : selectionValue->toString();
        values.push_back(std::make_pair(selectionValue, desc));
    }

    setSelectionValues(values);
}

AgString FieldFormat::getEncodedSelectionValues(ClassicEncodingSettingsPtr settings)
{
    if (selectionValues.size() == 0)
    {
        return AgString();
    }

    AgString enc;

    for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator value = selectionValues.begin(); value != selectionValues.end(); ++value)
    {
        AgString valueDesc = value->second;
        Element el(valueDesc, valueToEncodedString(value->first, settings));
        enc += el.encode(settings->isUseVisibleSeparators());
    }

    return enc;
}

AgString FieldFormat::getEncodedFlags()
{
    AgString buf;
    if (isNullable())
    {
        buf += AGG_GLOBAL.NULLABLE_FLAG;
    }
    if (isOptional())
    {
        buf += AGG_GLOBAL.OPTIONAL_FLAG;
    }
    if (isReadonly())
    {
        buf += AGG_GLOBAL.READ_ONLY_FLAG;
    }
    if (isNotReplicated())
    {
        buf += AGG_GLOBAL.NOT_REPLICATED_FLAG;
    }
    if (isExtendableSelectionValues())
    {
        buf += AGG_GLOBAL.EXTENDABLE_SELECTION_VALUES_FLAG;
    }
    if (isHidden())
    {
        buf += AGG_GLOBAL.HIDDEN_FLAG;
    }
    if (isKeyField())
    {
        buf += AGG_GLOBAL.KEY_FIELD_FLAG;
    }
    if (isInlineData())
    {
        buf += AGG_GLOBAL.INLINE_DATA_FLAG;
    }
    if (isAdvanced())
    {
        buf += AGG_GLOBAL.ADVANCED_FLAG;
    }
    if (isDefaultOverride())
    {
        buf += AGG_GLOBAL.DEFAULT_OVERRIDE;
    }
    return buf;
}

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


FieldFormat::FieldFormat(const AgString &name) : nullable(false), optional(false), extendableSelectionValues(false),
    readonly(false), notReplicated(false), hidden(false), keyField(false), inlineData(false), advanced(false),
    defaultOverride(false), transferEncode(false), immutable(false)
{
    this->name = name;
}

AgObjectPtr FieldFormat::convertValue(AgObjectPtr value)
{
    if (value.get() != NULL)
    {
        if (!(getFieldClass() == value->getClass() || getFieldWrappedClass() == value->getClass()))
        {
            throw ValidationException("Invalid class, need '" + AgString(getFieldWrappedClass().c_str()) + "', found '" + AgString(value->getClass().c_str()) + "'");
        }
    }

    return value;
}

FieldFormat& FieldFormat::setTransferEncode(bool transferEncode)
{
    this->transferEncode = transferEncode;
    return *this;
}

std::list<AgString> FieldFormat::getSuitableEditors()
{
    std::list<AgString> list;
    list.push_back(AGG_GLOBAL.EDITOR_LIST);
    return list;
}

AgObjectPtr FieldFormat::valueFromEncodedString(const AgString &source)
{
    return valueFromEncodedString(source, ClassicEncodingSettingsPtr(new ClassicEncodingSettings(false)), true);
}

AgObjectPtr FieldFormat::valueFromEncodedString(const AgString &source, ClassicEncodingSettingsPtr settings, bool validate)
{
    AgString str =  settings->isUseVisibleSeparators() ? DataTableUtils::DATA_TABLE_VISIBLE_NULL() : DataTableUtils::DATA_TABLE_NULL;
    if (source == str)
    {
        return AgObjectPtr();
    }
    else
    {
        return valueFromString(isTransferEncode() ? DataTableUtils::transferDecode(source) : source, settings, validate);
    }
}

AgObjectPtr FieldFormat::valueFromString(const AgString &value)
{
    return valueFromString(value, ClassicEncodingSettingsPtr(), false);
}

AgString FieldFormat::valueToString(AgObjectPtr value)
{
    return valueToString(value, ClassicEncodingSettingsPtr());;
}

AgString FieldFormat::valueToEncodedString(AgObjectPtr value, ClassicEncodingSettingsPtr settings)
{
    if (value.get() == 0)
    {
        return (settings.get() == NULL || !settings->isUseVisibleSeparators()) ? DataTableUtils::DATA_TABLE_NULL : DataTableUtils::DATA_TABLE_VISIBLE_NULL();
    }

    AgString strVal = valueToString(value, settings);
    return isTransferEncode() ? DataTableUtils::transferEncode(strVal) : strVal;
}

void FieldFormat::setDefaultFromString(const AgString &/*value*/)
{
    assert(0);
    //what is it?
    //setDefaultFromString(value);
}

void FieldFormat::setDefaultFromString(const AgString &value, ClassicEncodingSettingsPtr settings, bool validate)
{
    UNUSED(validate);
    if (value.length() == 0)
    {
        return;
    }

    // Overriding validate flag here, as default value may contain non-valid table
    setDefault(valueFromEncodedString(value, settings, false));
}

FieldFormat& FieldFormat::setDefault(AgObjectPtr value)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    try
    {
        defaultValue = checkAndConvertValue(value, true);
    }
    catch (ContextException &ex)
    {
        throw IllegalArgumentException(ex.getMessage(), ex.getDetails());
    }
    return *this;
}

AgString FieldFormat::getEncodedValidators(ClassicEncodingSettingsPtr settings)
{
    if (validators.size() == 0)
    {
        return AgString();
    }

    AgString enc;

    for (std::list<FieldValidatorPtr>::iterator fv = validators.begin(); fv != validators.end(); ++fv)
    {
        if ((*fv)->getType() != 0)
        {
            AgString str;
            str += (*fv)->getType();
            Element el(str, (*fv)->encode());
            enc += el.encode(settings->isUseVisibleSeparators());
        }
    }

    return enc;
}

AgString FieldFormat::encode()
{
    return encode(true);
}

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

AgString FieldFormat::encode(ClassicEncodingSettingsPtr settings)
{
    AgString data;

    data += Element(AgString(), getName()).encode(settings->isUseVisibleSeparators());
    data += Element(AgString(), AgString(getType())).encode(settings->isUseVisibleSeparators());

    encAppend(data, AGG_GLOBAL.ELEMENT_FLAGS, getEncodedFlags(), settings);

    if (settings->isEncodeDefaultValues())
    {
        data += Element(AGG_GLOBAL.ELEMENT_DEFAULT_VALUE, valueToEncodedString(getDefaultValue(), settings)).encode(settings->isUseVisibleSeparators());
    }

    encAppend(data, AGG_GLOBAL.ELEMENT_DESCRIPTION, DataTableUtils::transferEncode(description), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_HELP, DataTableUtils::transferEncode(help), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_SELECTION_VALUES, getEncodedSelectionValues(settings), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_VALIDATORS, getEncodedValidators(settings), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_EDITOR, DataTableUtils::transferEncode(editor), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_EDITOR_OPTIONS, DataTableUtils::transferEncode(editorOptions), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_ICON, DataTableUtils::transferEncode(icon), settings);
    encAppend(data, AGG_GLOBAL.ELEMENT_GROUP, DataTableUtils::transferEncode(group), settings);

    return data;
}

bool FieldFormat::extend(FieldFormat* other)
{
    return extendMessage(other).length() == 0;
}

AgString FieldFormat::extendMessage(FieldFormat* other)
{
    if (getName() != other->getName())
    {
        return "Wrong name: need " + getName() + ", found " + other->getName();
    }
    if (other->hasDescription() && getDescription() != other->getDescription())
    {
        return "Wrong description: need " + getDescription() + ", found " + other->getDescription();
    }
    if (getHelp() != other->getHelp())
    {
        return "Wrong help: need " + getHelp() + ", found " + other->getHelp();
    }
    if (getType() != other->getType())
    {
        return AgString("Wrong type: need ") + getType() + ", found " + other->getType();
    }
    if (!isNullable() && other->isNullable())
    {
        return AgString("Different nullable flags: need ") + (isNullable() ? "true" : "false") + AgString(", found ") + (other->isNullable() ? "true" : "false");
    }
    if (isReadonly() != other->isReadonly())
    {
        return AgString("Different readonly flags: need ") + (isReadonly() ? "true" : "false") + AgString(", found ") + (other->isReadonly() ? "true" : "false");
    }
    if (isHidden() != other->isHidden())
    {
        return AgString("Different hidden flags: need ") + (isHidden() ? "true" : "false") + AgString(", found ") + (other->isHidden() ? "true" : "false");
    }

    if (!isExtendableSelectionValues() || !other->isExtendableSelectionValues())
    {
        bool selectionValuesOk = other->getSelectionValues().size() == 0 || Util::equals(getSelectionValues(), other->getSelectionValues());

        if (!selectionValuesOk && getSelectionValues().size() != 0)
        {
            bool foundMissingValues = false;
            std::vector< std::pair<AgObjectPtr,AgString> > &selValues = getSelectionValues();
            std::vector< std::pair<AgObjectPtr,AgString> > &otherSelValues = other->getSelectionValues();
            for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator it = selValues.begin(); it != selValues.end(); ++it)
            {
                //find it->first in otherSelValues
                bool bFound = false;
                for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator itOther = otherSelValues.begin(); itOther != otherSelValues.end(); ++itOther)
                {
                    if (itOther->first->equals(it->first.get()))
                    {
                        bFound = true;
                        break;
                    }
                }

                if (!bFound)
                {
                    foundMissingValues = true;
                }
            }
            if (!foundMissingValues)
            {
                selectionValuesOk = true;
            }
        }

        if (!selectionValuesOk)
        {
            //todo getSelectionValues() to string
            return "Different selection values";
            //return "Different selection values: need " + other.getSelectionValues() + ", found " + getSelectionValues();
        }
    }

    if (getEditor() != other->getEditor())
    {
        return "Different editor: need " + getEditor() + ", found " + other->getEditor();
    }
    if (getEditorOptions() != other->getEditorOptions())
    {
        return "Different editor options: need " + getEditorOptions() + ", found " + other->getEditorOptions();
    }
    if (getIcon() != other->getIcon())
    {
        return "Wrong icon: need " + getIcon() + ", found " + other->getIcon();
    }
    if (getGroup() != other->getGroup())
    {
        return "Wrong group: need " + getGroup() + ", found " + other->getGroup();
    }

    std::list<FieldValidatorPtr> otherValidators = other->getValidators();
    std::list<FieldValidatorPtr> validators = getValidators();
    for (std::list<FieldValidatorPtr>::iterator otherValidator = otherValidators.begin(); otherValidator != otherValidators.end(); ++otherValidator)
    {
        std::list<FieldValidatorPtr>::iterator it = find(validators.begin(), validators.end(), *otherValidator);

        if (it == validators.end())
        {
            //todo make getValidators() to string
            return "Different validators";
            //return "Different validators: need " + getValidators() + ", found " + other.getValidators();
        }
    }

    DataTable *dtMy = dynamic_cast<DataTable *>(getDefaultValue().get());
    DataTable *dtOther = dynamic_cast<DataTable *>(other->getDefaultValue().get());

    if (dtMy != NULL && dtOther != NULL)
    {
        AgString msg = dtMy->getFormat()->extendMessage(dtOther->getFormat());
        if (msg.length() != 0)
        {
            return "Field format doesn't match: " + msg;
        }
    }
    return AgString();
}

FieldFormat& FieldFormat::addValidator(FieldValidatorPtr validator)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    validators.push_back(validator);
    return *this;
}

void FieldFormat::setValidators(const std::list<FieldValidatorPtr> &validators)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->validators = validators;
}

void FieldFormat::createValidators(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 )
    {
        char validatorType = (char)(*el)->getName()[0];
        AgString validatorParams = (*el)->getValue();

        if (validatorType == AGG_GLOBAL.VALIDATOR_LIMITS)
        {
            addValidator(FieldValidatorPtr(new LimitsValidator(*this, validatorParams)));
        }
        else if (validatorType == AGG_GLOBAL.VALIDATOR_REGEX)
        {
            addValidator(FieldValidatorPtr(new RegexValidator(validatorParams)));
        }
        else if (validatorType == AGG_GLOBAL.VALIDATOR_NON_NULL)
        {
            addValidator(FieldValidatorPtr(new NonNullValidator(validatorParams)));
        }
        else if (validatorType == AGG_GLOBAL.VALIDATOR_ID)
        {
            addValidator(FieldValidatorPtr(new IdValidator()));
        }
    }
}

AgObjectPtr FieldFormat::checkAndConvertValue(AgObjectPtr value, bool validate)
{

    if (!isNullable() && value.get() == NULL)
    {
        throw ValidationException(MessageFormat::format(Cres::get()->getString("dtNullsNotPermitted"), this->toString()));
    }

    value = convertValue(value);

    if (value.get() != NULL)
    {
        if (getSelectionValues().size() != 0)
        {
            if (!isExtendableSelectionValues())
            {
                //find value in getSelectionValues()
                bool bFound = false;
                for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator it = getSelectionValues().begin(); it != getSelectionValues().end(); ++it)
                {
                    if (it->first->equals(value.get()))
                    {
                        bFound = true;
                        break;
                    }
                }

                if (!bFound)
                {
                    if (validate)
                    {
                        throw ValidationException(Cres::get()->getString("dtValueNotInSelVals") + value->toString());
                    }
                    else
                    {
                        value = getDefaultValue();
                    }
                }
            }
        }
    }

    if (validate)
    {
        for (std::list<FieldValidatorPtr>::iterator fv = validators.begin(); fv != validators.end(); ++fv)
        {
            value = (*fv)->validate(value);
        }
    }

    return value;
}

AgString FieldFormat::getTypeName()
{
    return AGG_GLOBAL.TYPE_SELECTION_VALUES[getType()];
}

AgString &FieldFormat::getName()
{
    return name;
}

bool FieldFormat::isNullable()
{
    return nullable;
}

AgObjectPtr FieldFormat::getDefaultValue()
{
    if (defaultValue.get() == NULL && !isNullable())
    {
        defaultValue = getNotNullDefault();
    }
    return defaultValue;
}

AgObjectPtr FieldFormat::getDefaultValueCopy()
{
    AgObjectPtr def = getDefaultValue();
    return def.get() == NULL ? AgObjectPtr() : CloneUtils::genericClone(def);
}

AgString FieldFormat::getDescription()
{
    if (description.length() == 0)
    {
        if (cachedDefaultDescription.length() == 0)
        {
            cachedDefaultDescription = Util::nameToDescription(name);
        }

        return cachedDefaultDescription;
    }

    return description;
}

bool FieldFormat::hasDescription()
{
    return description.length() != 0;
}

AgString FieldFormat::getHelp()
{
    return help;
}

bool FieldFormat::isOptional()
{
    return optional;
}

bool FieldFormat::hasSelectionValues()
{
    return selectionValues.size() > 0;
}

std::vector< std::pair<AgObjectPtr,AgString> > &FieldFormat::getSelectionValues()
{
    return selectionValues;
}

FieldFormat& FieldFormat::addSelectionValue(AgObjectPtr value, const AgString &description)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    try
    {
        value = convertValue(value);
    }
    catch (ValidationException ex)
    {
        throw IllegalArgumentException(ex.getMessage(), ex.getDetails());
    }

    if (description.length() == 0)
    {
        throw IllegalArgumentException("Empty selection value description");
    }

    //check for duplicate for debud purposes
    bool bFound = false;
    for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator it = selectionValues.begin(); it != selectionValues.end(); ++it)
    {
        if (it->first->equals(value.get()))
        {
            bFound = true;
            break;
        }
    }

    if (bFound)
        throw IllegalArgumentException("Duplicate value");

    selectionValues.push_back(std::make_pair(value, description));

    return *this;
}

FieldFormat& FieldFormat::addSelectionValue(AgObjectPtr value)
{
    return addSelectionValue(value, value->toString());
}

bool FieldFormat::isExtendableSelectionValues()
{
    return extendableSelectionValues;
}

std::list<FieldValidatorPtr> &FieldFormat::getValidators()
{
    return validators;
}

bool FieldFormat::isReadonly()
{
    return readonly;
}

bool FieldFormat::isNotReplicated()
{
    return notReplicated;
}

bool FieldFormat::isTransferEncode()
{
    return transferEncode;
}

bool FieldFormat::isHidden()
{
    return hidden;
}

AgString FieldFormat::getEditor()
{
    return editor;
}

bool FieldFormat::isKeyField()
{
    return keyField;
}

AgString FieldFormat::getEditorOptions()
{
    return editorOptions;
}

bool FieldFormat::isInlineData()
{
    return inlineData;
}

bool FieldFormat::isAdvanced()
{
    return advanced;
}

void FieldFormat::setAdvanced(bool advanced)
{
    this->advanced = advanced;
}

FieldFormat& FieldFormat::setDescription(const AgString &description)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->description = description;
    return *this;
}

FieldFormat& FieldFormat::setHelp(AgString help)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    this->help = help;
    return *this;
}

FieldFormat& FieldFormat::setSelectionValues(std::vector< std::pair<AgObjectPtr,AgString> > &selectionValues)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    if (selectionValues.size() == 0)
    {
        this->selectionValues.clear();
        return *this;
    }

    this->selectionValues = selectionValues;

    // If current default value doesn't match to new selection values, we change it to the first selection value from the list
    // find getDefaultValue() in selectionValues
    AgObjectPtr defaultValue = getDefaultValue();
    bool bFound = false;
    if (defaultValue != NULL)
    {
        for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator it = selectionValues.begin(); it != selectionValues.end(); ++it)
        {
            if (it->first->equals(defaultValue.get()))
            {
                bFound = true;
                break;
            }
        }
    }

    if (!bFound && !extendableSelectionValues)
    {
        if (selectionValues.size() > 0)
        {
            setDefault(this->selectionValues.begin()->first);
        }
        else
        {
            assert(0);
        }
    }

    return *this;
}

FieldFormat& FieldFormat::setExtendableSelectionValues(bool extendableSelectionValues)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->extendableSelectionValues = extendableSelectionValues;
    return *this;
}

FieldFormat& FieldFormat::setNullable(bool nullable)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->nullable = nullable;
    return *this;
}

FieldFormat& FieldFormat::setOptional(bool optional)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->optional = optional;
    return *this;
}

FieldFormat& FieldFormat::setReadonly(bool readonly)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->readonly = readonly;
    return *this;
}

FieldFormat& FieldFormat::setNotReplicated(bool notReplicated)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->notReplicated = notReplicated;
    return *this;
}

FieldFormat& FieldFormat::setHidden(bool hidden)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->hidden = hidden;
    return *this;
}

FieldFormat& FieldFormat::setEditor(const AgString &editor)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }

    std::list<AgString> editors = getSuitableEditors();


    if (editor.length() != 0 && std::find(editors.begin(), editors.end(), editor) == editors.end())
    {
        AgString str = toString();
        for (std::list<AgString>::iterator it = editors.begin(); it != editors.end(); ++it)
        {
            str += " " + *it;
        }

        throw IllegalArgumentException(MessageFormat::format(Cres::get()->getString("dtEditorNotSuitable"), str));
    }

    this->editor = editor;

    return *this;
}

FieldFormat& FieldFormat::setKeyField(bool keyField)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->keyField = keyField;
    return *this;
}

FieldFormat& FieldFormat::setName(const AgString &name)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->name = name;
    return *this;
}

FieldFormat& FieldFormat::setEditorOptions(const AgString &editorOptions)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->editorOptions = editorOptions;
    return *this;
}

FieldFormat& FieldFormat::setInlineData(bool inlineData)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->inlineData = inlineData;
    return *this;
}

void FieldFormat::setSelectionValues(const AgString &source)
{
    createSelectionValues(source, ClassicEncodingSettingsPtr(new ClassicEncodingSettings(false)));
}

FieldFormat& FieldFormat::setIcon(const AgString &icon)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->icon = icon;
    return *this;
}

AgString FieldFormat::getIcon()
{
    return icon;
}

AgString FieldFormat::getGroup()
{
    return group;
}

FieldFormat& FieldFormat::setGroup(const AgString &group)
{
    if (immutable)
    {
        throw IllegalStateException("Immutable");
    }
    this->group = group;
    return *this;
}

bool FieldFormat::isDefaultOverride()
{
    return defaultOverride;
}

void FieldFormat::setDefaultOverride(bool defaultOverride)
{
    this->defaultOverride = defaultOverride;
}

AgString FieldFormat::toString()
{
    return description.length() != 0 ? description : name;
}

AgString FieldFormat::toDetailedString()
{
    return (description.length() != 0 ? description + " (" + name + ")" : name) + ", " + getTypeName();
}

TableFormatPtr FieldFormat::wrap()
{
    return TableFormatPtr(new TableFormat(this));
}

TableFormatPtr FieldFormat::wrapSimple()
{
    TableFormatPtr tf = TableFormatPtr(new TableFormat(this));
    tf->setMinRecords(1).setMaxRecords(1);
    return tf;
}

void FieldFormat::makeImmutable()
{
    immutable = true;
}

int FieldFormat::getSelectionValuesHashCode()
{
    if (selectionValues.size() == 0)
    {
        return 0;
    }
    else
    {
        int res = 0;
        for (std::vector< std::pair<AgObjectPtr,AgString> >::iterator it = selectionValues.begin(); it != selectionValues.end(); ++it)
        {
            res += it->first->hashCode() + it->second.hashCode();
        }
        return res;
    }
}

int FieldFormat::getValidatorsHashCode()
{
    if (validators.size() == 0)
    {
        return 0;
    }
    else
    {
        int res = 0;
        for (std::list<FieldValidatorPtr>::iterator it = validators.begin(); it != validators.end(); ++it)
        {
            res += (*it)->hashCode();
        }
        return res;
    }
}

int FieldFormat::hashCode()
{
    const int prime = 31;
    int result = 1;
    AgObjectPtr def = getDefaultValue();
    result = prime * result + ((def.get() == NULL) ? 0 : def->hashCode());
    result = prime * result + getType();
    result = prime * result + ((description.length() == 0) ? 0 : description.hashCode());
    result = prime * result + ((editor.length() == 0) ? 0 : editor.hashCode());
    result = prime * result + ((editorOptions.length() == 0) ? 0 : editorOptions.hashCode());
    result = prime * result + ((icon.length() == 0) ? 0 : icon.hashCode());
    result = prime * result + ((group.length() == 0) ? 0 : group.hashCode());
    result = prime * result + (extendableSelectionValues ? 1231 : 1237);
    result = prime * result + ((help.length() == 0) ? 0 : help.hashCode());
    result = prime * result + (hidden ? 1231 : 1237);
    result = prime * result + (inlineData ? 1231 : 1237);
    result = prime * result + (keyField ? 1231 : 1237);
    result = prime * result + ((name.length() == 0) ? 0 : name.hashCode());
    result = prime * result + (notReplicated ? 1231 : 1237);
    result = prime * result + (nullable ? 1231 : 1237);
    result = prime * result + (optional ? 1231 : 1237);
    result = prime * result + (readonly ? 1231 : 1237);
    result = prime * result + (advanced ? 1231 : 1237);
    result = prime * result + getSelectionValuesHashCode();
    result = prime * result + (transferEncode ? 1231 : 1237);
    result = prime * result + getValidatorsHashCode();
    return result;
}

bool FieldFormat::compareSelectionValues(std::pair<AgObjectPtr,AgString> &p1, std::pair<AgObjectPtr,AgString> &p2)
{
    return p1.first->equals(p2.first.get()) && p1.second == p2.second;
}
bool FieldFormat::compareValidators(FieldValidatorPtr &p1, FieldValidatorPtr &p2)
{
    return p1->equals(p2.get());
}

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

    FieldFormat *other = dynamic_cast<FieldFormat *>(obj);
    assert(other);

    if (name.length() == 0)
    {
        if (other->name.length() != 0)
        {
            return false;
        }
    }
    else if (name != other->name)
    {
        return false;
    }
    if (extendableSelectionValues != other->extendableSelectionValues)
    {
        return false;
    }
    if (hidden != other->hidden)
    {
        return false;
    }
    if (inlineData != other->inlineData)
    {
        return false;
    }
    if (keyField != other->keyField)
    {
        return false;
    }
    if (notReplicated != other->notReplicated)
    {
        return false;
    }
    if (nullable != other->nullable)
    {
        return false;
    }
    if (optional != other->optional)
    {
        return false;
    }
    if (readonly != other->readonly)
    {
        return false;
    }
    if (advanced != other->advanced)
    {
        return false;
    }
    if (description.length() == 0)
    {
        if (other->description.length())
        {
            return false;
        }
    }
    else if (description != other->description)
    {
        return false;
    }
    AgObjectPtr def = getDefaultValue();
    AgObjectPtr odef = other->getDefaultValue();
    if (def.get() == NULL)
    {
        if (odef.get() != NULL)
        {
            return false;
        }
    }
    else if (!def->equals(odef.get()))
    {
        return false;
    }
    if (!help.length())
    {
        if (other->help.length())
        {
            return false;
        }
    }
    else if (help != other->help)
    {
        return false;
    }
    if (!editor.length())
    {
        if (other->editor.length() != 0)
        {
            return false;
        }
    }
    else if (editor != other->editor)
    {
        return false;
    }
    if (editorOptions.length() == 0)
    {
        if (other->editorOptions.length() != 0)
        {
            return false;
        }
    }
    else if (editorOptions != other->editorOptions)
    {
        return false;
    }
    if (icon.length() == 0)
    {
        if (other->icon.length())
        {
            return false;
        }
    }
    else if (icon != other->icon)
    {
        return false;
    }
    if (group.length() == 0)
    {
        if (other->group.length() != 0)
        {
            return false;
        }
    }
    else if (group != other->group)
    {
        return false;
    }

    if (selectionValues.size() == 0)
    {
        if (other->selectionValues.size() != 0)
        {
            return false;
        }
    }
    else
    {
        if ( !std::equal (selectionValues.begin(), selectionValues.end(), other->selectionValues.begin(), compareSelectionValues) )
        {
            return false;
        }
    }
    if (transferEncode != other->transferEncode)
    {
        return false;
    }
    if (validators.size() == 0)
    {
        if (other->validators.size() != 0)
        {
            return false;
        }
    }
    else
    {
        if ( !std::equal (validators.begin(), validators.end(), other->validators.begin(), compareValidators) )
        {
            return false;
        }
    }
    return true;
}
