// OMD.cpp
// Data Model Demonstration using Bonsai. A bonsai is a non-empty set of trees
// in a bonsai pot. The term "bonsai" is both singular and plural.
// Version 1.03.
// Copyright 1999 by Rick Wagner, all rights reserved. Authorized use with
// attribution for educational purposes only.
// Created September 25, 1999.
// Last edited September 26, 1999.

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

const char* sVerNum = "Version 1.03";

// Class for the living organism that is a part of bonsai:
class Tree
{
public:
  Tree(char* name = "", char* species = "",         // Default and parameter constructor.
       void* partOf = NULL);
  ~Tree();                                          // Destructor.

  char* getName();                                  // Accessors.
  char* getSpecies();
  void* getPartOf();

  void setName(char* name);                         // Mutators.
  void setSpecies(char* species);
  void setPartOf(void* bonsai);

private:
  char* _name;
  char* _species;
  void* _partOf;                                    // Cast to Bonsai* later.
};

// Class for the inanimate object that is a part of bonsai:
class Pot
{
public:
  Pot(float size = 0, char* style = "", char* color = "",
      char* country = "", void* partOf = NULL);     // Default and parameter constructor.
  ~Pot();                                           // Destructor.

  float getSize();                                  // Accessors.
  char* getStyle();
  char* getColor();
  char* getCountry();
  void* getPartOf();

  void setSize(float size);                         //Mutators.
  void setStyle(char* style);
  void setColor(char* color);
  void setCountry(char* country);
  void setPartOf(void* bonsai);

private:
  float _size;
  char* _style;
  char* _color;
  char* _countryOfOrigin;
  void* _partOf;                                    // Cast to Bonsai* later.
};

// Container class for an assembly consisting of a pot and a set of trees:
class Bonsai
{
public:
  Bonsai(char* label = "");                         // Default constructor.
  ~Bonsai();                                        // Destructor.

  char* getLabel();                                 // Accessors.
  Pot* getPot();
  int getNumTrees();
  Tree* getTree(int i);

  void setPot(Pot* pot);                            //Mutators.
  void addTree(Tree* tree);
  void removeTree(Tree* tree);

private:
  char* _label;                                     // Label for the bonsai.
  Pot* _pot;                                        // Pointer to some bonsai pot.
  int _numTrees;                                    // Number of trees in the bonsai.
  Tree** _tree;                                     // Pointer to an array of tree pointers.
};

// Class function implementations:
// Class Tree member functions:
Tree::Tree(char* name, char* species, void* partOf) // Constructor
{
  _name = new char[strlen(name) + 1];
  strcpy(_name, name);
  _species = new char[strlen(species) + 1];
  strcpy(_species, species);
  _partOf = partOf;
}

Tree::~Tree()                                       // Destructor
{
  delete [] _name;
  delete [] _species;
}

char* Tree::getName()                               // Accessors
{
  return _name;
}

char* Tree::getSpecies()
{
  return _species;
}

void* Tree::getPartOf()
{
  return (Tree*) _partOf;
}

void Tree::setPartOf(void* bonsai)                  // Mutator.
{
  _partOf = bonsai;
}


// Pot class member functions:
Pot::Pot(float size, char* style, char* color,      // Constructor.
         char* country, void* partOf)
{
  _size = size;
  _style = new char[strlen(style) + 1];
  strcpy(_style, style);
  _color = new char[strlen(color) + 1];
  strcpy(_color, color);
  _countryOfOrigin = new char[strlen(country) + 1];
  strcpy(_countryOfOrigin, country);
  _partOf = partOf;
}

Pot::~Pot()                                         // Destructor.
{
  delete [] _style;
  delete [] _color;
  delete [] _countryOfOrigin;
}

float Pot::getSize()                                // Accessors
{
  return _size;
}

char* Pot::getStyle()
{
  return _style;
}

char* Pot::getColor()
{
  return _color;
}

char* Pot::getCountry()
{
  return _countryOfOrigin;
}

void* Pot::getPartOf()
{
  return _partOf;
}

void Pot::setSize(float size)                          // Mutators
{
  _size = size;
}

void Pot::setStyle(char* style)
{
  _style = style;
}

void Pot::setColor(char* color)
{
  _color = color;
}

void Pot::setCountry(char* country)
{
  _countryOfOrigin = country;
}

void Pot::setPartOf(void* bonsai)
{
  _partOf = bonsai;
}

// Class Bonsai member functions:
Bonsai::Bonsai(char* label)                          // Constructor
{
  int i = 0;
  _label = new char[strlen(label) + 1];
  strcpy(_label, label);
  _pot = NULL;
  _numTrees = 0;
  _tree = new Tree*[100];
  for (i = 0; i < 100; i++)
  {
    _tree[i] = NULL;                                 // For good housekeeping.
  }
}


Bonsai::~Bonsai()                                    // Destructor.
{
  delete [] _label;
  delete [] _tree;
  cout << " *Kaboom* ";
}

char* Bonsai::getLabel()                             // Accessors.
{
  return _label;
}

Pot* Bonsai::getPot()
{
  return _pot;
}

int Bonsai::getNumTrees()
{
  return _numTrees;
}

Tree* Bonsai::getTree(int i)
{
  return _tree[i];
}

void Bonsai::setPot(Pot* pot)
{
  _pot = pot;
  pot->setPartOf((void*) this);
}

void Bonsai::addTree(Tree* tree)                     // Mutator.
{
  _tree[_numTrees] = tree;
  _numTrees++;
  tree->setPartOf((void*) this);
}

void Bonsai::removeTree(Tree* tree)
{
  int i = 0;
  int j = 0;
  bool foundTree = 0;

  for (i = 0; i < _numTrees; i++)
  {
    if (_tree[i] == tree)                            // Comparing pointers.
    {
      foundTree = 1;
      _numTrees--;                                   // Straighten out the bookkeeping.
      tree->setPartOf(NULL);                         // Let the tree know it's no longer
                                                     // part of a bonsai.
      for (j = i; j < _numTrees; j++)
      {
        _tree[j] = _tree[j+1];                       // Compact the array.
      }
      break;                                         // Break out of for().
    }
  }
}

// Other function prototypes:
void BonsaiTest1(Bonsai* b1);                        // Demonstrate passing by pointer.
void BonsaiTest2(Bonsai* b2);                        // Demonstrate passing by pointer.

void main()                                          // Automated test sequence (ATS)
{
  Tree* t1;                                          // Declare some trees.
  Tree* t2;
  Tree* t3;
  Tree* t4;
  Pot* p1;                                           // Declare some pots.
  Pot* p2;
  Bonsai* b1;                                        // Declare some bonsai.
  Bonsai* b2;

  // Construct some trees, pots, and bonsai for test:
  t1 = new Tree("Gnarly Old Oak", "Cork oak");
  t2 = new Tree("Curvey Old Oak", "Cork oak");
  t3 = new Tree("Straight Old Oak", "Cork oak");
  t4 = new Tree("Ancient Juniper", "Prostrata juniper");

  p1 = new Pot(16, "Oval", "Brown", "China");
  p2 = new Pot(13, "Rectangular", "Gray", "Japan");

  b1 = new Bonsai("Cork Oak Forest");
  b2 = new Bonsai("Venerable Shokan Juniper");

  // Assign trees and pots to bonsai:
  b1->setPot(p1);
  b1->addTree(t1);
  b1->addTree(t2);
  b1->addTree(t3);

  b2->setPot(p2);
  b2->addTree(t4);

  // Pass "bonsai one" by pointer:
  BonsaiTest1(b1);

  // Pass "bonsai two" by pointer:
  BonsaiTest2(b2);
}

// Demonstrate pointer passing:
void BonsaiTest1(Bonsai* b1)
{
  int i = 0;
  Tree* t1 = b1->getTree(0);
  Tree* t2 = b1->getTree(1);
  Tree* t3 = b1->getTree(2);
  Pot* p1 = b1->getPot();

  cout << sVerNum << ": Bonsai one uses an " << p1->getStyle()
       << " " << p1->getColor()
       << " " << p1->getCountry() << " pot." << endl << endl;

  cout << "Bonsai one has the following " << b1->getNumTrees() << " trees:" << endl;
  for (i = 0; i < b1->getNumTrees(); i++)
  {
    cout << b1->getTree(i)->getName() << endl;
  }
  
  cout << endl << t1->getName() << " is part of "
       << ((Bonsai*) t1->getPartOf())->getLabel() << endl
       << "The " << p1->getStyle() << " "
       << p1->getColor() << " "
       << p1->getCountry() << " pot is part of "
       << ((Bonsai*) p1->getPartOf())->getLabel()
       << endl << endl;

  // Test the Bonsai::removeTree() function:
  //b1->removeTree(t2);
  //cout << "Bonsai one has the following " << b1->getNumTrees() << " trees:" << endl;
  //for (i = 0; i < b1->getNumTrees(); i++)
  //{
  //  cout << b1->getTree(i)->getName() << endl;
  //}
  //cout << endl << "Tree " << t2->getName() << " is part of (Bonsai pointer ==) "
  //     << t2->getPartOf() << "."<< endl;

  delete b1;                                             // Test the destructor;
  cout << "Bonsai one has been destroyed but the trees still exist:" << endl
       << "t1: " << t1->getName() << endl
       << "t2: " << t2->getName() << endl
       << "t3: " << t3->getName() << endl << endl << endl;
}

void BonsaiTest2(Bonsai* b2)
{
  int i = 0;

  Tree* t4 = b2->getTree(0);
  Pot* p2 = b2->getPot();

  cout << "Bonsai two uses a " << b2->getPot()->getStyle()
       << " " << b2->getPot()->getColor()
       << " " << b2->getPot()->getCountry() << " pot." << endl << endl;

  cout << "Bonsai two has the following trees:" << endl;
  for (i = 0; i < b2->getNumTrees(); i++)
  {
    cout << b2->getTree(i)->getName() << endl;
  }
  
  cout << endl << t4->getName() << " is part of "
       << ((Bonsai*) t4->getPartOf())->getLabel() << endl
       << "The " << p2->getStyle() << " "
       << p2->getColor() << " "
       << p2->getCountry() << " pot is part of "
       << ((Bonsai*) p2->getPartOf())->getLabel()
       << endl << endl;

  delete b2;
}
