/* Filename:  modemp.cpp

   Author:  Br. David Carlson

   Date:  February 5, 1998

   Revised:  March 11, 2001 to avoid modifying employee names, as that
   could change a sorted array into unsorted, thus making binary search
   unsuitable.

   Last Revised:  November 23, 2001

   This program uses the emp.dat binary file of employee records, as
   created by the makeemp program.  Specifically, this program lets
   the user repeatedly look up a given employee by name, displays the
   info on this employee, and then gives the user a chance to modify
   the ID and WageRate for this employee.  Any modified data is written
   back to the same emp.dat file.

   It is assumed that the emp.dat file is already sorted by the employee
   names (last name, then first name, of course).  If this is not the
   case, the lookup process is unlikely to work.  Thus one needs to
   either enter the data in order into the makeemp program or one needs
   to use a program (like sortemp) that sorts the emp.dat file.

   Tested with:
      Microsoft Visual C++ 6.0
      Microsoft Visual C++ .NET
      g++ under Linux
*/

#include <fstream>   // needed for files
#include "employee.h"  // needed for EmpType


/* Given:   EmpFile     A file stream already opened for input and output.
            Employee    An employee record containing the last name and
                        first name to search for.
   Assumes: That EmpFile is in ascending order.
   Task:    To do a binary search in EmpFile for Employee.
   Return:  EmpFile     The file stream (which can be modified by reading
                        and seeking in the file in that the file postion
                        pointer may be moved).
            Employee    If found, this parameter will contain the complete
                        record for the person looked up.
            Location    The location of the Employee record in the file
                        (as the number of bytes into EmpFile).
            SearchFile  In the function name, true is returned if Employee
                        was located, false otherwise.
*/
bool SearchFile(fstream & EmpFile, EmployeeType & Employee,
   long & Location)
   {
   EmployeeType EmployeeTemp;
   bool Found;
   int CmpResult;
   long Mid, Low, High, RecordSize;

   Found = false;
   Low = 0L;
   // Go to the end of the file:
   EmpFile.seekg(0L, ios::end);
   RecordSize = sizeof(EmployeeTemp);
   // Find the number of records and subtract 1:
   High = EmpFile.tellg() / RecordSize - 1L;

   while ((! Found) && (Low <= High))
      {
      Mid = (Low + High) / 2;
      Location = Mid * RecordSize;
      EmpFile.seekg(Location, ios::beg);
      EmpFile.read(reinterpret_cast <char *> (&EmployeeTemp), RecordSize);
      CmpResult = EmpCompare(Employee, EmployeeTemp);

      if (CmpResult == 0)
         {
         Employee = EmployeeTemp;
         Found = true;
         }
      else if (CmpResult < 0)
         High = Mid - 1L;
      else
         Low = Mid + 1L;
      }

   return Found;
   }


/* Given:   Employee  An employee record.
            EmpFile   A file stream, open for input and output.
            Location  The offset in EmpFile at which Employee can
                      be found.
   Task:    To allow the user to change the ID or WageRate in the Employee
            record, if desired, with the modified data being written
            to EmpFile.
   Return:  Employee  The (possibly) modified employee record.
            EmpFile   The modified file stream for the file of records.
*/
void Modify(EmployeeType & Employee, fstream & EmpFile, long Location)
   {
   char Choice;
   bool Modified = false;

   cout << endl << "Do you wish to modify the ID number (y/n)? ";
   cin >> Choice;
   if ((Choice == 'y') || (Choice == 'Y'))
      {
      Modified = true;
      cout << "Enter the corrected ID number: ";
      cin >> Employee.ID;
      }

   cout << endl << "Do you wish to modify the wage rate (y/n)? ";
   cin >> Choice;
   if ((Choice == 'y') || (Choice == 'Y'))
      {
      Modified = true;
      cout << "Enter the corrected wage rate: ";
      cin >> Employee.WageRate;
      }

   if (Modified)
      {
      EmpFile.seekp(Location, ios::beg);
      EmpFile.write(reinterpret_cast <char *> (&Employee),
         sizeof(Employee));
      }
   }


/* Given:   EmpFile   A binary file stream already opened for input
            and output.
   Task:    To allow the user to repeatedly look up an employee in
            EmpFile by name.  If the lookup succeeds, the info on the
            employee is displayed on the screen and the user is given
            a chance to modify the ID and WageRate for the employee.
   Return:  EmpFile   The modified file stream.
*/
void ProcessFile(fstream & EmpFile)
   {
   EmployeeType Employee;
   long Location;

   // change to CTRL d for Linux
   cout <<
      "Enter the last name of the employee to look up (CTRL z to quit)"
      << endl;
   cin >> Employee.LastName;

   while (! cin.fail())
      {
      cout << "Enter the first name of the employee to look up" << endl;
      cin >> Employee.FirstName;

      if (SearchFile(EmpFile, Employee, Location))
         {
         cout << endl;
         PrintEmployee(Employee);
         Modify(Employee, EmpFile, Location);
         }
      else
         cout << endl << "Not found" << endl;

      // change to CTRL d for Linux
      cout << endl <<
         "Enter the last name of the employee to look up (CTRL z to quit)"
         << endl;
      cin >> Employee.LastName;
      }
   }


int main(void)
   {
   fstream EmpFile;

   EmpFile.open("emp.dat", ios::in | ios::out | ios::binary);
   if (EmpFile.fail())
      {
      cerr << "Could not open file emp.dat" << endl;
      exit(1);
      }

   ProcessFile(EmpFile);
   EmpFile.close();

   return 0;
   }


