#pragma once
#include "slot_data.h"
#include "server.h"

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

#include <util/string/cast.h>
#include <util/string/vector.h>
#include <util/generic/map.h>
#include <util/generic/string.h>


namespace NRTYCluster {

    class IClusterScanCallback;
    class ISlotsFilter;

    class TDatacenter {
    private:
        TMap<TString, TServer> Servers;
        TMap<TString, TSlotData> Slots;
    public:

        static const TString SASMarker;
        static const TString MSKMarker;
        static const TString MANMarker;
        static const TString VLAMarker;

        TDatacenter() {

        }

        TDatacenter(const TDatacenter& dc) {
            Servers = dc.Servers;
            Slots = dc.Slots;
        }

        TDatacenter& operator=(const TDatacenter& dc) {
            Servers = dc.Servers;
            Slots = dc.Slots;
            return *this;
        }

        bool IsExists(const TSlotData& slot) const {
            return Slots.find(slot.ShortSlotName()) != Slots.end();
        }

        bool RegisterSlot(const TSlotData& slot) {
            if (!IsExists(slot)) {
                Servers[slot.ShortHost()].RegisterSlot(slot);
                Slots[slot.ShortSlotName()] = slot;
                return true;
            } else {
                return false;
            }
        }

        void ScanAll(IClusterScanCallback& callback) const;

        const TMap<TString, TServer>& GetServers() const {
            return Servers;
        }

        const TMap<TString, TSlotData>& GetSlots() const {
            return Slots;
        }

        TVector<TSlotData> GetSlotsList() const {
            TVector<TSlotData> result;
            for (TMap<TString, TSlotData>::const_iterator i = Slots.begin(); i != Slots.end(); ++i) {
                result.push_back(i->second);
            }
            return result;
        }

        bool Deserialize(const NJson::TJsonValue& json) {
            if (!json.IsMap())
                return false;

            Servers.clear();
            for (auto&& i : json.GetMapSafe()) {
                if (!Servers[i.first].Deserialize(i.second)) {
                    return false;
                }
                auto&& slots = Servers[i.first].GetSlots();
                Slots.insert(slots.begin(), slots.end());
            }
            return true;
        }

        NJson::TJsonValue Serialize() const {
            NJson::TJsonValue result(NJson::JSON_MAP);
            for (auto&& i : Servers) {
                result[i.first] = i.second.Serialize();
            }
            return result;
        }
    };

}
