// Purpose.  Adapter
//
// Discussion.  The Adapter pattern
// discusses how to "wrap" the old in-
// terface of a legacy component, so
// that it can continue to contribute
// in a new system.  It is about "im-   #include <iostream.h>
// pedance matching" an old dog with    #include <stdio.h>
// new tricks (to mix metaphors).  On   #include <time.h>
// the left, WimpyTime "hasa" in-
// stance of the legacy component,      class ManlyTime {
// and delegates the "heavy lifting"    public:
// to it.  On the right, private           char* getTime() {
// derivation is used to accomplish           static char buf[30];
// the same result.                           time_t  lt;
                                              tm*     ltStruct;
class ManlyTime {                             time( &lt );
public:                                       ltStruct = localtime(&lt);
   char* getTime() {                          strftime( buf, 30, "%H%M",
      static char buf[30];                       ltStruct );
      time_t  lt;                             return buf;
      tm*     ltStruct;                    }
      time( &lt );                      };
      ltStruct = localtime(&lt);
      strftime( buf, 30, "%H%M",        class WimpyTime :
         ltStruct );                              private ManlyTime {
      return buf;                       public:
   }                                       char* getTime() {
};                                            static char buf[30];
                                              char *ptr, mi[3], am[3];
class WimpyTime {                             int  hr;
public:                                       ptr = ManlyTime::getTime();
   char* getTime() {                          cout << "old interface time is "
      static char buf[30];                       << ptr << endl;
      char *ptr, mi[3], am[3];                strcpy( mi, &(ptr[2]) );
      int  hr;                                ptr[2] = '\0';
      ptr = imp_.getTime();                   sscanf( ptr, "%d", &hr );
      cout << "old interface time is "        strcpy( am, "AM" );
         << ptr << endl;                      if (hr > 12) {
      strcpy( mi, &(ptr[2]) );                   hr -= 12;
      ptr[2] = '\0';                             strcpy( am, "PM" ); }
      sscanf( ptr, "%d", &hr );               sprintf( buf, "%d:%s %s",
      strcpy( am, "AM" );                        hr, mi, am );
      if (hr > 12) {                          return buf;
         hr -= 12;                         }
         strcpy( am, "PM" ); }          };
      sprintf( buf, "%d:%s %s",
         hr, mi, am );                  void main( void )
      return buf;                       {
   }                                       WimpyTime  newT;
private:                                   char*      ptr;
   ManlyTime  imp_;                        ptr = newT.getTime();
};                                         cout << "new interface time is "
                                              << ptr << endl;
void main( void )                       }
{
   WimpyTime  newT;                     // old interface time is 1721
   char*      ptr;                      // new interface time is 5:21 PM
   ptr = newT.getTime();
   cout << "new interface time is "
      << ptr << endl;
}

// old interface time is 1709
// new interface time is 5:09 PM



// Purpose.  Adapter design pattern demo
//
// Discussion.  LegacyRectangle's interface is not compatible with the
// system that would like to reuse it.  An abstract base class is created
// that specifies the desired interface.  An "adapter" class is defined
// that publicly inherits the interface of the abstract class, and
// privately inherits the implementation of the legacy component.  This
// adapter class "maps" or "impedance matches" the new interface to the
// old implementation.

#include <iostream.h>

typedef int Coordinate;
typedef int Dimension;

/////////////////////////// Desired interface ///////////////////////////
class Rectangle {
public:
   virtual void draw() = 0;
};

/////////////////////////// Legacy component ///////////////////////////
class LegacyRectangle {
public:
   LegacyRectangle( Coordinate x1, Coordinate y1,
         Coordinate x2, Coordinate y2 ) {
      x1_ = x1;  y1_ = y1;  x2_ = x2;  y2_ = y2;
      cout << "LegacyRectangle:  create.  (" << x1_ << "," << y1_
         << ") => (" << x2_ << "," << y2_ << ")" << endl; }
   void oldDraw() {
      cout << "LegacyRectangle:  oldDraw.  (" << x1_ << "," << y1_
         << ") => (" << x2_ << "," << y2_ << ")" << endl; }
private:
   Coordinate x1_;
   Coordinate y1_;
   Coordinate x2_;
   Coordinate y2_;
};

/////////////////////////// Adapter wrapper ///////////////////////////
class RectangleAdapter : public Rectangle, private LegacyRectangle {
public:
   RectangleAdapter( Coordinate x, Coordinate y, Dimension w, Dimension h )
         : LegacyRectangle( x, y, x+w, y+h ) {
      cout << "RectangleAdapter: create.  (" << x << "," << y
         << "), width = " << w << ", height = " << h << endl; }
   virtual void draw() {
      cout << "RectangleAdapter: draw." << endl;
      oldDraw(); }
};

void main() {
   Rectangle*  r = new RectangleAdapter( 120, 200, 60, 40 );
   r->draw();
}

// LegacyRectangle:  create.  (120,200) => (180,240)
// RectangleAdapter: create.  (120,200), width = 60, height = 40
// RectangleAdapter: draw.
// LegacyRectangle:  oldDraw.  (120,200) => (180,240)



// Purpose.  Adapter design pattern (External Polymorphism demo)

// 1. Specify the new desired interface
// 2. Design a "wrapper" class that can "impedance match" the old to the new
// 3. The client uses (is coupled to) the new interface
// 4. The adapter/wrapper "maps" to the legacy implementation

#include <iostream.h>

class ExecuteInterface { public:                  // 1. Specify the new i/f
   virtual ~ExecuteInterface() { }
   virtual void execute() = 0;
};

template <class TYPE>                             // 2. Design a "wrapper" or
class ExecuteAdapter : public ExecuteInterface {  //    "adapter" class
public:
   ExecuteAdapter( TYPE* o, void (TYPE::*m)() ) { object = o;  method =m; }
   ~ExecuteAdapter()                            { delete object; }
   // 4. The adapter/wrapper "maps" the new to the legacy implementation
   void execute()             /* the new */     { (object->*method)(); }
private:                            
   TYPE* object;                                  // ptr-to-object attribute
   void (TYPE::*method)();    /* the old */       // ptr-to-member-function
};                                                //   attribute

// The old: three totally incompatible classes    // no common base class,
class Fea { public:                               // no hope of polymorphism
   ~Fea()        { cout << "Fea::dtor" << endl; }
   void doThis() { cout << "Fea::doThis()" << endl; }
};

class Feye { public:
   ~Feye()       { cout << "Feye::dtor" << endl; }
   void doThat() { cout << "Feye::doThat()" << endl; }
};

class Pheau { public:
   ~Pheau()          { cout << "Pheau::dtor" << endl; }
   void doTheOther() { cout << "Pheau::doTheOther()" << endl; }
};

/* the new is returned */ ExecuteInterface** initialize() {
   ExecuteInterface** array = new ExecuteInterface*[3]; /* the old is below */
   array[0] = new ExecuteAdapter<Fea>(   new Fea(),     &Fea::doThis       );
   array[1] = new ExecuteAdapter<Feye>(  new Feye(),    &Feye::doThat      );
   array[2] = new ExecuteAdapter<Pheau>( new Pheau(),   &Pheau::doTheOther );
   return array;
}

void main( void ) {
   ExecuteInterface** objects = initialize();

   for (int i=0; i < 3; i++) objects[i]->execute();  // 3. Client uses the new
                                                     //    (polymporphism)
   for (i=0; i < 3; i++) delete objects[i];
   delete objects;
}

// Fea::doThis()
// Feye::doThat()
// Pheau::doTheOther()
// Fea::dtor
// Feye::dtor
// Pheau::dtor