#pragma once
#include <mutex>
#include <map>
#include <condition_variable>



namespace SimCore {

    template<typename K, typename V>
    class SafeMap {

        private:
            std::map<K, V> store;
            mutable std::mutex mx_;
            std::condition_variable c_;

        protected:


        public:
            SafeMap()
            {
                store = std::map<K, V>();
            }

            void addValue(K key, V value )
            {
                std::lock_guard<std::mutex> lock(mx_);
                store.emplace(key,value);
                c_.notify_one();

            }

            void removePair(K key)
            {
                std::lock_guard<std::mutex> lock(mx_);
                auto search = store.find(key);
                if (search != store.end()) {
                    search = store.erase(search);
                } 
                c_.notify_one();

            }

            void overRideValue(K key, V newValue)
            {
                std::lock_guard<std::mutex> lock(mx_);
                auto search = store.find(key);
                if (search != store.end()) {
                    store[key] = newValue;
                } 
                c_.notify_one();


            }


            V getValue(K key)
            {
                std::lock_guard<std::mutex> lock(mx_);
                 V  value;
                auto search = store.find(key);
                if (search != store.end()) {
                      value = store[key];
                }
                    return value;

            }

            bool hasKey(K key)
            {
                std::lock_guard<std::mutex> lock(mx_);
                auto search = store.find(key);
                if (search != store.end()) {
                      return true;
                }else {
                return false;
                }

            }


            long size()
            {

                std::lock_guard<std::mutex> lock(mx_);
                
                return store.size();
            }
            

            const V& operator[](const K& key) const
            {
                std::lock_guard<std::mutex> lock(mx_);
                return store.at(key);
            }

            V& operator[](const K& key)
            {
                std::lock_guard<std::mutex> lock(mx_);
                return store[key];
            }





    };
}

