#include <iostream>
#include <map>
#include <string>

class ValueNotFoundException {};

template<typename T> class Memory
{
    typedef std::map<std::string, T> MemoryMap;

    Memory<T> *outerMemory;
    MemoryMap mmap;

    std::string memname;                                    // tylko dla wydruku :D

    Memory(Memory *outer, std::string name)                 // tylko dla wydruku :D (memname = name)
        : outerMemory(outer), memname(name)
    {
    }
public:
    std::string getName(void) const { return memname; }     // tylko dla wydruku :D
    static Memory getGlobal(void)
    {
        static Memory global(0, "(global)");
        return global;
    }

    Memory createInnerMemory(std::string name)
    {
        return Memory(this, name);
    }

    Memory<T>& setValue(std::string name, T value)
    {
        mmap[name] = value;
        return *this;
    }

    T getValue(std::string name)
    {
        if(mmap.find(name) != mmap.end()) return mmap[name]; // gdy znaleziono...
        if(!outerMemory) throw ValueNotFoundException(); // gdy nie znaleziono i jesteśmy w "globalu", to nie ma i na razie :D
        return outerMemory->getValue(name); // gdy nie znzaleziono, ale to na szczescie jakas inna pamiec :P
    }

    unsigned printMemTree() // tylko dla wydruku
    {
        using std::cout;
        using std::endl;

        class Helper
        {
        public:
            static void addTabs(unsigned u)
            {
                for(unsigned i = 0; i < u; i++)
                    cout << "  ";
            }
        };

        unsigned tabs = outerMemory ? outerMemory->printMemTree() : 0; // dobijamy sie aż do globala


        Helper::addTabs(tabs);
        cout << "ZAKRES \"" << memname << "\" : " << endl;

        typedef typename MemoryMap::iterator Iter;
        for(Iter it = mmap.begin(); it != mmap.end(); it++) // ALE SIĘ WKURWIŁEM TU KOMPILATORZE JEBANY
        {
            Helper::addTabs(tabs + 1);
            cout << '\"' << it->first << "\" : " << it->second << endl;
        }

        return tabs + 1; // jedziem wyżej :D
    }
};

template<typename T> void print(std::string name, Memory<T>& mem)
{
    try
    {
        T value = mem.getValue(name);
        std::cout << '`' << name << '`' << " (z perspektywy \"" << mem.getName() <<"\") = " << value << std::endl;
    }
    catch(ValueNotFoundException&)
    {
        std::cout << "Nie znaleziono zmiennej `" << name << "` z zakresu \"" << mem.getName() << '\"' << std::endl;
    }
}

int main(void)
{
    typedef Memory<int> MemI;

    MemI global = MemI::getGlobal();
    MemI inner1 = global.createInnerMemory("inner1");
    MemI inner2 = inner1.createInnerMemory("inner2");

    global.setValue("o", 123);
    inner1.setValue("x", 666).setValue("r", 30);
    inner2.setValue("x", 82);

    inner2.printMemTree(); // rysujemy drzewko :P

    // TESTUJEMY
    print("o", global);
    print("r", inner2);
    print("o", inner2);
    print("dupadupadupa", inner1);
    print("x", inner2);
    print("o", inner1);

    return 0;
}
