/*TITLE mailing list program*/

/****keyword-flag*** "%v %f %n" */
/* "12 21-Mar-98,19:23:00 MAILX.CPP" */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mailx.h"
#include "bitfunc.h"
#include "date.h"
#include "..\\common\\timings.h"


CustomerSelection initialize(char *min,char *max,char *start,char *end);

void process(FILE *customer_data_file, FILE *customer_list_file,
CustomerSelection customer_selection);

void terminate(FILE *customer_data_file, FILE *customer_list_file);

static int override;

int main(int argc, char *argv[])
{
	start_timing();

	FILE *customer_data_file;
	FILE *customer_list_file;
	char customer_data_file_name[100];
	char customer_list_file_name[100];
	CustomerSelection customer_selection;

	if (argc < 6)
		{
		printf("Usage: mailx customer_file min max start end [override]\n");
		exit(1);
		}

	if (argc < 7)
		override = 0;
	else
		override = atoi(argv[6]);

	strcpy(customer_data_file_name,argv[1]);
	strcat(customer_data_file_name,".dat");

	strcpy(customer_list_file_name,argv[1]);
	strcat(customer_list_file_name,".lst");

	customer_data_file = fopen(customer_data_file_name,"rb");

	if (customer_data_file == NULL)
		{
		printf("Cannot open file %s.\n",customer_data_file_name);
		exit(1);
		}

	customer_list_file = fopen(customer_list_file_name,"w");

	if (customer_list_file == NULL)
		{
		printf("Cannot open file %s.\n",customer_list_file_name);
		exit(1);
		}

	setvbuf(customer_list_file, NULL, _IOFBF, 32000);

	customer_selection = initialize(argv[2],argv[3],argv[4],argv[5]);

	process(customer_data_file, customer_list_file, customer_selection);

	terminate(customer_data_file, customer_list_file);

	end_timing();

	return 0;
}


CustomerSelection initialize(char *min,char *max,char *start,char *end)
{
	CustomerSelection temp_selection;

	temp_selection.min_spent = atoi(min);

	temp_selection.max_spent = atoi(max);

	temp_selection.min_date = date_string_to_days(start);

	temp_selection.max_date = date_string_to_days(end);

	return(temp_selection);
}


void process(FILE *customer_data_file, FILE *customer_list_file,
CustomerSelection customer_selection)
{
	int i;
	unsigned k;
	unsigned zip_block_start;
	unsigned zip_count;
	unsigned zip_entry;
	unsigned list_index;
	unsigned items_read;
	unsigned items_processed;
	int total_items_read;
	DataRecord search_record[BATCH_SIZE];
	DataRecord data_record;
	long data_file_length;	
	long data_file_count;
	char *found;
	ZipRecord *temp_zip_pointer[ZIP_BLOCK_ENTRIES];
	ZipRecord **zip_pointer;
	ZipRecord *zip_block[ZIP_BLOCK_COUNT];
	unsigned *record_number;
	unsigned items_found;
	char *file_buffer;
	unsigned processing_batch = BATCH_SIZE;
	int current_zip_block = -1;
	int current_zip_entry = ZIP_BLOCK_ENTRIES;

	int countdown;

	setvbuf(customer_data_file, file_buffer, _IOFBF, 32000);

	fseek(customer_data_file, 0L, SEEK_END);
	data_file_length = ftell(customer_data_file);
	fseek(customer_data_file, 0L, SEEK_SET);

	data_file_count = data_file_length / sizeof(DataRecord);
	fseek(customer_data_file, 0L, SEEK_SET);

	file_buffer = (char *)calloc(32000,1);

	found = (char *)allocate_bitmap(data_file_count);

	items_found = 0;
	total_items_read = 0;
	countdown = override;

	for (;;)
		{
		items_read = fread(search_record, sizeof(DataRecord), processing_batch, 
		customer_data_file);

		for (items_processed = 0; items_processed < items_read; items_processed ++)
			{
			if (override == 0)
				{
				if (search_record[items_processed].dollars_spent < 
					customer_selection.min_spent)
				  continue;

				if (search_record[items_processed].dollars_spent > 
					customer_selection.max_spent)
				  continue;

				if (search_record[items_processed].date_last_here < 
					customer_selection.min_date)
				  continue;

				if (search_record[items_processed].date_last_here > 
					customer_selection.max_date)
				  continue;
				}
			else
				{
				countdown --;
				if (countdown > 0)
					continue;
				countdown = override;
				}

			items_found ++;
			setbit(found,(long)(items_processed+total_items_read));

			if (current_zip_entry == ZIP_BLOCK_ENTRIES)
				{
				current_zip_block ++;
				current_zip_entry = 0;
				zip_block[current_zip_block] = (ZipRecord *)
				calloc(ZIP_BLOCK_ENTRIES,sizeof(ZipRecord));
				for (k = 0; k < ZIP_BLOCK_ENTRIES; k ++)
					temp_zip_pointer[k] = zip_block[current_zip_block] + k;
				}

			memcpy(&temp_zip_pointer[current_zip_entry]->zip,
			search_record[items_processed].zip,ZIP_LENGTH+1);
			temp_zip_pointer[current_zip_entry]->record_number = 
			items_processed+total_items_read;
			current_zip_entry ++;
			}
		total_items_read += items_read;
		if (items_read != processing_batch)
			break;
		}

	timing("Pass 1 time");

	zip_pointer = (ZipRecord **)calloc(items_found,sizeof(ZipRecord *));
	zip_block_start = 0;
	for (i = 0; i <= current_zip_block; i ++)
		{
		if (i < current_zip_block)
			zip_count = ZIP_BLOCK_ENTRIES;
		else
			zip_count = items_found-zip_block_start;
		for (zip_entry = 0; zip_entry < zip_count; zip_entry ++)
			{
			zip_pointer[zip_block_start+zip_entry] = zip_block[i] + zip_entry;
			}
		zip_block_start += zip_entry;
		}

	record_number = (unsigned *)calloc(items_found,sizeof(int));
	list_index = 0;
	for (i = 0; i < total_items_read; i ++)
		{
		if (testbit(found,i))
			{
			record_number[list_index] = i;
			list_index ++;
			}
		}

	Megasort((unsigned char **)zip_pointer, record_number, ZIP_LENGTH, 
	items_found);

	timing("Sorting time");
    
	setvbuf(customer_data_file, file_buffer, _IOFBF, sizeof(DataRecord));

	for (items_processed = 0; items_processed < items_found; items_processed ++)
		{
		fseek(customer_data_file,
		(long)(zip_pointer[items_processed]->record_number)*(long)sizeof(DataRecord),SEEK_SET);
		fread(&data_record, sizeof(DataRecord), 1, customer_data_file);
		fprintf(customer_list_file,"%s %s %s\n",data_record.first_name,
		data_record.last_name,zip_pointer[items_processed]->zip);
		}

	timing("Pass 2 time");

	printf("Total records selected: %ld\n",items_found);

	free(file_buffer);
	free(found);
	free(zip_pointer);
	for (i = 0; i <= current_zip_block; i ++)
		free(zip_block[i]);

}


void terminate(FILE *customer_data_file, FILE *customer_list_file)
{
	fclose(customer_data_file);
	fclose(customer_list_file);
}



