
/*	address_functions.c
 *
 *	Functions and support routines for our address book application, for
 *	file, record, and field access.
 */

#include "address_includes.h"

/* Arrays to hold information on field lengths and names */
int field_lengths[TOTAL_FIELDS] =
 	{
	40, 64, 64, 64, 64, 10, 20, 128, 128
 	};

char *field_names[TOTAL_FIELDS] =
	{
	"Name", "Address 1", "Address 2", "Address 3",
	"Address 4", "Post Code", "Phone #",
	"E-Mail", "Comment"
	};

extern long total_records;

/**************************************
 *
 *	void create_record(void);
 *
 *	This function creates a new record, the user entering field data
 *	in from the keyboard.
 */

void create_record(void)
{
	char record[RECORD_LENGTH];
	char *record_pointer;
	char temp_line[512];
	int loop;
	BOOL entered_ok = FALSE;
	BPTR file_channel = 0;

	printf("Create a new record\n\n");

	/* Clear our record in case its re-used memory */
	for (loop = 0; loop < RECORD_LENGTH; loop++)
		record[loop] = 0;

	/* Get a pointer to the start of our record */
	record_pointer = record;

	/* Input fields */
	for (loop = 0; loop < TOTAL_FIELDS; loop++)
		{
		entered_ok = FALSE;

		/* Enter this field, with error checking on length */
		while (!entered_ok)
			{
			/* Prompt with field name */
			printf("%-30s", field_names[loop]);

			/* Now input a value for this */
			gets(temp_line);

			if (strlen(temp_line) < field_lengths[loop])
				entered_ok = TRUE;
			else
				printf("Error, field too long. Try again.\n");
			}

		/* Insert this field into our record */
		strcpy(record_pointer, temp_line);

		/* Point to next field */
		record_pointer = record_pointer + field_lengths[loop];
		}

	/* Open our file */
	if (!(file_channel = Open("addresses", MODE_READWRITE)))
		{
		printf("Can't open our file.\n");
		return;
		}

	/* Seek to the end of this file */
	Seek(file_channel, 0, OFFSET_END);

	/* Write out our data */
	Write(file_channel, record, RECORD_LENGTH);

	/* Now close up the file */
	Close(file_channel);

	return;
}

/**************************************
 *
 *	void read_record(void);
 *
 *	This function reads an existing record.
 */

void read_record(void)
{
	char record[RECORD_LENGTH];
	char temp_line[512];
	char *record_pointer;
	BPTR file_channel;
	int	loop = 0;
	long record_number = 0;
	long data_read = 0;

	/* Input a record number */
	printf("\nWhich record number to read? ");
	gets(temp_line);
	record_number = atol(temp_line);

	/* Open our file */
	if (!(file_channel = Open("addresses", MODE_OLDFILE)))
		{
		printf("Can't open our file.\n");
		return;
		}

	/* Seek to the correct position of this file */
	data_read = Seek(file_channel, (record_number * RECORD_LENGTH), OFFSET_BEGINNING);
	if (data_read == -1)
		{
		printf("Error reading record %ld\n", record_number);
		Close(file_channel);
		return;
		}

	/* Read in our data */
	data_read = Read(file_channel, record, RECORD_LENGTH);
	if (data_read < RECORD_LENGTH)
		{
		printf("Error reading record %ld\n", record_number);
		Close(file_channel);
		return;
		}

	/* Now close up the file */
	Close(file_channel);

	/* Now display this record on the screen */
	record_pointer = record;

	printf("\nRecord number %ld:\n\n", record_number);

	for (loop = 0; loop < TOTAL_FIELDS; loop ++)
		{
		/* Show field name and data */
		printf("%-30s%s\n", field_names[loop], record_pointer);

		/* Go to next field */
		record_pointer = record_pointer + field_lengths[loop];
		}

	/* All done, quit to menu */
	return;
}

/**************************************
 *
 *	void edit_record(void);
 *
 *	This function edits an existing record.
 */

void edit_record(void)
{
	char temp_line[512];
	char command;
	long record_number;
	char record[RECORD_LENGTH];
	BOOL finished_edit = FALSE;
	long field_number;
	int loop;
	long field_offset;
	char *field_pointer;

	/* Input a record number */
	printf("\nWhich record number to edit? ");
	gets(temp_line);
	record_number = atol(temp_line);

	/* Read this record in */
	if (!(read_record_data(&record[0], record_number)))
		{
		printf("Failure to read record %ld\n", record_number);
		return;
		}

	/* Do our edit here */
	field_pointer = record;

	while(!finished_edit)
		{
		/* Show fields with numbers */
		show_record_data(&record[0], record_number);

		/* Now prompt the user for a field number */
		printf("\nEnter a field number 1 - %ld, S to Save and Exit, or A to Abort: ",
			TOTAL_FIELDS);
		gets(temp_line);
	
		field_number = atol(temp_line);
		if (field_number > 0 && field_number < TOTAL_FIELDS+1)
			{
			/* Edit this field */
			field_number--; 							/* Adjust it from 0-TOTAL_FIELDS-1 */
			printf("Enter new field data\n%-30s:", field_names[field_number]);
			gets(temp_line);
			
			/* Find offset inside record of this field */
			field_offset = 0;

			for (loop = 0; loop < field_number; loop++)
				field_offset = field_offset + field_lengths[loop];

			/* Copy the new data across */
			strcpy(field_pointer+field_offset, temp_line);

			/* Make sure we don't accidently do something */
			temp_line[0] = ' ';
			}

		/* This is out of address_book.c, converts first character to 
				upper case and uses it as a command. */
		command = temp_line[0];
		if (islower(command))
			command = command - 0x20;

		switch(command)
			{
			case 'S':
				/* Save selected. Save record, then quit */
				if (!(write_record_data(&record[0], record_number)))
					{
					printf("Failure to write record %ld\n", record_number);
					return;
					}
				finished_edit = TRUE;
				break;

			case 'A':
				/* Abort selected, simply quit, don't save */
				finished_edit = TRUE;
				break;
			}
		}

	/* All done, return to menu */
	return;
}

/**************************************
 *
 *	BOOL show_record_data(char *record_data, record_number)
 *
 *	Function to show a specified record on the screen.
 *	Records are numbered from 1 (In reality they're from 0).
 */

void show_record_data(char *record_data, long record_number)
{
	int loop;

	/* Now display this record on the screen */
	printf("\nRecord number %ld:\n\n", record_number);

	for (loop = 0; loop < TOTAL_FIELDS; loop ++)
		{
		/* Show field name and data */
		printf("%ld: %-30s%s\n", loop+1, field_names[loop], record_data);

		/* Go to next field */
		record_data = record_data + field_lengths[loop];
		}

	return;
}

/**************************************
 *
 *	BOOL read_record_data(char *record_data, long record_number)
 *
 *	Function to read a specified record into a supplied area of memory.
 *	Does not print anything, returns FALSE if it fails or TRUE if it
 *	succeeded.
 */

BOOL read_record_data(char *record_data, long record_number)
{
	BPTR file_channel;
	long data_read = 0;

	/* Open our file */
	if (!(file_channel = Open("addresses", MODE_OLDFILE)))
		return FALSE;

	/* Seek to the correct position of this file */
	data_read = Seek(file_channel, (record_number * RECORD_LENGTH), OFFSET_BEGINNING);
	if (data_read == -1)
		{
		Close(file_channel);
		return FALSE;
		}

	/* Read in our data */
	data_read = Read(file_channel, record_data, RECORD_LENGTH);
	if (data_read < RECORD_LENGTH)
		{
		Close(file_channel);
		return FALSE;
		}

	/* Now close up the file */
	Close(file_channel);

	return TRUE;
}

/**************************************
 *
 *	BOOL write_record_data(char *record_data, long record_number)
 *
 *	Function to write a specified record from a supplied area of memory.
 *	Does not print anything, returns FALSE if it fails or TRUE if it
 *	succeeded. Specifying -1 as a record ID adds the record as a new one
 *	to the end of the file.
 */

BOOL write_record_data(char *record_data, long record_number)
{
	BPTR file_channel;
	long data_written;

	/* Open our file */
	if (!(file_channel = Open("addresses", MODE_READWRITE)))
		return FALSE;

	/* Seek to the correct position of this file */
	if (record_number == -1)
		data_written = Seek(file_channel, 0, OFFSET_END);
	else
		data_written = Seek(file_channel, (record_number * RECORD_LENGTH), OFFSET_BEGINNING);

	if (data_written == -1)
		{
		Close(file_channel);
		return FALSE;
		}

	/* Write out our data */
	data_written = Write(file_channel, record_data, RECORD_LENGTH);
	if (data_written < RECORD_LENGTH)
		{
		Close(file_channel);
		return FALSE;
		}

	/* Now close up the file */
	Close(file_channel);

	return TRUE;
}

/**************************************
 *
 *	long find_total_records(void);
 *
 *	Finds the total number of records in our file. It does this by checking
 *	its file-size and dividing it by the size of a record. Returns 0 if
 *	the file is empty or does not exist.
 */

long find_total_records(void)
{
	BPTR file_channel;
	long tot_records = 0;

	/* Open our file */
	if (!(file_channel = Open("addresses", MODE_OLDFILE)))
		return NULL;

	/* Calculate total records */
	Seek(file_channel, 0, OFFSET_END);
	tot_records = (Seek(file_channel, 0, OFFSET_CURRENT) / RECORD_LENGTH);

	Close(file_channel);

	return tot_records;
}

/**************************************
 *
 *	long search_record_data(long start_record, long direction,
 *													char *search_data);
 *
 *	Searches our addresses for matches. The passed record structure (Search
 *	data) contains any fields that contain match data. Direction is either
 *	SEARCH_FORWARDS or SEARCH_BACKWARDS. Start record is the record to start
 *	the search from. Returns -1 if no record match found.
 */

long search_record_data(long start_record, long direction, char *search_data)
{
	long	loop_step;
	BOOL	done = FALSE;
	long	record_id;
	char	match_record[RECORD_LENGTH];
	char	*match_ptr, *search_ptr;
	int 	loop;

	/* Default a start position */
	if (start_record == -1) start_record = 0;

	/* Set the loop direction correctly */
	if (direction == SEARCH_FORWARDS)
		loop_step = 1;
	else
		loop_step = -1;

	/* Loop through records till done */
	record_id = start_record;

	while (!done)
		{
		/* Read in record to check against */
		if (!(read_record_data(match_record, record_id))) 	return -1;

		/* Check for matches ... */
		match_ptr = match_record;
		search_ptr = search_data;

		for (loop = 0; loop < TOTAL_FIELDS; loop ++)
			{
			if (strstr(match_ptr, search_ptr))
				{
				/* Match found, return it ... */
				return record_id;
				}

			match_ptr = match_ptr + field_lengths[loop];
			search_ptr = search_ptr + field_lengths[loop];
			}

		/* Move to next record */
		record_id = record_id + loop_step;

		/* Check if done */
		if (record_id == (total_records + 1) || record_id == -1)		done = TRUE;		
		}

	/* No match, return error */
	return -1;
}
