// Purpose.  Strategy                   #include <iostream.h>
//                                      #include <stdlib.h>
// Discussion.  The class Stat has a    #include <time.h>
// Bubble sort algorithm hard-wired in
// it.  It would be nice if the choice  class SortImp;
// of algorithm were configurable.
// The Strategy pattern suggests "de-   class Stat {
// fine a family of algo's, encapsu-    public:
// late each one, and make them inter-     Stat();
// changeable" via an abstract base        void upGrade();
// class.                                  void downGrade();
                                           void readVector( int[], int );
class Stat {     /* Bubble sort */         int getMin() { return min_; }
public:                                    int getMax() { return max_; }
   void readVector( int v[], int n ) {     int getMed() { return med_; }
      sort_( v, n );                    private:
      min_ = v[0];   max_ = v[n-1];        int min_, max_, med_;
      med_ = v[n/2]; }                     SortImp*  imp_;
   int getMin() { return min_; }        };
   int getMax() { return max_; }
   int getMed() { return med_; }        class SortImp { public:
private:                                   virtual void sort( int[], int ) = 0;
   int min_, max_, med_;                };
   void sort_( int v[], int n ) {
      for (int i=n-1; i > 0; i--)       class SortBubble : public SortImp {
         for (int j=0; j < i; j++)      public:
            if (v[j] > v[j+1]) {           void sort( int v[], int n );
               int t = v[j];            };
               v[j] = v[j+1];
               v[j+1] = t; }            class SortShell : public SortImp {
      cout << "Bubble: ";               public:
      for (int k=0; k < n; k++)            void sort( int v[], int n );
         cout << v[k] << ' ';           };
      cout << endl;
   }                                    #include "strategy2.inc"
};
                                        Stat::Stat() { imp_ = new SortBubble; }
void main( void )                       void Stat::upGrade()   { delete imp_;
{                                          imp_ = new SortShell; }
   const int NUM = 9;                   void Stat::downGrade() { delete imp_;
   int       array[NUM];                   imp_ = new SortBubble; }
   time_t    t;                         void Stat::readVector(int v[], int n) {
   srand((unsigned) time(&t));             imp_->sort( v, n );
   cout << "Vector: ";                     min_ = v[0];   max_ = v[n-1];
   for (int i=0; i < NUM; i++) {           med_ = v[n/2]; }
      array[i] = rand() % 9 + 1;
      cout << array[i] << ' '; }        void main( void )
   cout << endl;                        {
                                           const int NUM = 9;
   Stat  obj;                              int       array[NUM];
   obj.readVector( array, NUM );           time_t    t;
   cout << "min is " << obj.getMin()       srand((unsigned) time(&t));
      << ", max is " << obj.getMax()       cout << "Vector: ";
      << ", median is " << obj.getMed()    for (int i=0; i < NUM; i++) {
      << endl;                                array[i] = rand() % 9 + 1;
}                                             cout << array[i] << ' '; }
                                           cout << endl;
/***** current implementation *****/
// Vector: 6 9 9 8 6 5 7 9 2               Stat  obj;
// Bubble: 2 5 6 6 7 8 9 9 9               obj.upGrade();
// min is 2, max is 9, median is 7         obj.readVector( array, NUM );
/*** an upgraded implementation ***/       cout << "min is " << obj.getMin()
// Vector: 4 8 6 4 6 7 4 7 2                  << ", max is " << obj.getMax()
// Shell:  2 4 4 4 6 6 7 7 8                  << ", median is " << obj.getMed()
// min is 2, max is 8, median is 6            << endl;
                                        }


// Purpose.  Strategy (template         #include <iostream>
//                     approach)        #include <cstdlib>
// A template can be used to configure  #include <ctime>
// a client with a Strategy.  This      using namespace std;
// technique is appropriate if: 1) the
// Strategy can be selected at com-     template<class STRATEGY>
// pile-time, and 2) it does not have   class Stat {
// to be changed at run-time.  With a   public:
// template, there is no need to spe-      void readVector( int v[], int n ) {
// cify the interface in a SortImp            imp_.sort( v, n );
// base class.  The Stat class now has        min_ = v[0];   max_ = v[n-1];
// an instance of the sort object, in-        med_ = v[n/2]; }
// stead of a ptr to the base class.       int getMin() { return min_; }
// The inheritance approach offers         int getMax() { return max_; }
// more options and expressiveness.        int getMed() { return med_; }
// The template approach offers mildly  private:
// better efficiency.                      int       min_, max_, med_;
                                           STRATEGY  imp_;
class Stat {     /* Bubble sort */      };
public:
   void readVector( int v[], int n ) {  class SortBubble {
      sort_( v, n );                    public:
      min_ = v[0];   max_ = v[n-1];        void sort( int v[], int n );
      med_ = v[n/2]; }                  };
   int getMin() { return min_; }
   int getMax() { return max_; }        class SortShell {
   int getMed() { return med_; }        public:
private:                                   void sort( int v[], int n );
   int min_, max_, med_;                };
   void sort_( int v[], int n ) {
      for (int i=n-1; i > 0; i--)       #include "strategy2.inc"
         for (int j=0; j < i; j++)
            if (v[j] > v[j+1]) {        void main( void ) {
               int t = v[j];               const int NUM = 9;
               v[j] = v[j+1];              int       array[NUM];
               v[j+1] = t; }               time_t    t;
      cout << "Bubble: ";                  srand((unsigned) time(&t));
      for (int k=0; k < n; k++)            cout << "Vector: ";
         cout << v[k] << ' ';              for (int i=0; i < NUM; i++) {
      cout << endl;                           array[i] = rand() % 9 + 1;
   }                                          cout << array[i] << ' '; }
};                                         cout << endl;

void main( void ) {                        Stat<SortBubble>  obj;
   const int NUM = 9;                      obj.readVector( array, NUM );
   int       array[NUM];                   cout << "min is " << obj.getMin()
   time_t    t;                               << ", max is " << obj.getMax()
   srand((unsigned) time(&t));                << ", median is " << obj.getMed()
   cout << "Vector: ";                        << endl;
   for (int i=0; i < NUM; i++) {
      array[i] = rand() % 9 + 1;           Stat<SortShell>  two;
      cout << array[i] << ' '; }           two.readVector( array, NUM );
   cout << endl;                           cout << "min is " << two.getMin()
                                              << ", max is " << two.getMax()
   Stat  obj;                                 << ", median is " << two.getMed()
   obj.readVector( array, NUM );              << endl;
   cout << "min is " << obj.getMin()    }
      << ", max is " << obj.getMax()
      << ", median is " << obj.getMed() // Vector: 3 5 4 9 7 1 4 9 2
      << endl;                          // Bubble: 1 2 3 4 4 5 7 9 9
}                                       // min is 1, max is 9, median is 4
                                        // Shell:  1 2 3 4 4 5 7 9 9
// Vector: 6 9 9 8 6 5 7 9 2            // min is 1, max is 9, median is 4
// Bubble: 2 5 6 6 7 8 9 9 9
// min is 2, max is 9, median is 7



// Purpose.  Strategy design pattern demo
//
// Discussion.  The Strategy pattern suggests: encapsulating an algorithm
// in a class hierarchy, having clients of that algorithm hold a pointer
// to the base class of that hierarchy, and delegating all requests for
// the algorithm to that "anonymous" contained object.  In this example,
// the Strategy base class knows how to collect a paragraph of input and
// implement the skeleton of the "format" algorithm.  It defers some
// details of each individual algorithm to the "justify" member which is
// supplied by each concrete derived class of Strategy.  The TestBed class
// models an application class that would like to leverage the services of
// a run-time-specified derived "Strategy" object.

#include <iostream.h>
#include <fstream.h>
#include <string.h>

class Strategy;

class TestBed {
public:
   enum StrategyType { Dummy, Left, Right, Center };
   TestBed()         { strategy_ = NULL; }
   void setStrategy( int type, int width );
   void doIt();
private:
   Strategy*  strategy_;
};

class Strategy {
public:
   Strategy( int width ) : width_( width ) { }
   void format() {
      char line[80], word[30];
      ifstream  inFile( "quote.txt", ios::in );
      line[0] = '\0';

      inFile >> word;
      strcat( line, word );
      while (inFile >> word)
      {
         if (strlen(line) + strlen(word) + 1 > width_)
            justify( line );
         else
            strcat( line, " " );
         strcat( line, word );
      }
      justify( line );
   }
protected:
   int     width_;
private:
   virtual void justify( char* line ) = 0;
};

class LeftStrategy : public Strategy {
public:
   LeftStrategy( int width ) : Strategy( width ) { }
private:
   /* virtual */ void justify( char* line ) {
      cout << line << endl;
      line[0] = '\0'; }
};

class RightStrategy : public Strategy {
public:
   RightStrategy( int width ) : Strategy( width ) { }
private:
   /* virtual */ void justify( char* line ) {
      char  buf[80];
      int   offset = width_ - strlen( line );
      memset( buf, ' ', 80 );
      strcpy( &(buf[offset]), line );
      cout << buf << endl;
      line[0] = '\0'; }
};

class CenterStrategy : public Strategy {
public:
   CenterStrategy( int width ) : Strategy( width ) { }
private:
   /* virtual */ void justify( char* line ) {
      char  buf[80];
      int   offset = (width_ - strlen( line )) / 2;
      memset( buf, ' ', 80 );
      strcpy( &(buf[offset]), line );
      cout << buf << endl;
      line[0] = '\0'; }
};

void TestBed::setStrategy( int type, int width ) {
   delete strategy_;
   if      (type == Left)   strategy_ = new LeftStrategy( width );
   else if (type == Right)  strategy_ = new RightStrategy( width );
   else if (type == Center) strategy_ = new CenterStrategy( width ); }

void TestBed::doIt() { strategy_->format(); }

void main() {
   TestBed  test;
   int      answer, width;
   cout << "Exit(0) Left(1) Right(2) Center(3): ";
   cin >> answer;
   while (answer)
   {
      cout << "Width: ";
      cin >> width;
      test.setStrategy( answer, width );
      test.doIt();
      cout << "Exit(0) Left(1) Right(2) Center(3): ";
      cin >> answer;
   }
   return 0;
}

// Exit(0) Left(1) Right(2) Center(3): 2
// Width: 75
//       The important lesson we have learned is that development for reuse is
//  complex. If making a good design is difficult, then making a good reusable
//         design is even harder, and any amount of process description cannot
// substitute for the skill, imagination, and experience of a good designer. A
// process can only support the creative work, and ensure that things are done
//                             and recorded properly. [Karlsson et al, REBOOT]
// Exit(0) Left(1) Right(2) Center(3): 3
// Width: 75
//    The important lesson we have learned is that development for reuse is
// complex. If making a good design is difficult, then making a good reusable
//     design is even harder, and any amount of process description cannot
// substitute for the skill, imagination, and experience of a good designer. A
// process can only support the creative work, and ensure that things are done
//               and recorded properly. [Karlsson et al, REBOOT]