Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Bookstore Project The Project (Statement of Required Work with hints) To simplify your behavior diagrams, separate them according to the forms you will use one

Bookstore Project

The Project (Statement of Required Work with hints)

To simplify your behavior diagrams, separate them according to the forms you will use one set of diagrams for each form. Please try to keep your diagrams neat, uncluttered, but as detailed as needed to complete the project.

The Underlying Layer of Classes As summarized below, these classes must contain every piece of data and every method required to make your system work properly. The only way to figure out what goes in these classes is to maintain a list of attributes, properties, and methods that are needed based on the details of your behavior diagram. I will map out an outline of what is required here. You will need to do the rest, including completing the descriptions of the attributes, properties, and methods I have listed here (or those that you used). When you write your code, I strongly urge you to use Message Boxes in every possible place where you think you will want to know whether or not your code is working. They can be a great debugging tool in tracking the behavior of program. You can always comment some of them out if they become too annoying.

The Employee Class Provides a model for a bookstore Employee entity. Note that the information about each Employee initially will be stored in a text file, one record per Employee. Each record contains five substrings each separated from the other by an asterisk and one or more blanks. We use this file only to validate an Employees AccessID and Pin and to update the last date of Bookstore Inventory access for this Employee. The Employee is not allowed to change any of this information on his/her own. (See also Item B that comes next.)

Attributes: I try to prefix the names of attributes in the actual code for a class with the word hidden. You need to fill in the description of these attributes, what they represent and how they are used. Examples: hiddenName; hiddenAccessID

Access ID (a 5 digit integer) --

Name (text) --

Pin (4 digit integer) --

Annual Pay (decimal) --

Last date of access to inventory (date) --

*** Employee Data String a string containing the above information as text (read from the file and to be split in this class, with the information stored in the above 5 attributes). You also need a list of strings for split to store the results of its work, before you place these results in the above attributes. The string should be an argument to the createEmployeeObject method and the list of strings should be local to this method. They should not be considered attributes of the Employee Class. (Why not?)

*** Valid AccessID Length and Valid Pin Length constants for validating lengths of input

Properties: (You define the get and set properties as you see fit.)

Methods: (Mostly public methods. Others may be needed. Arguments to be added)

(constructor) used to perform any required initialization for the Employee class.

checkEmployeeID Compares the Employee Access ID entered by the user to the Access ID in a list element. If no match, ask for re-entry. If there is a match we can then move on to

createEmployeeObject Takes a string from the Employee Text File, splits it into 5 components, creates an Employee object from this string and adds it to the EmployeeList Class (described next). All 5 elements from the Text File must be validated here.

createStringToDisplay converts Employee attributes to a string suitable for display in a Message Box

updateEmployeeTransactionDate updates the Last Date of Access for an Employee to the current date

verifyPin given the Pin entered by the Employee, checks to see if it matches the Pin corresponding to the Access ID entered by the user.

Exceptions: Handle cases in which the Employee Access ID cannot be found and/or Pin in Employee Object does not match the Access ID. In addition, handle cases of failed validations (checked as records are read and stored in an Employee Object) of

Access ID (must be a 5 digit integer),

Pin (must be a 4 digit integer),

Name (cannot be blank),

Annual Pay (must be a decimal),

Last Date of Access to the Inventory (DateTime format)

The Employee List Class Provides a model for an internal array list used to store the information about all of the employees working for the Bookstore. This list initially will be populated from the information stored on the Current Employee Text File, and at the end of execution of your program, it will be written out to an Updated Employee Text File.

Attributes:

InternalList an array list containing data on all Employees

index holds index in List where current logged in Employee is stored.

Properties: (You define the get and set properties as you see fit.)

Methods: (Some of the public methods. Others may be needed. Arguments to be added)

(constructor) used to perform any required initialization for this class

findEmployeeInList Searches the Employee List to find an object with an Access ID that matches the ID entered by the Employee. (Saves and return employee index in the list

getCount Returns the Count attribute of the InternalList

initializeEntireList Reads each record in sequence from the currentEmployeeFile object, converts the string read to valid Employee object attributes and adds the object to the list. Continues to read (using a sentinel-controlled while loop) while there is still data in the file. (Note that in order to actually create an object to be added to the list we have to pass each string to the Employee class so it can split the string and store the substrings (create an Employee object to be inserted).

updateEmployeeObject Updates last date of access to todays date (NOW).

verifyPin calls verifyPin in in Employee class, passing the Pin.

writeEntireList Writes the contents of the entire EmployeeList object to the updatedEmployeeFile object.

Exceptions: Handle case in which Employee file object is empty or cannot otherwise be read.

The Book Class Provides a model for a Book in the Bookstore inventory

Attributes

Note: This class is similar to the Employee class. The information about the books in the Store inventory is stored in a text file, one record per book. Each record contains seven substrings each separated from the other by a dollar sign and one or more blanks. [The main difference between how we handle Books as opposed to Employees is that the collection of Employees to be manipulated is stored in an internal storage array list to be filled from the Employee file when the program begins, and written back out to an updated file when the program is ready to terminate. The Books collection is never stored internally. Rather information on each book is read and processed one record at a time from a text file (of Current File type) and when processing is complete, updated information is stored in another text file (of Updated File type). Only one record at a time is stored internally. (Note that the Bookstore might have a few employees, but tens of thousands of books, which could take up considerable internal storage). In addition, we need some exercise in manipulating array lists and additional work in manipulating external text files.)

ISBN (string: 3 digits, a hyphen, and 3 more digits: no spaces)

Title (string)

Author (string)

Price (decimal)

Number on hand (integer)

Date of last tranaction (date)

*** Book Information String a string containing the above information as text (to be split in this class with the information stored in these 6 attributes). Again, you also need a list of strings for split to store the results of its work, before you place these results in the above attributes. NOTE: This string in this case can be an attribute of the Book class as it is used by more than one method in the class.

Properties (none unless you want some)

Methods

bookMatch given a book ISBN (as entered by the user) and a record from the current Book File, checks for a match. (Must split and save the record contents in Books attributes for future reference, in addition to checking for an ISBN match.)

displayBookRecord creates a nicely formatted string to display in a Message Box. (Converts content (attributes) of a Book object to string to a format suitable for display in a Message Box.)

modifyBookRecord (not used modifications to a book record are written directly to the Updated Book File)

Exceptions: Handle case in which Employee ISBN cannot be found and all cases in which any data involved in a Book transaction are not in proper format or values make no sense (such as a negative price, etc.)

The BookStore Class This is a relatively simple class. Note that the currentEmployeeFile and currentBookFile objects belong to this class. So does the employeeList object. Employees and Books are, in a very real sense, part of the Bookstore. Thus, this model of the entire store must contain the collections of Employees and Books. For this project, these Book and Employee collections are stored in external text files. But the Employee collection is small enough that we decided to temporarily store the information nternally in an array list.

Attributes

Book object

Employee List object

Current Book File object and path

Current Employee File object and path

Updated Book File object and path

Updated Employee File object and path

*** Also used to store system constants as defined by the Bookstore owner. For example information about restrictions on lengths of some of the Employee and Book attributes.

Properties (Whatever you think you need or want. I used a bunch of them in this class)

Methods

checkForDuplicateRecord checks for a duplicate record when user attempts to add

new book

closeFiles closes all external files

copyRemainingRecords after an employees changes are processed, copies all

remaining records in the currentEmployeeFile to the updatedEmployeeFile.

findAndSaveBook given a book ISBN (entered by the user) and a book record (read from the currentBookFile) checks to see if the user ISBN matches the record ISBN (the first field of the record). If there is a match, this method splits the record into its 6 component parts and saves them.

findEmployee given an employees Access ID uses a sentinel-controlled while loop to find the correct employee record in the EmployeeList (calls findEmployeeInList in the employee List class).

rewindFiles rewinds all external files prior to closing

writeEntireEmployeeList calls writeEmployeeList in the Employee list class to write all Employee records in the List back out to the updatedEmployeeFile.

writeOneRecord writes the contents of one Book record to the updatedBookFile.

The CurrentFile Class

Attributes

string currentFilePath file path

System.IO.StreamReader currentFileSR stream reader object

integer recordReadCount tracks number of records read

Properties (none)

Methods

(constructor) sets count of records read to 0 and opens the current file

getNextRecord gets and returns the next record from the current file (also returns a Boolean flag indicating if the end of file was encountered)

getRecordsReadCount returns number of records read

closeFile closes the file

rewindFile rewinds a file

The UpdatedFile Class (very similar to the currentFile class)

This is a multi-form project. I strongly urge you to limit the number of forms to 4 or 5.

You may wish to declare and instantiate in a separate GlobalsClass any objects (if there are any) you need to be publicly accessible to the rest of your project. You might also wish to declare and instantiate in the GlobalsClass a couple of the forms that have multiple uses (if there are any) and need to be accessed in several different forms or classes. This will simplify life a bit.

Remember that your first form, the EmployeeAccessIDEntry Form, needs to be designated as your startup form.

EmployeeAccessIDEntry Form Welcomes the user and asks for the users account number. Note that a user of this system needs to be an Employee of the Bookstore and needs to have a valid Access ID (and Pin). Information about all employees (fewer than 10 of them) will be stored in a text file which we will model with the CurrentFile class (discussed earlier). I suggest you use the code behind the EmployeeAccessIDEntry Form to verify that the Employee Access ID was properly structured (a five digit integer) and then search the Employee file object to find the record for this ID. This search is complicated and if the AccessID number is not found, the required steps to give the user another chance at valid data entry are also a bit complicated. If the AccessID number sought was found, you can then turn control over to the

EmployeePinEntry Form Use this form to ask the user (the Employee) to enter his/her pin number. Check the user pin against the record for the account. Give the user three chances to get the pin correct before telling them to see the BookStore manager and ending the program (and closing all the files). Once a matching pin is entered, you can allow the Employee to choose a Book transaction by turning control over to the

TransactionSelect Form This is the most complicated of the forms. The transactions to be implemented include (1) Add New Book to Inventory, (2) Update a Book in Inventory, (3) Delete Existing Book, (4) Processing Complete (Done). In all cases except (4), the user should be required to enter the ISBN Number for the book involved in the transaction. The user should be given the option to indicate whether the transaction option and ISBN number selected is the one they want (Yes or No). If No is selected, reset the form controls and ask the user to select the desired transaction and ISBN. If Yes is selected, you can allow the user to enter data relevant to the update or add transactions and then complete processing. Again, displaying the results of the transaction and the updated files is important after which files and forms can be closed. Use Message Boxes for this use them a lot so you can see what is working and what is not. You will also find the debugger really helpful.

The above comments should provide you with some idea of the large-grained behavior of the Bookstore Inventory Project. You will also note that, as is the case with almost all such systems, the Bookstore project is layered. That is, the code behind these three forms involves the manipulation of 8 key entities or objects, the Bookstore object itself, Book, Employee and Employee List objects, and four text based file objects, currentBookFile and currentEmployeeFile (instances of the CurrentFile class), and updatedBookFile and updatedEmployeeFile (instances of the UpdatedFile class). The classes that model these objects make up the layer of code between the forms and the CLR. Virtually every line of code you write as the code behind your forms will involve access to the methods and properties of these four classes.

________________________________________________________________________________

--GIVEN SOURCE CODE--

SOURCE CODE FOR PROJECT 2

This code needs to be read carefully and questions need to be asked in class.

CURRENT FILE CLASS (you need to write the updatedFile class)

// Current File Class // Data stores and methods related to a current (input) text file processed by the project

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms;

namespace Bookstore_Inventory_Project_II { class currentFileClass { private string currentFilePath; private System.IO.StreamReader currentFileSR; // Reference variable of type SR private int recordReadCount;

// Constructor with file path input // Create instance of StreamReader class (type) and store reference public currentFileClass (string filePath) { recordReadCount = 0; currentFilePath = filePath; try { currentFileSR = new System.IO.StreamReader(currentFilePath); } catch (Exception ex) { MessageBox.Show("Cannot open file" + currentFilePath + "Terminate Program.", "Output File Connection Error.", MessageBoxButtons.OK, MessageBoxIcon.Warning); } // end Try } // end currentFileClass Constructor

// Read a record from the current file // Returns: the text string read and (through an output argument) a true-false // indicator for end-of-file public string getNextRecord( ref Boolean endOfFileFlag) { string nextRecord;

endOfFileFlag = false; nextRecord = currentFileSR.ReadLine();

if (nextRecord == null) { endOfFileFlag = true; } else { recordReadCount += 1; } // end if

return (nextRecord); } // end getNextRecord

// Get value of number of records read public int getRecordsReadCount() { return recordReadCount; } // end getRecordsReadCount

// Close the input file public void closeFile() { currentFileSR.Close(); } // end closeFile

// Rewind the input file public void rewindFile() { recordReadCount = 0; currentFileSR = new System.IO.StreamReader(currentFilePath); currentFileSR.DiscardBufferedData(); currentFileSR.BaseStream.Seek(0, System.IO.SeekOrigin.Begin); } // end rewindFile

} // end currentFileClass } // end namespace

GLOBALS CLASS

// Globals Information Class // Contains only a reference to the BookStore class and the instantiation of this class // Frank Friedman // CIS 3309

// Created on January 13 by FLF // Modified ... January 30, 2017 and February 2, 2017

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;

namespace Bookstore_Inventory_Project_II { class Globals {

// NOTE: // Static methods of a class may be called without instantiating the class // They called from the class itself // Static objects or variables may be accessed without creating an instance of the class // that contains them // When you declare a class as static, all its members are automatically static

// Application classes -- BookStore is accessible throughout all code without passing it as an argument public static BookStoreClass BookStore = new BookStoreClass(); } // end Globals Class } // end namespace

FRONT END OF THE BOOKSTORE CLASS YOU WILL HAVE TO WRITE THE REST AS NEEDED

// BookStore Class // Contains constants, properties and other data related to the Bookstore // Frank Friedman // CIS 3309

// Created on January 13 by FLF // Modified ... January 30, 2017

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;

namespace Bookstore_Inventory_Project_II { class BookStoreClass { // Books and the EmployeeList and all the text files belong to the Bookstore public BookClass Book = new BookClass(); public EmployeeListClass EmployeeList = new EmployeeListClass();

// The Files the Bookstore Owns private static string currentBookFilePath = "currentBookFile.txt"; private static string updatedBookFilePath = "updatedBookFile.txt"; private static string currentEmployeeFilePath = "currentEmployeeFile.txt"; private static string updatedEmployeeFilePath = "updatedEmployeeFile.txt";

public static currentFileClass currentBookFile = new currentFileClass(currentBookFilePath); public static updatedFileClass updatedBookFile = new updatedFileClass(updatedBookFilePath); public static currentFileClass currentEmployeeFile = new currentFileClass(currentEmployeeFilePath); public static updatedFileClass updatedEmployeeFile = new updatedFileClass(updatedEmployeeFilePath);

// Bookstore parameters (Named constants defined by the Bookstore) private int hiddenAccessIDLength = 5; // Length of AccessNet ID private int hiddenISBNLeftLength = 3; // Length of left part of ISBN private int hiddenISBNRightLength = 3; // Length of right part of ISBN // Number of attempts BookStore allows a user before terminating an inventory // update session private int hiddenTryCountMax = 3;

. . .

// Find Employee in Employee List // Returns a reference to the employee found and (through an argument) returns // true or false public EmployeeClass findEmployee (int ID, // IN: employee ID to be found out Boolean found) // OUT: flag indicating if Employee ID found in current // Employee object { EmployeeClass emp; // reference to current Employee being checked for ID

if ((emp = EmployeeList.findEmployeeInList(ID)) != null) { found = true; } else found = false; return emp; } // end findEmployee

. . .

// Displays the list of employees (After they were written to the Employee File) public void writeEntireEmployeeList() { EmployeeList.displayEntireList(); } // end writeEntireEmploeeList

Sample Text Files

Employee File

11111 * Chris Jones * 9999 * $10,000 * 1/1/2017 22222 * Denise Cavey * 8888 * $20,000 * 1/1/2017 60606 * Harold in Italy* 7777 *$60,000 * 1/1/2017 44444 * John Pine * 6666 * $40,000 * 1/1/2017 55555 * Claudia Fiore * 5555 * $50,000 * 1/1/2017

Book File (for later use)

123-456 * I am the Ogre * Shrek * $12.09 * 100 * 11/8/2016 120-777 * Sam I Am * Sam Wheeler * $50.00 * 20 * 9/12/1942 999-999 * Me I are * The Big Grump * $1,500. * 1500 * 6/6/1942 135-790 * How to Play Third Base * Brooks Robinson *$55.55 * 225 * 12/31/1956 246-802 * How to Play QB * Johnny Unitas * $60,000 * 34 * 1/1/2017 684-205 * How Swell is Retirement * Y. A. Tittle *$14.14* 42 * 12/31/2007 234-756 * I am Glad I Lost * Hillary Clinton * $225,000.00 * 6500 * 11/08/2016 232-323 * Of Thee I Sing * Julianne Baird * $145,000 * 123 * 7/4/1776 876-543 * I am sorry I won * Donald * $000 * 234 * 1/20/2017

AN ALGORITHM FOR READING RECORDS FROM THE EMPLOYEE FILE AND STORING THESE RECORDS, ONE-BY-ONE IN THE INTERNAL EMPLOYEE LIST

(This is an algorithm involving a sentinel-controlled while loop, It happens to be written in C# .NET and is part of a complete method, but a pseudo-code code segment would work just as well. You need to clearly understand what each line of code here does. Even though you have not yet seen the code for some of the methods called, you should be able to tell me what these called methods do.)

public Boolean initializeEntireList() { string nextRecord; Boolean isEndOfFile = true; Boolean success; int countProcessedRecords = 0;

nextRecord = BookStoreClass.currentEmployeeFile.getNextRecord(ref isEndOfFile); while (!isEndOfFile) { countProcessedRecords++; EmployeeClass emp = new EmployeeClass(); success = emp.createEmployeeObject(nextRecord); if (success != true) { MessageBox.Show ("Unable to create an Employee Object. Employee list not created.", "Employee List Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; } InternalList.Add(emp); nextRecord = BookStoreClass.currentEmployeeFile.getNextRecord(ref isEndOfFile); } //end While

if (countProcessedRecords > 0) return true; else return false; } // end initializeEntireList

ONE WAY TO VALIDATE THE INPUT STRING AS READ FROM THE CURRENT EMPLOYEE FILE. If you find errors, you can fix them. public Boolean createEmployeeObject (string s) // IN: string from the Employee Text File {

EmployeeClass thisEmployee = this; string [] employeeString = s.Split('*'); int i;

int employeeStringSize = employeeString.GetLength(0);

// Convert AccessID to an integer of required length if (employeeString[0].Length != validAccessIDLength) { MessageBox.Show (employeeString[0] + ": AccessID string is not exactly 5 characters. Employee File Corrupt. Execution Terminated.", "AccessID in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

try { hiddenAccessID = Convert.ToInt32(employeeString[0]); } catch { MessageBox.Show (employeeString[0] + " AccessID string is not a valid integer. Employee File Corrupt. Execution Terminated.", "AccessID in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

// Name string to string (no conversion) hiddenName = employeeString[1]; if (hiddenName == " " || hiddenName == "") { MessageBox.Show (hiddenName + ": Name string is empty or Blank. Employee File Corrupt. Execution Terminated.", "Name in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

// Convert Pin to an integer of required length if (employeeString[2].Length != validPinLength) { MessageBox.Show (employeeString[2] + ": Pin string is not exactly 4 characters. Employee File Corrupt. Execution Terminated.", "Pin in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

try { hiddenPin = Convert.ToInt32(employeeString[2]); } catch { MessageBox.Show (employeeString[2] + ": Pin string is empty or Blank. Employee File Corrupt. Execution Terminated.", "Pin in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

// Convert annualPay to a positive decimal try { hiddenAnnualPay = Convert.ToDecimal(employeeString[3].Replace(",", "").Replace("$", "")); } catch { MessageBox.Show (employeeString[3] + ": Annual Pay string is not a valid decimal. Employee File Corrupt. Execution Terminated.", "Annual pay in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

// Convert last Date of Access to a date try { hiddenLastDateOfAccess = DateTime.Parse(employeeString[4]); } catch { MessageBox.Show (employeeString[4] + ": Date of Last Access string is not a valid date. Employee File Corrupt. Execution Terminated.", "Date of last access in Employee File Invalid", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; }

// All data valid return (true); } // end createEmployeeObject

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Automating Access Databases With Macros

Authors: Fish Davis

1st Edition

1797816349, 978-1797816340

More Books

Students also viewed these Databases questions