// Purpose.  Mediator design pattern lab
//
// Discussion.  In this design, each user "knows" its groups, and each group
// "knows" its users.  The many-to-many mapping between the User class and the
// Group class couples them together.  If we "objectified" this mapping rela-
// tionship several benefits would result: the two classes are no longer
// coupled, many mappings could be supported simply by creating many "mediator"
// instances, and the "mediator" abstraction could be refined through
// inheritance.
//
// Assignment.
// o The new main() and the Mediator implementation are provided.
// o Create a Mediator declaration.  It's state will include: array of 10 ptrs
//   to Group, array of 10 ptrs to User, totalGroups int, totalUsers int, 10x10
//   matrix of int for the "mapping".  It's behavior will include:
//   addUser(User*), addGroup(Group*), map(User*,Group*), reportUsers(Group*),
//   reportGroups(User*)
// o User::addGroup() and Group::addUser() have been moved to Mediator
// o User::groups_ and Group::users_ have been moved to Mediator
// o User and Group ctors need to accept a reference to the Mediator instance
// o User::reportGroups() and Group::reportUsers() now delegate to the Mediator

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

class Group;

class User {
public:
   User( char* );
   const char* getName();
   void addGroup( Group* );
   void reportGroups();
private:
   char    name_[15];
   Group*  groups_[10];
   int     total_;
};

class Group {
public:
   Group( char* );
   const char* getName();
   void addUser( User* );
   void reportUsers();
private:
   char   name_[15];
   User*  users_[10];
   int    total_;
};

User::User( char* name ) {
   strcpy( name_, name );
   total_ = 0;
}
const char* User::getName()                { return name_; }
void        User::addGroup( Group* group ) { groups_[total_++] = group; }
void User::reportGroups() {
   cout << "   " << name_ << ": ";
   for (int i=0; i < total_; i++)
      cout << ((i == 0) ? "" : ", ") << groups_[i]->getName();
   cout << endl;
}


Group::Group( char* name ) {
   strcpy( name_, name );
   total_ = 0;
}
const char* Group::getName()             { return name_; }
void        Group::addUser( User* user ) { users_[total_++] = user; }
void Group::reportUsers() {
   cout << "   " << name_ << ": ";
   for (int i=0; i < total_; i++)
      cout << ((i == 0) ? "" : ", ") << users_[i]->getName();
   cout << endl;
}

void main( void ) {
   User*     users[4];
   Group*    groups[4];
   users[0]  = new User(  "Kermit"      );
   users[1]  = new User(  "Gonzo"       );
   users[2]  = new User(  "Fozzy"       );
   users[3]  = new User(  "Piggy"       );
   groups[0] = new Group( "Green"       );
   groups[1] = new Group( "ColdBlooded" );
   groups[2] = new Group( "Male"        );
   groups[3] = new Group( "Muppets"     );

   for (int i=0; i < 4; i++)
      for (int j=0; j <= i; j++) {
         groups[i]->addUser( users[j] );
         users[j]->addGroup( groups[i] ); }

   cout << "Groups:" << endl;
   for (i=0; i < 4; i++) groups[i]->reportUsers();

   cout << "Users:" << endl;
   for (i=0; i < 4; i++) users[i]->reportGroups();

   for (i=0; i < 4; i++) { delete users[i];  delete groups[i]; }
}

// Groups:
//    Green: Kermit
//    ColdBlooded: Kermit, Gonzo
//    Male: Kermit, Gonzo, Fozzy
//    Muppets: Kermit, Gonzo, Fozzy, Piggy
// Users:
//    Kermit: Green, ColdBlooded, Male, Muppets
//    Gonzo: ColdBlooded, Male, Muppets
//    Fozzy: Male, Muppets
//    Piggy: Muppets

#if 0
Mediator::Mediator() {
   totalGroups_ = 0;
   totalUsers_  = 0;
   for (int i=0; i < 10; i++)
      for (int j=0; j < 10; j++)
         mappings_[i][j] = 0;
}
void Mediator::addUser( User* user ) {
   users_[totalUsers_++]   = user;
}
void Mediator::addGroup( Group* group ) {
   groups_[totalGroups_++] = group;
}

void Mediator::map( User* user, Group* group ) {
   int  i, j;
   for (i=0; i < totalGroups_; i++)
      if ( ! strcmp( groups_[i]->getName(), group->getName() ) )
         break;
   for (j=0; j < totalUsers_; j++)
      if ( ! strcmp( users_[j]->getName(), user->getName() ) )
         break;
   mappings_[i][j] = 1;
}
void Mediator::reportUsers( Group* g ) {
   int  i, j, first;
   for (i=0; i < totalGroups_; i++)
      if ( ! strcmp( groups_[i]->getName(), g->getName()))
         break;
   for (j=0, first=1; j < totalUsers_; j++)
      if (mappings_[i][j]) {
         cout << ((first) ? "" : ", ") << users_[j]->getName();
         first = 0;
      }
   cout << endl;
}
void Mediator::reportGroups( User* u ) {
   int  i, j, first;
   for (j=0; j < totalUsers_; j++)
      if ( ! strcmp( users_[j]->getName(), u->getName()))
         break;
   for (i=0, first=1; i < totalGroups_; i++)
      if (mappings_[i][j]) {
         cout << ((first) ? "" : ", ") << groups_[i]->getName();
         first = 0;
      }
   cout << endl;
}

void main( void ) {
   User*     users[4];
   Group*    groups[4];
   Mediator  mapping;
   users[0]  = new User(  "Kermit",      mapping );
   users[1]  = new User(  "Gonzo",       mapping );
   users[2]  = new User(  "Fozzy",       mapping );
   users[3]  = new User(  "Piggy",       mapping );
   groups[0] = new Group( "Green",       mapping );
   groups[1] = new Group( "ColdBlooded", mapping );
   groups[2] = new Group( "Male",        mapping );
   groups[3] = new Group( "Muppets",     mapping );

   for (int i=0; i < 4; i++) {
      mapping.addUser( users[i] );
      mapping.addGroup( groups[i] ); }

   for (i=0; i < 4; i++)
      for (int j=0; j <= i; j++)
         mapping.map( users[j], groups[i] );

   cout << "Groups:" << endl;
   for (i=0; i < 4; i++) groups[i]->reportUsers();

   cout << "Users:" << endl;
   for (i=0; i < 4; i++) users[i]->reportGroups();

   for (i=0; i < 4; i++) { delete users[i];  delete groups[i]; }
}
#endif