// Purpose.  Flyweight design pattern lab
//
// Discussion.  Let's say 20 bytes per gadget is unacceptable overhead.  We
// want to "lighten up" the Gadget hierarchy, and, share a small number of
// "real" instances across a larger number of "virtual" instances.
//
// Assignment.
// o Replace the current main() with the one commented-out at the end
// o Gadget's x_, y_, and w_ are not shareable.  Remove them from Gadget's
//   private state, and, modify draw() to accept x, y, and w.
// o Add a Factory class that supports the expectations in the new main()
// o Factory could use a static array of 2 Gadget ptrs as its "cache" or
//   "pool" data structure (don't forget to init this static array)
// o getFlyweight() will check this static array to see if the requested
//   flyweight exists (if it doesn't, it will create it), and then return it
// o Notice how the "client" code in main() got more complicated.  The client
//   is responsible for knowing (or computing) the new "extrinsic" state and
//   passing that state to the flyweight objects.

#include <iostream.h>

// Microsoft Visual C++ code
#include <Wtypes.h>
#include <wincon.h>
HANDLE  console_ = GetStdHandle(STD_OUTPUT_HANDLE);
void gotoxy( int x, int y ) {
   COORD  coord;
   coord.X = x-1;
   coord.Y = y-1;
   SetConsoleCursorPosition( console_, coord );
}

class Gadget {
public:
   Gadget( int col, int row, int width, char ch ) {
      x_ = col;  y_ = row;  w_ = width;
      ch_ = ch;
   }
   virtual void draw() {
      int  i;
      gotoxy( x_, y_ );
      for (i=0; i < w_; i++)    cout << ch_;
      cout << endl;
      gotoxy( x_, y_+1 );
      cout << ch_;
      for (i=0; i < w_-2; i++)  cout << ' ';
      cout << ch_ << endl;
      gotoxy( x_, y_+2 );
      for (i=0; i < w_; i++)    cout << ch_;
      cout << endl;
   }
private:
   long  x_, y_, w_;
   char  ch_;
};

class Label : public Gadget {
public:
   Label( int col, int row, int width ) : Gadget(col,row,width,'@') { }
};

class Edit : public Gadget {
public:
   Edit( int col, int row, int width ) : Gadget(col,row,width,'#') { }
};

void main( void ) {
   Gadget* list[] = {
      new Label( 10, 1, 5 ), new Label( 10, 4, 7 ), new Label( 10, 7, 9 ),
      new Edit( 16, 1, 9 ),  new Edit( 18, 4, 7 ),  new Edit( 20, 7, 5 )   };
   for (int i=0; i < 6; i++)
      list[i]->draw();
   for (i=0; i < 6; i++)
      delete list[i];
   cout << "\nsizeof Gadget is " << sizeof(Gadget) << endl;
   cout << "sizeof Label is " << sizeof(Label) << endl;
}

//          @@@@@ #########
//          @   @ #       #
//          @@@@@ #########
//          @@@@@@@ #######
//          @     @ #     #
//          @@@@@@@ #######
//          @@@@@@@@@ #####
//          @       @ #   #
//          @@@@@@@@@ #####
//
// sizeof Gadget is 20
// sizeof Label is 20

#if 0
void main( void ) {
   Gadget*  list[6];
   list[0] = Factory::getFlyweight( "label" );
   list[1] = Factory::getFlyweight( "label" );
   list[2] = Factory::getFlyweight( "label" );
   list[3] = Factory::getFlyweight( "edit" );
   list[4] = Factory::getFlyweight( "edit" );
   list[5] = Factory::getFlyweight( "edit" );
   for (int i=0; i < 3; i++)
      list[i]->draw( 10, i*3+1, i*2+5 );
   for (i=3; i < 6; i++)
      list[i]->draw( (i-3)*2+16, (i-3)*3+1, 9-(i-3)*2 );
   cout << "\nsizeof Gadget is " << sizeof(Gadget) << endl;
   cout << "sizeof Label is " << sizeof(Label) << endl;
}
#endif