// ==========================================================================
// $Id: building_virt.cpp,v 1.5 2014/11/25 03:23:47 jlang Exp $
// CSI2372 example Code for lecture 7
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   SITE, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: building_virt.cpp,v $
// Revision 1.5  2014/11/25 03:23:47  jlang
// Updated lecture example.
//
// Revision 1.4  2014/11/25 00:08:04  jlang
// Update in class - Nov 2014
//
// Revision 1.3  2008/10/06 20:51:41  jlang
// Changed prices
//
// Revision 1.2  2008/09/13 01:36:52  jlang
// Minor clarifications arrays and operators
//
// Revision 1.1  2006/10/16 01:44:37  jlang
// small caps names
//
// Revision 1.1  2006/10/16 01:36:18  jlang
// Check in for lecture 7
//
//
// ==========================================================================
#include <iostream>
#include <vector>

// #define USE_POINTERS

using std::cout;
using std::endl;

class Building {
	double d_sqft; int d_noRooms;
  float d_price;
public:
  Building( double _sqft = 1000.0, int _noRooms = 3 ) :
    d_sqft( _sqft ), d_noRooms( _noRooms ), d_price( 0 ) {}
  int getNoRooms() { return d_noRooms; }
  void setPrice( float _price ) { d_price = _price; return; } 
  float getPrice() const { return d_price; }
  virtual float calculateTax() const { return d_price * 0.15f; }
protected:
  void setSqft( double _sqft ) { d_sqft = _sqft; }
};

class OfficeTower : public Building {
public:
  OfficeTower( double _sqft = 50000, int _noRooms = 50 ) 
    : Building( _sqft, _noRooms){}
  virtual float calculateTax() const { return getPrice() * 0.03f;}
};

class Cottage : public Building {
public:
  Cottage( double _sqft = 500, int _noRooms = 1 ) 
    : Building( _sqft, _noRooms){}
  virtual float calculateTax() const { return getPrice() * 0.06f;}
};

class House : public Building {
	int d_noOccu;
public:
  House( int _noOccu = 2 ) :d_noOccu( _noOccu ) {}
  virtual float calculateTax() const { return getPrice() * 0.07f;}
  int getNoOccupants() { return d_noOccu; };	
  int getNoRooms();
  void setSqft( double _sqft );  
};

int House::getNoRooms(){ 
  // Kitchen and Bathroom do not count
  return Building::getNoRooms() - 2;
}

void House::setSqft( double _sqft ) { 
  // max 1500 per person
  if ( _sqft/d_noOccu > 1500.0 ) { _sqft = 1500.0 * d_noOccu; }
  Building::setSqft( _sqft ); 
}


// Example showing that vectors hold copies
// Copy-ctor slices the sub-classes of Building
// Dynamic types are needed for virtual functions.
void do_not_use() 
{
  // Handles to different buildings
  Building *buildingA = new OfficeTower();
  Building *buildingB = new House();
  Building *buildingC = new Cottage();

  std::vector<Building> vBuild;
  // Prototype: void push_back (const Building& val);
  vBuild.push_back(*buildingA);
  vBuild.push_back(*buildingB);
  vBuild.push_back(*buildingC);

  // Set prices - through a reference to the element
  vBuild[0].setPrice( 100000 );
  vBuild[1].setPrice( 100000 );
  vBuild[2].setPrice( 100000 );

  // Each building should behave differently
  // use tax-rate for offices
  cout << "Tax for office: " <<  vBuild[0].calculateTax() << endl;
  // use tax-rate for homes
  cout << "Tax for House: " <<  vBuild[1].calculateTax() << endl;
  // use tax-rate for vac. homes
  cout << "Tax for Cottage: " <<  vBuild[2].calculateTax() << endl;
  // use tax-rate for vac. homes - works but price was not set
  cout << "Tax for Cottage: " <<  buildingC->calculateTax() << endl;

  delete buildingA;
  delete buildingB;
  delete buildingC;

  return;
}


#ifdef USE_POINTERS

int main() 
{
  // Handles to different buildings
  Building *buildingA = new OfficeTower();
  Building *buildingB = new House();
  Building *buildingC = new Cottage();

  // Set prices
  buildingA->setPrice( 100000 );
  buildingB->setPrice( 100000 );
  buildingC->setPrice( 100000 );

  // Each building should behave differently
  // use tax-rate for offices
  cout << "Tax for office: " <<  buildingA->calculateTax() << endl;
  // use tax-rate for homes
  cout << "Tax for House: " <<  buildingB->calculateTax() << endl;
  // use tax-rate for vac. homes
  cout << "Tax for Cottage: " <<  buildingC->calculateTax() << endl;

  delete buildingA;
  delete buildingB;
  delete buildingC;

  cout << "------------------------------------------" << endl;
  cout << "Do Not Use: " << endl;
  cout << "------------------------------------------" << endl;
  do_not_use();

  return 0;
}

#else

int main() 
{
  // Handles to different buildings
  OfficeTower tower;
  House aHouse;
  Cottage aCottage;
  Building& buildingA = tower;
  Building& buildingB = aHouse;
  Building& buildingC = aCottage;

  // Set prices
  buildingA.setPrice( 100000 );
  buildingB.setPrice( 100000 );
  buildingC.setPrice( 100000 );

  // Each building should behave differently
  // use tax-rate for offices
  cout << "Tax for office: " <<  buildingA.calculateTax() << endl;
  // use tax-rate for homes
  cout << "Tax for House: " <<  buildingB.calculateTax() << endl;
  // use tax-rate for vac. homes
  cout << "Tax for Cottage: " <<  buildingC.calculateTax() << endl;

  cout << "------------------------------------------" << endl;
  cout << "Do Not Use: " << endl;
  cout << "------------------------------------------" << endl;
  do_not_use();

  return 0;
}

#endif
