// Purpose: messages travel both up and down the layers,
//          message interface per layer per direction,
//          one concrete Facade per layer (implements 1 or 2 interfaces)
//          Singleton access to Facade objects

#include <iostream>
using namespace std;

class ChildOf3  { public: virtual void downMessage() = 0; };
class ParentOf2 { public: virtual void upMessage()   = 0; };
class ChildOf2  { public: virtual void downMessage() = 0; };
class ParentOf1 { public: virtual void upMessage()   = 0; };

class C : public ParentOf2 { public:
   void execute();
   void upMessage();
};
class B : public ParentOf1, public ChildOf3 { public:
   void upMessage();
   void downMessage();
};
class A : public ChildOf2 { public:
   void downMessage();
   void execute();
};

class SC {   // Singleton Collection
public:
   static C& layer3() { return cObject; }
   static B& layer2() { return bObject; }
   static A& layer1() { return aObject; }
private:
   static C cObject;  static B bObject;  static A aObject;
};
   C SC::cObject;     B SC::bObject;     A SC::aObject;

void thirdParty( ChildOf2& obj1, ChildOf3& obj2, ParentOf2& obj3 ) {
   obj1.downMessage();
   obj2.downMessage();
   obj3.upMessage();
}

void main( void ) {
   SC::layer3().execute();
   SC::layer1().execute();
   thirdParty( SC::layer1(), SC::layer2(), SC::layer3() );
}

// C::execute          // A::execute        // A::downMessage
// B::downMessage      // B::upMessage      // B::downMessage
// A::downMessage      // C::upMessage      // A::downMessage
                                            // C::upMessage

void C::execute()     { cout << "C::execute" << endl;
                        SC::layer2().downMessage(); }
void C::upMessage()   { cout << "C::upMessage" << endl; }

void B::upMessage()   { cout << "B::upMessage" << endl;
                        SC::layer3().upMessage(); }
void B::downMessage() { cout << "B::downMessage" << endl;
                        SC::layer1().downMessage(); }

void A::execute()     { cout << "A::execute" << endl;
                        SC::layer2().upMessage(); }
void A::downMessage() { cout << "A::downMessage" << endl; }