// Object-Oriented Technology: Payroll project source

/*************************************************

Author: Jeff Zhuk

Date: 07/03/95

Module: payroll.cpp

  Description:
	This module is the main program for the PAYROLL project.
	It presents EMPLOYEE - related menu and prompts the user for
	a proper selection:
		1.  Load the payroll database file.
 		2.  Add an employee to the database.
 		3.  Remove an employee from the database.
   		4.  Save the employee database into a file.
  		5.  Display all the employee data. 
   		6.  Exit.
	There are several types of EMPLOYEE that get paid differently: 
		Manager - gets its salary any way
		Hourly  - paid by worked hours
		Sales	- paid by hours plus percent of total sale

Different employee types have slightly different data attributes.  
Each attribute for simplicity takes one line of characters.
The first attribute in an employee record reflects an employee type.
The employee database file is a text file, 
that can be displayed and printed by any editor.
All the Employees are connected with a Linked List
It means that each Employee (no matter what type) 
has a pointer to the NEXT Employee.
********************************************************/
#include < iostream.h>
#include < conio.h>
#include < stdio.h>
#include < string.h>
#include < ctype.h>

#include "employee.h"
#include "hourly.h"
#include "sales.h"
#include "manager.h"

Employee *head=NULL; // Head pointer to the Linked List. 
// It must be unique, static and accessible throughout the program

// 5 modules implementing 5 Use cases 
int LoadDatabase(); // returns number of employees loaded
void AddEmployee(); // adds an Employee to the list of employees
void RemoveEmployee();
void DisplayEmployees();
int SaveDatabase();  // returns number of employees saved

// A Module used by all scenarios to create a new employee
Employee* NewEmployee(char* employeeType); // Instantiates Employee of
					// a proper type and returns a pointer 

int main() // argc and argv can be used to provide database file name
{
	int done = 0;       // to indicate the user selected EXIT
	int counter;
	char buf[80]="";        // input string buffer

	while(!done)
	{		// Display the PAYROLL database actions menu

		cout << "\nWelcome to the PAYROLL application" << endl;
		cout << "    1. Load payroll.txt database file.\n";
		cout << "    2. Add an employee to the database.\n";
		cout << "    3. Remove an employee from the database.\n";
		cout << "    4. Display all the employees loaded.\n";
		cout << "    5. Save the database into payroll.txt file.\n";
		cout << "    6. Exit.\n";

		// Prompt for desired action

		cout << "\nEnter the number of the desired action: ";

		// Get the number of the desired action
		// It expects any characters (but not just BLANK) and ENTER

		cin >> buf; // Integer can be used here, but a user (smart one)
			    // can enter non-digit character to puzzle "cin"	
        
        cin.ignore(1);
		// Determine the desired action and invoke the function

		switch (buf[0]) 	// The first character is analysed
		{		// to recognize the user selection
			case '1': counter = LoadDatabase();
			cout << "\nLoaded records=" << counter;
			break;
			case '2': AddEmployee();
			break;
		  	case '3': RemoveEmployee();
			break;
			case '4': DisplayEmployees();
			break;
			case '5': counter = SaveDatabase();
			cout << "\nWritten records=" << counter;
			break;
			case '6': done = 1; // EXIT
			break; 
		
			default: cout << "\nInvalid action. Please re-enter\n" ;
		}
	}	// Keep prompting until EXIT
	return done;
}
/********************************* int LoadDatabase() ********************
The function reads database file if Employee Linked List is empty (head==NULL).
File can include all the Employee type records.
Employee Type attribute and Employee* NewEmployee() function are used
to recognize and make an instance of a proper employee type object.
Then 	newEmp->Read() 	- polymorphic statement is used
to read a proper record structure.
**************************************************************************/
// 
int LoadDatabase()
{
	FILE *fp;
	Employee *newEmp;
	Employee *previousEmp=NULL;
	char empType[80]="";
	int counter=0;

	if(head) { // head pointer is not NULL, something is already loaded
		cout << "\nDatabase already loaded/created" ;
		return 0;
	}
	if((fp = fopen("payrol.txt", "r")) == NULL)  { // can not open
		cout << "\nError opening file: payrol.txt \n";
		return 0;
	}
	// read the file
	for(counter=0;fgets(empType,80,fp);counter++) {  // read empType
		if(feof(fp))	// check for End Of File
			break;
		newEmp = NewEmployee(empType); // Employee of proper type
		if (newEmp==NULL) {   // wrong type
			fclose(fp);	// Error, stop reading
			return counter; // return from here
		}
		newEmp->Read(fp);   // read the rest of the record
					// using proper Read() polymorphically
		// make a Linked List

		if(head==NULL)		// set head pointer for a Linked List
			head = newEmp;
		else
			previousEmp->SetNext(newEmp); // set Next pointer
		previousEmp = newEmp;	    // for a previous Employee
	}				// using Employee::SetNext
	fclose(fp);
	return counter;
}



Employee* NewEmployee(char* empType) // Instantiates Employee of proper type
{				     // and returns a pointer to it	
	Employee* newEmp=NULL;

	switch(empType[0]) // what type of employee is this
	{					// Constructor works here
		case 'M': newEmp = new Manager;	// Manager::Manager()
					break;
		case 'H': newEmp = new Hourly;	// Hourly::Hourly()
					break;
		case 'S': newEmp = new Sales; 	// Sales::Sales()
					break;
		default: cout << "\nUnknown type of Employee=" << empType;
	}
	return newEmp;	// the pointer will be NULL for unknown Employee type
}

void AddEmployee() // Prompts for the Employee data, Instantiates a proper 
{		   // type of Employee and adds it to the Linked List
	char empType[80]="";
	Employee *newEmp=NULL;
	Employee *emp=NULL;
		// Prompt for desired employee type

	cout << "\nEnter type of Employee to add: M/H/S\n" ;
	cout << "M - for Manager; H - for Hourly or S - for Sales\n";

	cin >> empType;
	newEmp=NewEmployee(empType); // instantiate Employee of proper type
	if (newEmp != NULL)	 // do nothing if no Employee instantiated or
		newEmp->Add();	// Add proper Employee polymorphically
				// by prompting a user for all the data				
	// attach to a Linked List

	if(head==NULL)		// set head pointer for a Linked List
		head = newEmp;
	else {			//Find the last Employee on the list 
		for(emp = head; emp->GetNext() != NULL; emp = emp->GetNext());
		emp->SetNext(newEmp);  // set Next pointer to the new Employee
	}	// SetNext() and etNext() methods are defined in Employee (base) class	            
}




void RemoveEmployee()   // Prompts a user for SSN, then finds and
{		            	// removes the Employee. Preserves Linked List integrity.
	Employee *emp=NULL;    		// current Employee on the List
	Employee *previousEmp=NULL;	// previous Employee on the List
	char ssn[10];

	cout << "\nEnter social security number of the employee: ";
	cin >> ssn;
	for(emp = head; emp != NULL; emp = emp->GetNext() ) { // search through
		if( strcmp(ssn,emp->GetSSN()) == 0) { // the Linked List for SSN
		// when found, first switch the pointers
		// to preserve  Linked List integrity
			if (emp == head)  // if it is first in the Linked List
				head = emp->GetNext(); // shift head pointer 
			if(previousEmp != NULL)
				previousEmp->SetNext(emp->GetNext());

			delete emp; 	// delete the object now
			break;	
		}
		previousEmp = emp;	// store the pointer for the next cycle
	}				// when it will serve as previous one
	if( emp == NULL )
		cout << "\nCan not find Employee with SSN=" << ssn;	
}		

int SaveDatabase() 	// search through the Linked List and
{			// saves each Employee of a proper type polymorphically
	FILE *fp;
	Employee *emp;
	int counter=0;

	if( head == NULL) {
		cout << "\nThere is nothing to save. \n";
		return 0;
	}
	// open the file
	if ((fp = fopen("payrol.txt", "w")) == NULL) { // some problem
		cout << "\nCan not open payrol.txt file for writing";
		return 0;
	}
	// save the file
	for(emp = head; emp != NULL; emp = emp->GetNext() ) { // search through
		emp->Save(fp);			// Linked List and
		counter++;	// save each Employee polymorphically
	}
	fclose(fp);    // done, close the file
	return counter;
}
void DisplayEmployees() // Get all the Employees from the Linked List
{			// and display each type of Employee polymorphically 
	Employee  *emp;

	for(emp = head; emp != NULL; emp = emp->GetNext() )
	{
	 // search through
		emp->Display();			// Linked List and
				// display each Employee polymorphically
		cout << " Enter key to continue ...";
		cin.get();		
	}

}	

void DeleteEOL( char *str )
{
  str[ strlen( str ) -1 ] = '\0';
}                         
 
////////////////////////// employee.cpp ////////////////////////                

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

#include "employee.h"

void Employee::Read(FILE *fp)
{
  
  fgets (Ssn,80,fp);
  DeleteEOL( Ssn );
  fgets (Name,80,fp);
  DeleteEOL( Name );
  fgets (BirthDate,80,fp);
  DeleteEOL( BirthDate );
  fgets (HireDate,80,fp);  
  DeleteEOL( HireDate );
 }
  
void Employee::Save(FILE *fp)
{
  fprintf(fp, "%s\n", empType );
  fprintf(fp, "%s\n", Ssn );
  fprintf (fp, "%s\n", Name);
  fprintf (fp, "%s\n", BirthDate);
  fprintf (fp, "%s\n", HireDate);

 }
void Employee::SetNext(Employee *newEmp)
{
  this->next = newEmp;
}

Employee* Employee::GetNext()
{
  return this->next ;
}

void Employee::Add( void )
{
  
  cout << "  Enter Ssn  :";
  cin >> Ssn;
//  cout << endl;
  cout << "  Enter Name :";
  cin >> Name;
  cout << "  Birth date :";
  cin >> BirthDate;
  cout << "  Hire date  :";
  cin >> HireDate;

 }
void Employee::Display( void )
{
 cout << "  E m p l o y e e   : " << empType <

  
///////////////////////////////   employee.h    /////////////////////////////
#ifndef _EMPLOYEE_H_
#define _EMPLOYEE_H_ 

class Employee
{
protected:
	char empType[80];        
	char Ssn[80];
	char Name[80]; 
	char BirthDate[80];
	char HireDate[80];
	Employee *next; 

public:	
// functions 
    Employee() { next = NULL;}
    virtual void Read(FILE *pf);
    virtual void Add();
    virtual void Save(FILE *pf);
    virtual void Display();
    char 		*GetSSN(){ return Ssn;};
    Employee 	*GetNext();
    void    	SetNext(Employee *);
};
                                        
void DeleteEOL(char *); 
#endif                                
       
////////////////////////   hourly.cpp   /////////////////////////////
#include < iostream.h>
#include < stdio.h>
#include < string.h>

#include "hourly.h"

void Hourly::Read(FILE *fp)
{ 
  Employee::Read( fp ); 
  
  fgets (HourlyRate,80,fp);
  DeleteEOL( HourlyRate );
  fgets (WorkHours,80,fp);
  DeleteEOL( WorkHours );
 }

void Hourly::Save(FILE *fp)
{ 
  Employee::Save( fp ); 
  
  fprintf (fp, "%s\n", HourlyRate );
  fprintf (fp,"%s\n", WorkHours  );
 }


void Hourly::Add( void )  
{ 
  Employee::Add();
  cout << "  Enter Hourly rate :";
  cin >> HourlyRate;
  cout << "   Enter work hours :" ;
  cin >> WorkHours ;

}


void Hourly::Display( void )  
{ 
  Employee::Display();
  cout << "  HourlyRate  : " << HourlyRate << endl;
  cout << "  Work hours  : " << WorkHours  << endl;
}
//////////////////////////////////////   hourly.h     //////////////////
#ifndef _HOURLY_H_
#define _HOURLY_H_ 

#include "employee.h"

class Hourly : public Employee {  // Hourly worker paid by worked hours
	char  HourlyRate[80];
	char  WorkHours[80] ;
	
public:
	Hourly():Employee(){ strcpy( empType, "H" );};		
    virtual void Read(FILE *pf);
    virtual void Add();
    virtual void Save(FILE *pf);
    virtual void Display();
};       
    
#endif    

///////////////////////////////   manager.cpp    //////////////////////////
#include < iostream.h>
#include < stdio.h>
#include < string.h>

#include "manager.h"

void Manager::Read(FILE *fp)// : ( FILE *fp )  
{ 
  Employee::Read( fp );
  
  fgets (Salary,80,fp);
  DeleteEOL( Salary );
}
                          
  
void Manager::Save(FILE *fp)// : ( FILE *fp )  
{ 
  Employee::Save( fp );
  fprintf (fp, "%s\n", Salary);

  
}

void Manager::Add( void )  
{ 
  Employee::Add();
  cout << "  Enter Salary :";
  cin >> Salary;
}

void Manager::Display( void )  
{ 
  Employee::Display();
  cout << "  Salary     : " << Salary << endl;
}
///////////////////////////////////////   manager.h    ///////////////////////
#ifndef _MANAGER_H_ 
#define _MANAGER_H_

#include "employee.h"

class Manager : public Employee {      // Manager gets his salary any way
	char  Salary[80]  ; 
	
public:    
    Manager() : Employee(){ strcpy( empType, "M" );};
    virtual void Read(FILE *pf);
    virtual void Add();
    virtual void Save(FILE *pf);
    virtual void Display();
};
#endif
 
/////////////////////////   sales.cpp    ////////////////////////
#include < iostream.h>
#include < stdio.h>
#include < string.h>

#include "sales.h"

void Sales::Read(FILE *fp) 
{ 
  Hourly::Read( fp) ;
  fgets (TotalSale,80,fp);
  DeleteEOL( TotalSale );
  fgets (PercentPaid,80,fp);
  DeleteEOL( PercentPaid );
 } 

  

void Sales::Save(FILE *fp) 
{ 
  Hourly::Save( fp) ;
  fprintf( fp, "%s\n", TotalSale  );
  fprintf( fp, "%s\n", PercentPaid);
 } 


void Sales::Add( void )  
{ 
  Hourly::Add();
  cout << "   Enter total sale  :";
  cin >> TotalSale;
  cout << "   Enter percent paid:" ;
  cin >> PercentPaid ;
}

void Sales::Display( void )  
{ 
  Hourly::Display();
  cout << "  Total sale    :" << TotalSale << endl;
  cout << "  Percent paid  :" << PercentPaid << endl;
}
 
////////////////////////////   sales.h    ///////////////////////////
#ifndef _SALES_H_
#define _SALES_H_

#include "horly.h"

class Sales : public Hourly {    //Saler persen paid by worked hours + percent total sale
	char  TotalSale[80];
	char  PercentPaid[80];
			
public:
    Sales() : Hourly(){ strcpy( empType, "S" ); };
    virtual void Read(FILE *pf);        // read proper record structure
    virtual void Add();
    virtual void Save(FILE *pf);
    virtual void Display();
};
#endif