#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>

#include "files.h"

#define OUT_BUF_MAX     (2 * OUT_BUF_SIZE)


static unsigned long input_file_length = 0;
static unsigned long output_file_length = 0;

static int input_file;
static int output_file;

static unsigned char output_area [OUT_BUF_MAX];
static int output_index;
static int output_max;

static unsigned char input_area [IN_BUF_SIZE];
static int input_index;
static int input_len;


static void read_input_area (void);
static void write_output_area (void);


long OpenInputFile (char *fn)

{
	long filesize;

	input_file = open (fn, O_RDONLY | O_BINARY);
	if (input_file < 0)
	{
		perror ("Error on file open");
		exit (EXIT_FAILURE);
	}

	filesize = lseek (input_file, 0L, SEEK_END);
	lseek (input_file, 0L, SEEK_SET);

	read_input_area ();

	return filesize;
}


int ReadInputFile (void)

{
	if (input_index == input_len)
	{
		read_input_area ();
		if (input_len == 0) return -1;
	}

	return input_area [input_index ++];
}



int ResetOutputPointer (unsigned pos)

{
	output_index -= pos;
	if (output_index < 0)
	{
		output_index += OUT_BUF_MAX;
		output_file_length -= OUT_BUF_MAX;
	}

	return output_area [output_index];
}


void OpenOutputFile (char *fn)

{
	output_file = open (fn, O_RDWR+O_BINARY+O_CREAT+O_TRUNC, S_IREAD+S_IWRITE);
	if (output_file < 0)
	{
		perror ("Error on output file open");
		exit (EXIT_FAILURE);
	}

	output_file_length = 0;
	output_index = 0;
	output_max = OUT_BUF_MAX;
}



void WriteOutputFile (int ch)

{
	output_area [output_index] = ch;

	output_index ++;
	if (output_index == output_max)
		write_output_area ();
	else
	if (output_index == OUT_BUF_MAX)
	{
		output_index = 0;
		output_file_length += OUT_BUF_MAX;
	}
}



void CloseInputFile (void)

{	close (input_file);
}



void CloseOutputFile (void)

{
	if (output_index < output_max)
	{
		write (output_file, &output_area [output_max], OUT_BUF_MAX - output_max);
		output_max = 0;
	}

	write (output_file, &output_area [output_max], output_index - output_max);
	close (output_file);
}



static void read_input_area ()

{
	input_file_length += input_len;
	input_index = 0;
	input_len = read (input_file, input_area, IN_BUF_SIZE);

	if (input_len < 0)
	{
		perror ("Error reading input file");
		exit (EXIT_FAILURE);
	}
}


static void write_output_area (void)

{
	int n;

	if (output_max == OUT_BUF_MAX)
	{
		output_file_length += OUT_BUF_MAX;
		output_max = OUT_BUF_SIZE;
		output_index = 0;
	}
	else
		output_max += OUT_BUF_SIZE;

	n = write (output_file, &output_area [output_index], OUT_BUF_SIZE);
	if (n < 0)
	{
		perror ("\nError writing output file");
		exit (EXIT_FAILURE);
	}
	else
	if (n < OUT_BUF_SIZE)
	{
		printf ("\nDisk full on write\n");
		exit (EXIT_FAILURE);
	}
}


unsigned long GetOutputLength (void)

{	return output_file_length + output_index;
}


unsigned long GetInputLength (void)

{	return input_file_length + input_index;
}
