/* Program: Personal
 *
 * Project 1: Personal Department Information
 * author: Thoralf Czichy, Student#: 10956
*/

// include the required header files
#include <iostream.h>
#include <list.h>

// we're using the list namespace from the standard-library later on
using std::list;

/* function readLine()
 *   reads a "string" (char*) from cin and gives the result as return value
 *   memory is allocated according to the exact lenght of the string
*/
char* readLine(){

  char charBuffer[256]; // buffer with max 256 chars
  char *charReturn = 0; // pointer to an char
  int numberOfChars;    // holds the number of chars we've got from the user

  // empty the buffer
  cin.ignore(255,'\n');
  // read one line from cin and store it in charBuffer
  cin.getline(charBuffer,255);

  // reserve memory for the exact lenght of the data we've got from the user
  charReturn = new char[strlen(charBuffer)+1];

  // copy the user-string to that newly allocated memory
  strcpy(charReturn, charBuffer);

  // return the pointer to that "string"
  return charReturn;
} //end of function readLine()

/* Class Person
 *  serves as a base class for all other classes
*/
class Person{
  public:
   Person();
   virtual ~Person() {delete name;} // free the memory for member name
   virtual void const printData() = 0; // has to be overwritten by derived classes
   virtual bool const isEmployee() = 0; //has to be overwritten by derived classes
   virtual bool const isTemporary() = 0; //has to be overwritten by derived classes

  protected:
    char* name;
    int salary;
}; //end of class Person::Person

/* constructor Person::Person
 *  Asks for relevant data and initialize with it.
*/
Person::Person(){
  // ask for the name
  cout << "Name: ";
  name=readLine();

  // ask for the salary
  cout << "Salary: ";
  cin >> salary;
} //end of constructor Person::Person()

/* Class Employee
 *   Represents one employee.
*/
class Employee : virtual public Person{
  public:
    Employee();
    void const printData();

    //returns true, because it is an employee
    bool const isEmployee() {return true;}

    //returns false, because it is not a temporary
    bool const isTemporary() {return false;}

  protected:
    int department;
}; //end of class Employee

/* Constructor Employee:Employee
 *   Asks for relevant data and initializes with it.
*/
Employee::Employee(){
  // ask for the department of the employee
  cout << "Department: ";
  cin >> department;
}//end of constructor Employee::Employee()

/* function Employee::printData()
 *   Prints the data of that particular employee to cout
*/
void const Employee::printData(){
  cout << "EMPLOYEE:\n\tName: " << name << "\n\tDepartment: " << department <<
       "\n\tSalary: " << salary << endl;
} // end of function Employee::printData()

/* Class Manager
 *   Represents one manager
*/
class Manager : public Employee{
  public:
    Manager();
    void const printData();

  protected:
    int level;
}; // end of class Manager

/* Constructor Manager
 *   asks for relevant data and initializes with it.
*/
Manager::Manager(){
  // ask for the level of that manager
  cout << "Level: ";
  cin >> level;
} // end of constructor Manager:Manager


/* function Manager::printData()
 *   Prints the data of that particular manager to cout
*/
void const Manager::printData(){
  cout << "MANAGER:\n\tName: "<< name <<"\n\tDepartment: " << department <<
       "\n\tSalary: " <<salary <<"\n\tLevel: "<<level << endl;
} // end of function Manager::printData()

/* Class Director
 *   Represents one director
*/
class Director : public Manager{
  public:
    Director();
    virtual ~Director() {delete company;}// free the memory for member company
    void const printData();

  protected:
    char *company;
}; // end of class Director

/* Constructor Director
 *   asks for relevant data and initializes with it.
*/
Director::Director(){
  // ask for the company of that director
  cout << "Company: ";
  company=readLine();
} // end of constructor Director::Director


/* function Director::printData()
 *   Prints the data of that particular director to cout
*/
void const Director::printData(){
  cout << "DIRECTOR:\n\tName: "<< name <<"\n\tDepartment: " << department <<
       "\n\tSalary: " <<salary <<"\n\tLevel: "<<level<< "\n\tCompany: "<< company<< endl;
} // end of function Director::printData()

/* Class Temporary
 *   Represents one temorary
*/
class Temporary : virtual public Person{
  public:
    Temporary();
    virtual ~Temporary(){delete contractTime;}//free the memory for contractTime
    void const printData();

    //returns false, because it is not an employee
    bool const isEmployee() {return false;}

    //returns true, because it is a temporary
    bool const isTemporary() {return true;}

  protected:
    char *contractTime;
}; // end of class Temorary

/* Constructor Temporary
 *   asks for relevant data and initializes with it.
*/
Temporary::Temporary(){
  //ask for the contract time
  cout << "contract time: ";
  contractTime=readLine();
} // end of constructor Temporary::Temporary

/* function Temporary::printData()
 *   Prints the data of that particular temporary to cout
*/
void const Temporary::printData(){
  cout << "TEMPORARY:\n\tName: " <<name <<"\n\tContract time: "<<contractTime<<
       "\n\tSalary: "<<salary<<endl;
} // end of function Temprary::printData()


/* Class Secretary
 *   Represents one secretary. Is derived from Temporary and Employee.
 *   No additional constructor is needed because all the work is done by
 *   the constructors of the Super-classes.
*/
class Secretary: public Temporary, public Employee{
  public:
    void const printData();

    //returns true, because it is an employee
    bool const isEmployee() {return true;}

    //returns true, because it is a temporary
    bool const isTemporary() {return true;}

}; // end of class Secretary

/* function Secretary::printData()
 *   Prints the data of that particular secretary to cout
*/
void const Secretary::printData(){
  cout <<"SECRETARY:\n\tName: "<<name<<"\n\tDepartment: "<<department<<
       "\n\tSalary: "<<salary<<"\n\tContract time: "<<contractTime<<endl;
} // end of function Secretary::printData()

//define a new type Personslist, which allows us to store references to Persons
typedef list<Person*> PersonsList;

/* function addNewPersonsList
 *   Asks for the type of the new person, which is to be added.
 *   Depending on the type of person a new object of that type is created
 *   and is added to the personsList.
*/
void addNewPerson(PersonsList& personsList){

  int choice; // stores users choice

  //print first question
  cout << endl <<
       "(1) Temporary (2) Employee (3) Secretary " <<
       " (4) Manager (5) Director (6) Cancel" << endl;
  cout << "Your Choice: ";

  //get user input
  cin >> choice;

  // Depending on the user choice create the object and add it to personsList.
  // Because every object (Temporary, Employee, Secretary, Manager and Director)
  // is directly or indirectly derived from Person the new objects can be stored
  // in the PersonsList which takes references to Persons and its derivations
  switch (choice){
    case 1:
      personsList.push_back( new Temporary()); //create and store
      break;
    case 2:
      personsList.push_back( new Employee());
      break;
    case 3:
      personsList.push_back( new Secretary());
      break;
    case 4:
      personsList.push_back( new Manager());
      break;
    case 5:
      personsList.push_back( new Director());
      break;
    case 6:
      break;
  } //end of switch
} //end of function addNewPerson()

/* function main
 *   main program
*/
int main(){

  PersonsList personsList; //a list for storing the Persons

  int choiceMain = 0; // stores users choice
  int choiceListType = 0; //stores users choice
  int choiceNext = 0; // stores users choice

  // print out heading
  cout << "Personal Department Information" << endl << endl;

  // do oit again and again, until the user chooses Number 4
  for(;choiceMain!=4;){

    // print out what choices the user has
    cout << "(1) Insert (2) List (3) List-one by one (4) Cancel" <<endl;
    cout << "Your choice: ";

    // ask for users choice
    cin >> choiceMain;

    // depending on the choice do either insert a new person (1),
    // print a list (2,3) or do nothing (4 and everything else)
    switch (choiceMain){
      case 1:
        // add a new person
        addNewPerson(personsList);
        break;
      case 2:
      case 3:
        // print out what choices the user has
        cout << "(1) list of temporaries (2) list of employees (3) list all" <<endl;
        cout << "your choice: ";

        // ask for users choice
        cin >> choiceListType;

        // print list of persons. first go through the whole list
        // iP is the iterator
        for (PersonsList::iterator iP=personsList.begin();
              iP!=personsList.end(); ++iP) {
          // depending on the users choice only temporaries, only employees
          // or both will be printed
          switch (choiceListType){
            // call for each object in that list the printData()-function.
            // this will print the member-variables from the object.
            // depending on the actual type of the object there will be a
            // different output
            case 1: //only temporaries
              if ((*iP)->isTemporary()) //only if it's a temporary
                (*iP)->printData();
              break;
            case 2: //only employees
              if ((*iP)->isEmployee()) //only if it's a employee
                (*iP)->printData();
              break;
            case 3: //all persons
              (*iP)->printData();
              break;
          }

          // in case the user has choosen "(3) List one-by-one"
          if (choiceMain==3) {
            // the user is asked, whether he/she wants to see the next person
            // or skip the listing and get back to the main menu
            cout << "(1) next (2) cancel: ";
            cin >> choiceNext;

            // if the listing is to be skipped
            if (choiceNext==2) {

              // print a message that the user has skipped the list
              cout << "list manually ended"<<endl;

              // and leave the for-loop
              break;
            }// end of if
          }// end of if
        } // end of for

        // after printing all persons print out, that the end is reached
        cout << "end of list"<<endl;
        cout << endl;
        break;
    } // end of switch
  } // end of for

  // before leaving the program deallocate the memory used for the objects
  // therefore go through the list
  for (PersonsList::iterator iP=personsList.begin();
        iP!=personsList.end(); ++iP) {
    // and delete the objects - the destructors of the objects will be called
    delete(*iP);
  }
  // normal abortion of the program
  return 1;
} // end of function main()

