Lab 11-21

/*
	This program has some kind of bug on option 6
	This is an update of last weeks record.c

  */


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

#define FMAX 20
#define LMAX 20
#define QUIT 7

struct Employee {
	int idNum;
	char firstName[FMAX];
	char lastName[LMAX];
	struct Employee* next;
};

typedef struct Employee Employee;

typedef Employee* EmpList;

void write_record(Employee e, long pos, FILE *ofp);
Employee read_record(long pos, FILE *ifp);
Employee input_record();
void output_record(Employee record);
int main_menu();
long record_count(FILE *fptr);
long getUserNum(FILE *fptr);
EmpList createList(FILE *fptr);
EmpList createListLast(FILE *fptr);
void printList(EmpList l);
void deleteList(EmpList l);
EmpList findName(EmpList l, char * target);
int nameEquals(char * findName, char * first, char * last);
char * readLine();

void changeTwoItems(int *iptr, char *cptr);

int main(void) {

	Employee record;
	FILE *fptr;
	long record_pos;
	int choice;
	EmpList list = NULL;

	fptr = fopen("emp.dat", "r+");
	if (fptr == NULL) {
		fptr = fopen("emp.dat", "w+");
	}

	record_pos = record_count(fptr);

	printf("%ld record(s)\n", record_count(fptr));

	while ( (choice = main_menu()) != QUIT) {
		switch ( choice ) {
			case 1: {//add
				record = input_record();
				write_record(record, record_pos, fptr);
				record_pos++;
				break;
			}
			case 2: { //get
				int recordNum = getUserNum(fptr);
				record = read_record(recordNum, fptr);
				output_record(record);
				break;
			}
			case 3: { //list all
				long i;
				long rec_count = record_count(fptr);
				//printf("record count: %d\n", rec_count);
				for(i = 0; i < rec_count; i++) {
					record = read_record(i, fptr);
					output_record(record);
				}
				break;
			}
			case 4: { //create reverse linked list
				if (list != NULL) {
					deleteList(list);
				}
				list = createList(fptr);
				printList(list);
				break;
			}
			case 5: { //create forward linked list
				if (list != NULL) {
					deleteList(list);
				}
				list = createListLast(fptr);
				printList(list);
				break;
			}
			case 6: { //find name
				char *name;
				EmpList person;

				printf("%s", "Name? ");
				name = readLine();
				if (list == NULL) {
					list = createListLast(fptr);
				}
				person = findName(list, name);
				free(name);
				printf("name found? %s\n", person == NULL ? 
										    "No" : "Yes" );
				break;
			}
			default:
				break;
		}
	}

	//record = input_record();
	//output_record(record);

	return 0;
}

void write_record(Employee e, long pos, FILE *ofp) {

	fseek(ofp, pos * sizeof(Employee), SEEK_SET);
	fwrite(&e, sizeof(Employee), 1, ofp);

}

Employee read_record(long pos, FILE *ifp) {

	Employee record;
	
	fseek(ifp, pos * sizeof(Employee), SEEK_SET);
	fread(&record, sizeof(Employee), 1, ifp);

	return record;

}

Employee input_record() {

	Employee record;

	printf("%s", "ID Num: ");
	scanf("%d", &record.idNum); 

	printf("%s", "First Name: ");
	scanf("%s", record.firstName); 

	printf("%s", "Last Name: ");
	scanf("%s", record.lastName); 

	return record;
}

void output_record(Employee record) {

	printf("\n%s\n", "=====================");

	printf("%s %d\n", "ID Num:", record.idNum); 

	printf("%s %s\n", "First Name:", record.firstName);

	printf("%s %s\n", "Last Name: ", record.lastName);

	printf("%s %s\n", "Next Null? ", (record.next == NULL) ?
										"Yes" : "No" );

	printf("%s\n", "=====================");

	return;
}

int main_menu() {

	int choice;

	printf("\n%s", "1) Add new record\n");
	printf("%s", "2) Get a record\n");
	printf("%s", "3) List all records\n");
	printf("%s", "4) Make reverse linked list\n");
	printf("%s", "5) Make forward linked list\n");
	printf("%s", "6) Find name in list\n");
	printf("%s", "7) Quit\n");

	printf("%s", "\n --> ");
	fflush(stdin);
	scanf("%d", &choice);
	
	return choice;
}

long record_count(FILE *fptr) {

	long current_pos = ftell(fptr);
	long end_pos;

	fseek(fptr, 0, SEEK_END);
	end_pos = ftell(fptr);
	fseek(fptr, current_pos, SEEK_SET);

	return end_pos / sizeof(Employee);
}

long getUserNum(FILE *fptr) {
	
	long num = -1;
	long max_rec = record_count(fptr);
	int firstTime = 1;

	while( num < 0 || num >= max_rec) {
		if (firstTime) {
			printf("%s", "What record? ");
			firstTime = 0;
		}
		else {
			printf("%s", "Bad Record#: What record? ");
		}
		scanf("%ld", &num);
	}

	return num;
}

EmpList createList(FILE *fptr) {
	EmpList list = NULL;
	EmpList newEmp;
	Employee record;
	long i;
	long rec_count = record_count(fptr);

	for(i = 0; i < rec_count; i++) {
		//printf("reading a record\n");
		record = read_record(i, fptr);				//read a record
		newEmp = malloc( sizeof(Employee) );		//malloc memory
		*newEmp = record;							//copy record
		newEmp->next = list;						//put at start
		list = newEmp;								//update list ptr
	}

	return list;
}

EmpList createListLast(FILE *fptr) {
	EmpList list = NULL;		// points to head of list
	EmpList last = NULL;		// points to end of list
	EmpList newEmp;
	Employee record;
	long i;
	long rec_count = record_count(fptr);

	for(i = 0; i < rec_count; i++) {
		//printf("reading a record\n");
		record = read_record(i, fptr);				//read a record
		newEmp = malloc( sizeof(Employee) );		//malloc memory
		*newEmp = record;							//copy record
		newEmp->next = NULL;						//put at start

		if (list == NULL) {
			list = newEmp;								//update list ptr
		}
		else { // list exists
			last->next = newEmp;
		}

		last = newEmp;
	}

	return list;
}

void printList(EmpList l) {
	
	while ( l != NULL ) {
		output_record( *l );
		l = l->next;
	}
}

void deleteList(EmpList l) {
	EmpList temp;

	while ( l != NULL ) {
		temp = l;
		l = l->next;
		free( temp );
	}
}

EmpList findName(EmpList l, char * target) {
	// return pointer to found record or NULL

	while ( l != NULL &&
		    !nameEquals(target, l->firstName, l->lastName) ) {
		l = l->next;
	}
	return l;
}


int nameEquals(char * findName, char * first, char * last) {

	// first + space + last + null
	int nameLen = strlen(first) + strlen(last) + 2;
	char *targetName = malloc( nameLen * sizeof(char) );
	int result;

	strcpy(targetName, first);
	strcat(targetName, " ");
	strcat(targetName, last);
	printf("find name: %s target name: %s\n", findName, targetName);

	result = strcmp(findName, targetName);
	free(targetName);

	return !result;
}

char * readLine() {
	char line[100];
	int charCount = 0;
	char ch;
	char *name;

	fflush(stdin);
	while ( (ch = getchar()) != '\n') {
		line[charCount++] = ch;	
	}

	line[charCount] = '\0';
	name = malloc(charCount * sizeof(char));
	strcpy(name, line);
	//printf("Name entered: %s Len: %d\n", name, strlen(name));

	return name;
}