#pragma once

#include "attribute.h"
#include "common.h"

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

namespace NSaas {
    class TZone;

    class TAbstractZone : public TNonCopyable {
        friend class TAttribute;
        friend class TProtobufDeserializer;
    public:
        typedef TMultiMap<TString, TSimpleSharedPtr<TAbstractZone> > TZones;
        typedef TMap<TString, TAttribute> TAttributes;

    public:
        virtual ~TAbstractZone() {}

        TZone& AddZone(const TString& name);
        bool HasZone(const TString& name) const;
        TZone& GetZone(const TString& name);
        TAttribute& AddAttribute(const TString& name);
        bool HasAttribute(const TString& name) const;
        const TAttribute& GetAttribute(const TString& name) const;
        TAbstractZone& AddSearchAttribute(const TString& name, const TString& value);
        TAbstractZone& AddSearchAttribute(const TString& name, ui32 value);

        virtual NJson::TJsonValue ToJson(TToJsonContext& context) const = 0;
        virtual const TString& GetName() const = 0;

    protected:
        virtual NRTYServer::TZone& AddSubZone() = 0;

        virtual void OnAttribute(const TString& name, const TString& value, TAttributeValue::TAttributeValueType type) = 0;
        void RegisterAttribute(const TString& name, const TString& value, TAttributeValue::TAttributeValueType type);
        static void AddZoneValue(NJson::TJsonValue& target, const TString& name, const NJson::TJsonValue& object);
    protected:
        TZones SubZones;
        TAttributes Attributes;
    };

    class TZone: public TAbstractZone {
    public:
        typedef TZone TThis;

    public:
        TZone(NRTYServer::TZone& zone)
            : InternalZone(zone)
        {}
        virtual NJson::TJsonValue ToJson(TToJsonContext& context) const override;

        /*(Get|Set|Has)Name*/ PROTOBUF_FIELD_ACCESSORS_REF_OVERRIDE(TString, Name, InternalZone, Name)
        /*(Get|Set|Has)Text*/ PROTOBUF_FIELD_ACCESSORS_REF(TString, Text, InternalZone, Text)
        TString& MutableText() {
            return * InternalZone.MutableText();
        }
    protected:
        virtual NRTYServer::TZone& AddSubZone() override {
            return * InternalZone.AddChildren();
        }
        virtual void OnAttribute(const TString& name, const TString& value, TAttributeValue::TAttributeValueType type) override;

    private:
        NRTYServer::TZone& InternalZone;
    };
}
