// Purpose.  Composite                  // Strategy.  Use recursive composition
                                        // to create a heterogeneous aggregate
#include <string.h>                     // that can be treated homogeneously.
enum NodeType { FileT, DirT };          //
int  g_indent = 0;                      // Benefit.  No more type checking and
                                        // type casting (coupling between Dir
class File {                            // and File is gone, Dir is only
public:                                 // coupled to abstract base class)
   File( char* n ) { type_ = FileT;
      strcpy( name_, n ); }             class AbsFile {
   NodeType getType() { return type_; } public:
   void ls() {                             virtual void ls() = 0;
      for (int i=0; i < g_indent; i++)  protected:
         cout << ' ';                      char        name_[20];
      cout << name_ << endl; }             static int  indent_;
private:                                };
   NodeType  type_;                     int AbsFile::indent_ = 0;
   char      name_[20];
};                                      class File: public AbsFile {
                                        public:
class Dir {                                File( char* n ) {
public:                                       strcpy( name_, n ); }
   Dir( char* n ) { type_ = DirT;          void ls() {
      strcpy( name_, n ); total_ = 0; }       for (int i=0; i < indent_; i++)
   NodeType getType() { return type_; }          cout << ' ';
   void add( File* f ) {                      cout << name_ << endl; }
      files_[total_++] = f;             };
   }
   void ls() {                          class Dir : public AbsFile {
      for (int i=0; i < g_indent; i++)  public:
         cout << ' ';                      Dir( char* n ) {
      cout << name_ << ":" << endl;           strcpy( name_, n ); total_ = 0; }
      g_indent += 3;                       void add( AbsFile* f ) {
      for (int i=0; i < total_; i++)          files_[total_++] = f; }
         if (files_[i]->getType()          void ls() {
               == DirT)                       for (int i=0; i < indent_; i++)
            ((Dir*) files_[i])->ls();            cout << ' ';
         else                                 cout << name_ << ":" << endl;
            files_[i]->ls();                  indent_ += 3;
      g_indent -= 3; }                        for (int i=0; i < total_; i++)
private:                                         files_[i]->ls();
   NodeType  type_;                           indent_ -= 3; }
   char      name_[20];                 private:
   File*     files_[10];                   AbsFile*  files_[10];
   int       total_;                       int       total_;
};                                      };

void main( void )                       void main( void )
{                                       {
   Dir   one("1"), two("2"), thr("3");     Dir   one("1"), two("2"), thr("3");
   File  a("a"), b("b"), c("c"),           File  a("a"), b("b"), c("c"),
         d("d"), e("e");                         d("d"), e("e");
   one.add( &a );                          one.add( &a );
   one.add( (File*) &two );                one.add( &two );
   one.add( &b );                          one.add( &b );
   two.add( &c );                          two.add( &c );
   two.add( &d );                          two.add( &d );
   two.add( (File*) &thr );                two.add( &thr );
   thr.add( &e );                          thr.add( &e );
   one.ls();                               one.ls();
}                                       }

// 1:          //       d               // 1:          //       d
//    a        //       3:              //    a        //       3:
//    2:       //          e            //    2:       //          e
//       c     //    b                  //       c     //    b




// Purpose.  Composite design pattern
//
// 1. Identify the scalar/primitive classes and vector/container classes
// 2. Create an "interface" (lowest common denominator) that can make all
//    concrete classes "interchangeable"
// 3. All concrete classes declare an "is a" relationship to the interface
// 4. All "container" classes couple themselves to the interface (recursive
//    composition, Composite "has a" set of children up the "is a" hierarchy)
// 5. "Container" classes use polymorphism as they delegate to their children

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

// 2. Create an "interface" (lowest common denominator)
class Component { public: virtual void traverse() = 0; };

class Leaf : public Component {        // 1. Scalar class   3. "isa" relationship
   int value;
public:
   Leaf( int val ) { value = val; }
   void traverse() { cout << value << ' '; }
};

class Composite : public Component {   // 1. Vector class   3. "isa" relationship
   vector<Component*> children;        // 4. "container" coupled to the interface
public:
   // 4. "container" class coupled to the interface
   void add( Component* ele ) { children.push_back( ele ); }
   void traverse() {
      for (int i=0; i < children.size(); i++)
         // 5. Use polymorphism to delegate to children
         children[i]->traverse();
}  };

void main( void ) {
   Composite containers[4];

   for (int i=0; i < 4; i++)
      for (int j=0; j < 3; j++)
         containers[i].add( new Leaf( i * 3 + j ) );

   for (i=1; i < 4; i++)
      containers[0].add( &(containers[i]) );

   for (i=0; i < 4; i++) {
      containers[i].traverse();
      cout << endl;
}  }

// 0 1 2 3 4 5 6 7 8 9 10 11
// 3 4 5
// 6 7 8
// 9 10 11




// Purpose.  Composite design pattern - multiple container classes

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

class Component { public: virtual void traverse() = 0; };

class Primitive : public Component {
   int value;
public:
   Primitive( int val ) { value = val; }
   void traverse()      { cout << value << "  "; }
};

class Composite : public Component {
   vector<Component*> children;
   int                value;
public:
   Composite( int val )     { value = val; }
   void add( Component* c ) { children.push_back( c ); }
   void traverse() {
      cout << value << "  ";
      for (int i=0; i < children.size(); i++)
          children[i]->traverse();
}  };

class Row : public Composite { public:     // Two different kinds of "con-
   Row( int val ) : Composite( val ) { }   // tainer" classes.  Most of the
   void traverse() {                       // "meat" is in the Composite
      cout << "Row";                       // base class.
      Composite::traverse();
}  };

class Column : public Composite { public:
   Column( int val ) : Composite( val ) { }
   void traverse() {
      cout << "Col";
      Composite::traverse();
}  };

void main( void ) {
      Row    first( 1 );                     // Row1
      Column second( 2 );                    //   |
      Column third( 3 );                     //   +-- Col2
      Row    fourth( 4 );                    //   |     |
      Row    fifth( 5 );                     //   |     +-- 7
      first.add( &second );                  //   +-- Col3
      first.add( &third  );                  //   |     |
      third.add( &fourth );                  //   |     +-- Row4
      third.add( &fifth  );                  //   |     |     |
      first.add(  &Primitive( 6 ) );         //   |     |     +-- 9
      second.add( &Primitive( 7 ) );         //   |     +-- Row5
      third.add(  &Primitive( 8 ) );         //   |     |     |
      fourth.add( &Primitive( 9 ) );         //   |     |     +-- 10
      fifth.add(  &Primitive(10 ) );         //   |     +-- 8
      first.traverse();  cout << '\n';       //   +-- 6
}

// Row1  Col2  7  Col3  Row4  9  Row5  10  8  6




// Purpose.  Composite and Prototype - lightweight persistence

#pragma warning( disable : 4786 )
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <fstream>
using namespace std;

class Component { public:
   virtual ~Component() { }
   virtual void       traverse() = 0;
   virtual Component* clone() = 0;
   virtual void       initialize( ifstream& ) = 0;
};

namespace Factory {
   map<string,Component*> hash;
   void add( string s, Component* c ) { hash[s] = c; }
   Component* makeComponent( string name ) { return hash[name]->clone(); }
}

class Leaf : public Component {
   string value;
public:
   ~Leaf()                           { cout << 'd' << value << ' '; }
   /*virtual*/ void       traverse() { cout << value << ' '; }
   /*virtual*/ Component* clone()    { return new Leaf(); }
   /*virtual*/ void       initialize( ifstream& is ) { is >> value; }
};

class Composite : public Component {
   vector<Component*> children;
   string             value;
public:
   ~Composite() {
      cout << 'd' << value << ' ';
      for (int i=0; i < children.size(); i++)
          delete children[i];
   }
   void add( Component* c ) { children.push_back( c ); }
   /*virtual*/ void traverse() {
      cout << value << ' ';
      for (int i=0; i < children.size(); i++)
          children[i]->traverse();
   }
   /*virtual*/ Component* clone() { return new Composite(); }
   /*virtual*/ void       initialize( ifstream& is ) {
      is >> value;
      string str, delim( "/"+value );
      is >> str;
      while (str != delim) {
         add( Factory::makeComponent( str ) );
         children[children.size()-1]->initialize( is );
         is >> str;
}  }  };

void main( void ) {
   Factory::add( "comp", new Composite() );
   Factory::add( "leaf", new Leaf() );
   ifstream is( "compositeCreate.txt" );
   string str;
   is >> str;
   Component* root = Factory::makeComponent( str );
   root->initialize( is );
   root->traverse();  cout << '\n';
   delete root;       cout << '\n';
}

/***
comp a leaf 1 comp b comp d leaf 8 leaf 9 /d leaf 4 comp e leaf 10
leaf 11 leaf 12 /e leaf 2 comp c leaf 5 leaf 6 leaf 7 /c /b leaf 3 /a
***/

// a 1 b d 8 9 4 e 10 11 12 2 c 5 6 7 3
// da d1 db dd d8 d9 d4 de d10 d11 d12 d2 dc d5 d6 d7 d3