#pragma once

#include "common.h"

#include <saas/util/types/cast.h>

#include <library/cpp/json/json_value.h>

#include <util/generic/string.h>
#include <util/string/cast.h>
#include <util/generic/vector.h>
#include <util/generic/set.h>
#include <util/generic/map.h>
#include <library/cpp/charset/doccodes.h>

namespace NSaas {
    class TAbstractZone;
    class TAttribute;

    class TAttributeValue {
        friend class TAbstractZone;
    public:
        enum TAttributeValueType {avtInt, avtLit, avtProp, avtGrp, avtGrpLit, avtFactor, avtIntFactor, avtFSProp, avtSpecKey, avtTIProp};

    public:
        TAttributeValue(const TString& value, TAttribute& parent)
            : Value(value)
            , Parent(parent)
        {}

        TAttributeValue& AddType(TAttributeValueType type);
        NJson::TJsonValue ToJson(TToJsonContext& context) const;
        NJson::TJsonValue GetType() const;
        const TString& GetValue() const {return Value;};

        void SetBinary(bool f = true);
        bool IsBinary() const;

    public:
        static bool IsSearchAttribute(TAttributeValueType type) {
            return type == TAttributeValue::avtInt ||
                   type == TAttributeValue::avtLit;
        }
    private:
        bool AddTypeInternal(TAttributeValueType type);
    private:
        TSet<TAttributeValueType> Types;
        TString Value;
        TAttribute& Parent;
        bool Binary = false;
    };

    class TAttribute {
    public:
        TAttribute(const TString& name, TAbstractZone& parent)
            : Name(name)
            , Parent(parent)
            , HasSearchAttiributeValue(false)
        {}

        const TString& GetName() const {
            return Name;
        }
        TAttributeValue& AddValue(const TString& value);
        template <typename T>
        TAttributeValue& AddValue(const T& value) {
            return AddValue(ToString(value));
        }
        bool HasValue(const TString& value) const {
            return Values.contains(value);
        }
        bool FindValue(const TString& value) const {
            return HasValue(value);
        }
        void GetValues(TVector<const TAttributeValue*>& values) const;

        bool IsSearchAttribute() const {
            return HasSearchAttiributeValue;
        }
        void OnTypeAdd(const TString& value, TAttributeValue::TAttributeValueType type);
        NJson::TJsonValue ToJson(TToJsonContext& context) const;
    private:
        typedef TMap<TString, TAttributeValue> TValues;
    private:
        TString Name;
        TAbstractZone& Parent;
        TValues Values;
        bool HasSearchAttiributeValue;
    };
}
