// Purpose.  Direct coupling, lots of start-up and shut-down overhead

#include <iostream>
#include <string>
using namespace std;

class Image {
   int        id;
   static int next;
public:
   Image() { id = next++;  cout << "   $$ ctor: "<< id << '\n'; }
   ~Image()              { cout << "   dtor: " << id << '\n'; }
   void draw()           { cout << "   drawing image " << id << '\n'; }
};
int Image::next = 1;

void main( void ) {
   Image images[5];
   int   i;

   cout << "Exit[0], Image[1-5]: ";
   cin >> i;
   while (i) {
      images[i-1].draw();
      cout << "Exit[0], Image[1-5]: ";
      cin >> i;
}  }

//    $$ ctor: 1
//    $$ ctor: 2
//    $$ ctor: 3
//    $$ ctor: 4
//    $$ ctor: 5
// Exit[0], Image[1-5]: 2
//    drawing image 2
// Exit[0], Image[1-5]: 4
//    drawing image 4
// Exit[0], Image[1-5]: 2
//    drawing image 2
// Exit[0], Image[1-5]: 0
//    dtor: 5
//    dtor: 4
//    dtor: 3
//    dtor: 2
//    dtor: 1




// Purpose.  Proxy design pattern

// 1. Design an "extra level of indirection" wrapper class
// 2. The wrapper class holds a pointer to the real class
// 3. The pointer is initialized to null
// 4. When a request comes in, the real object is created "on first use"
//    (aka lazy intialization)
// 5. The request is always delegated

class RealImage {
   int  id;
public:
   RealImage( int i ) { id = i;  cout << "   $$ ctor: "<< id << '\n'; }
   ~RealImage()                { cout << "   dtor: " << id << '\n'; }
   void draw()                 { cout << "   drawing image " << id << '\n'; }
};

// 1. Design an "extra level of indirection" wrapper class
class Image {
   // 2. The wrapper class holds a pointer to the real class
   RealImage* theRealThing;
   int        id;
   static int next;
public:
   Image()  { id = next++;  theRealThing = 0; }  // 3. Initialized to null
   ~Image() { delete theRealThing; }
   void draw() {
      // 4. When a request comes in, the real object is created "on first use"
      if ( ! theRealThing) theRealThing = new RealImage( id );
      // 5. The request is always delegated
      theRealThing->draw();
}  };
int Image::next = 1;

void main( void ) {
   Image images[5];
   int   i;

   cout << "Exit[0], Image[1-5]: ";
   cin >> i;
   while (i) {
      images[i-1].draw();
      cout << "Exit[0], Image[1-5]: ";
      cin >> i;
}  }

// Exit[0], Image[1-5]: 2
//    $$ ctor: 2
//    drawing image 2
// Exit[0], Image[1-5]: 4
//    $$ ctor: 4
//    drawing image 4
// Exit[0], Image[1-5]: 2
//    drawing image 2
// Exit[0], Image[1-5]: 4
//    drawing image 4
// Exit[0], Image[1-5]: 0
//    dtor: 4
//    dtor: 2




// Purpose.  "->" and "." operators give different results

class Subject { public: virtual void execute() = 0; };

class RealSubject : public Subject {
   string str;
public:
   RealSubject( string s ) { str = s; }
   /*virtual*/ void execute() { cout << str << '\n'; }
};

class ProxySubject : public Subject {
   string       first, second, third;
   RealSubject* ptr;
public:
   ProxySubject( string s ) {
      int num = s.find_first_of( ' ' );
      first = s.substr( 0, num );   s = s.substr( num+1 );
      num = s.find_first_of( ' ' );
      second = s.substr( 0, num );  s = s.substr( num+1 );
      num = s.find_first_of( ' ' );
      third = s.substr( 0, num );   s = s.substr( num+1 );
      ptr = new RealSubject( s );
   }
   ~ProxySubject() { delete ptr; }
   RealSubject* operator->() {
      cout << first << ' ' << second << ' ';
      return ptr;
   }
   /*virtual*/ void execute() {
      cout << first << ' ' << third << ' ';
      ptr->execute();
   }
};

void main( void ) {
   ProxySubject obj( string( "the quick brown fox jumped over the dog" ) );
   obj->execute();
   obj.execute();
}

// the quick fox jumped over the dog
// the brown fox jumped over the dog




// Purpose.  "A protection proxy controls access to the original object."

class Person {
   string nameString;
   static string list[];
   static int next;
public:
   Person() { nameString = list[next++]; }
   string name() { return nameString; }
};
string Person::list[] = { "Tom", "Dick", "Harry", "Bubba" };
int    Person::next = 0;

class PettyCashProtected {
   int balance;
public:
   PettyCashProtected() { balance = 500; }
   bool withdraw( int amount ) {
      if (amount > balance) return false;
      balance -= amount;
      return true;
   }
   int getBalance() { return balance; }
};

class PettyCash {
   PettyCashProtected realThing;
public:
   bool withdraw( Person& p, int amount ) {
      if (p.name() == "Tom" || p.name() == "Harry" || p.name() == "Bubba")
         return realThing.withdraw( amount );
      else return false;
   }
   int getBalance() { return realThing.getBalance(); }
};

void main( void ) {
   PettyCash  pc;
   Person     workers[4];
   for (int i=0, amount=100; i < 4; i++, amount += 100)
      if ( ! pc.withdraw( workers[i], amount ))
         cout << "No money for " << workers[i].name() << '\n';
      else
         cout << amount << " dollars for " << workers[i].name() << '\n';
   cout << "Remaining balance is " << pc.getBalance() << '\n';
}

// 100 dollars for Tom
// No money for Dick
// 300 dollars for Harry
// No money for Bubba
// Remaining balance is 100




// Purpose.  Simulate a Persistent Object Pointer

template <typename TBD>
class POP {          // Persistent Object Pointer
   string oid;
   TBD*   ptr;
public:
   POP( string id )  { oid = id;  ptr = 0; }
   ~POP()            { delete ptr; }
   TBD* operator->() {
      if ( ! ptr)
         // simulate the persistence mechanism
         ptr = new TBD( oid );
      return ptr;
}  };

class Person {
   string name;
   int    age;
public:
   Person( string n ) { name = n; }
   string getName()   { return name; }
   int    getAge()    { return 32; }
};

void main( void ) {
   POP<Person> ph( "Tom" );
   cout << "policy holder is " << ph->getName() << ", age is " << ph->getAge() << '\n';
}

// policy holder is Tom, age is 32