#pragma once

#include <string>
#include <map>
#include <list>

#include "GlobalVars.h"
#include "util/Cloneable.h"
#include "util/Pointers.h"
#include "util/AgObject.h"
#include "util/simpleobject/AgString.h"

class FieldFormat : public Cloneable, public AgObject
{
private: 
    AgString name;
    bool nullable;
    bool optional;
    bool extendableSelectionValues;
    bool readonly;
    bool notReplicated;
    bool hidden;
    bool keyField;
    bool inlineData;
    bool advanced;
    bool defaultOverride;
    AgObjectPtr defaultValue;
    AgString description;
    AgString help;
    AgString group;
    AgString editor;
    AgString editorOptions;

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

    std::list<FieldValidatorPtr> validators;
    AgString icon;
    bool transferEncode;
    bool immutable;
    AgString cachedDefaultDescription;

    void createSelectionValues(const AgString &source, ClassicEncodingSettingsPtr settings);
    AgString getEncodedSelectionValues(ClassicEncodingSettingsPtr settings);
    AgString getEncodedFlags();
    static void encAppend(AgString &buffer, const AgString &name, const AgString &value, ClassicEncodingSettingsPtr settings);

    int getSelectionValuesHashCode();
    int getValidatorsHashCode();
    static bool compareSelectionValues(std::pair<AgObjectPtr,AgString> &p1, std::pair<AgObjectPtr,AgString> &p2);
    static bool compareValidators(FieldValidatorPtr &p1, FieldValidatorPtr &p2);

protected:
    FieldFormat(const AgString &name);
    virtual AgObjectPtr convertValue(AgObjectPtr value);
    FieldFormat& setTransferEncode(bool transferEncode);
    virtual std::list<AgString> getSuitableEditors();

public:
    virtual char getType() = 0;
    virtual std::string getFieldClass() = 0;
    virtual std::string getFieldWrappedClass() = 0;
    virtual AgObjectPtr getNotNullDefault() = 0;
    virtual AgObjectPtr valueFromString(const AgString &value, ClassicEncodingSettingsPtr settings, bool validate) = 0;
    virtual AgString valueToString(AgObjectPtr value, ClassicEncodingSettingsPtr settings) = 0;

    AgObjectPtr valueFromEncodedString(const AgString &source);
    AgObjectPtr valueFromEncodedString(const AgString &source, ClassicEncodingSettingsPtr settings, bool validate);
    AgObjectPtr valueFromString(const AgString &value);  // return raw pointer, called side need delete AgObject
    AgString valueToString(AgObjectPtr value);
    AgString valueToEncodedString(AgObjectPtr value, ClassicEncodingSettingsPtr settings);
    void setDefaultFromString(const AgString &value);
    void setDefaultFromString(const AgString &value, ClassicEncodingSettingsPtr settings, bool validate);
    FieldFormat& setDefault(AgObjectPtr value);

    AgString getEncodedValidators(ClassicEncodingSettingsPtr settings);
    AgString encode();
    AgString encode(bool useVisibleSeparators);
    AgString encode(ClassicEncodingSettingsPtr settings);

    bool extend(FieldFormat* other);
    AgString extendMessage(FieldFormat* other);
    FieldFormat& addValidator(FieldValidatorPtr validator);
    void setValidators(const std::list<FieldValidatorPtr> &validators);
    void createValidators(const AgString& source, ClassicEncodingSettingsPtr settings);
    AgObjectPtr checkAndConvertValue(AgObjectPtr value, bool validate);

    AgString getTypeName();
    AgString &getName();
    bool isNullable();
    AgObjectPtr getDefaultValue();
    AgObjectPtr getDefaultValueCopy();
    AgString getDescription();
    bool hasDescription();
    AgString getHelp();
    bool isOptional();
    bool hasSelectionValues();
    std::vector< std::pair<AgObjectPtr,AgString> > &getSelectionValues();
    FieldFormat& addSelectionValue(AgObjectPtr value,const AgString &description);
    FieldFormat& addSelectionValue(AgObjectPtr value);
    bool isExtendableSelectionValues();    
    std::list<FieldValidatorPtr> &getValidators();
    bool isReadonly();
    bool isNotReplicated();
    bool isTransferEncode();

    bool isHidden();
    AgString getEditor();
    bool isKeyField();
    AgString getEditorOptions();
    bool isInlineData();
    bool isAdvanced();
    void setAdvanced(bool advanced);
    FieldFormat& setDescription(const AgString &description);
    FieldFormat& setHelp(AgString help);
    FieldFormat& setSelectionValues(std::vector< std::pair<AgObjectPtr,AgString> > &selectionValues);
    FieldFormat& setExtendableSelectionValues(bool extendableSelectionValues);
    FieldFormat& setNullable(bool nullable);
    FieldFormat& setOptional(bool optional);
    FieldFormat& setReadonly(bool readonly);
    FieldFormat& setNotReplicated(bool notReplicated);

    FieldFormat& setHidden(bool hidden);
    FieldFormat& setEditor(const AgString & editor);
    FieldFormat& setKeyField(bool keyField);
    FieldFormat& setName(const AgString & name);
    FieldFormat& setEditorOptions(const AgString & editorOptions);
    FieldFormat& setInlineData(bool inlineData);

    void setSelectionValues(const AgString & source);
    FieldFormat& setIcon(const AgString & icon);
    AgString getIcon();
    AgString getGroup();
    FieldFormat& setGroup(const AgString & group);
    bool isDefaultOverride();
    void setDefaultOverride(bool defaultOverride);
    AgString toString();
    AgString toDetailedString();

    TableFormatPtr wrap();
    TableFormatPtr wrapSimple();

    void makeImmutable();

    virtual int hashCode();
    virtual bool equals(AgObject* obj);

    static FieldFormat* create(const AgString &name, const AgString &valueClass);
    static FieldFormat* create(const AgString &name, char type);
    static FieldFormat* create(const AgString &name, char type, const AgString & description);
    static FieldFormat* create(const AgString &name, char type, const AgString & description, AgObjectPtr defaultValue);
    static FieldFormat* create(const AgString &name, char type, const AgString & description, AgObjectPtr defaultValue, const AgString & group);
    static FieldFormat* create(const AgString &name, char type, const AgString & description, AgObjectPtr defaultValue, bool nullable);
    static FieldFormat* create(const AgString &name, char type, const AgString & description, AgObjectPtr defaultValue, bool nullable, const AgString & group);
    static FieldFormat* create(const AgString & format, ClassicEncodingSettingsPtr settings);
    static FieldFormat* create(const AgString & format, ClassicEncodingSettingsPtr settings, bool validate);
    static FieldFormat* create(const AgString & format);

    virtual FieldFormat * clone();
};


