#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _GNU_SOURCE
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "hdd_file.h"

#ifdef __APPLE__
#define fopen64 fopen
#define fseeko64 fseek
#define off64_t off_t
#endif

void hdd_load(hdd_file_t *hdd, const char *fn, int sectors)
{
	if (hdd->f == NULL)
	{
		/* Try to open existing hard disk image */
		hdd->f = fopen64(fn, "rb+");
		if (hdd->f == NULL)
		{
			/* Failed to open existing hard disk image */
			if (errno == ENOENT)
			{
				/* Failed because it does not exist,
				   so try to create new file */
				hdd->f = fopen64(fn, "wb+");
				if (hdd->f == NULL)
				{
//					aka31_log("Cannot create file '%s': %s",
//					      fn, strerror(errno));
					return;
				}
			}
			else
			{
				/* Failed for another reason */
//				aka31_log("Cannot open file '%s': %s",
//				      fn, strerror(errno));
				return;
			}
		}
	}

	hdd->sectors = sectors;
}

void hdd_close(hdd_file_t *hdd)
{
	if (hdd->f)
	{
		fclose(hdd->f);
		hdd->f = NULL;
	}
}

int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
{
	off64_t addr;
	int transfer_sectors = nr_sectors;

	if ((hdd->sectors - offset) < transfer_sectors)
		transfer_sectors = hdd->sectors - offset;
	addr = (uint64_t)offset * 512;

	fseeko64(hdd->f, addr, SEEK_SET);
	fread(buffer, transfer_sectors*512, 1, hdd->f);

	if (nr_sectors != transfer_sectors)
		return 1;
	return 0;
}

int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer)
{
	off64_t addr;
	int transfer_sectors = nr_sectors;

	if ((hdd->sectors - offset) < transfer_sectors)
		transfer_sectors = hdd->sectors - offset;
	addr = (uint64_t)offset * 512;

	fseeko64(hdd->f, addr, SEEK_SET);
	fwrite(buffer, transfer_sectors*512, 1, hdd->f);

	if (nr_sectors != transfer_sectors)
		return 1;
	return 0;
}

int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors)
{
	off64_t addr;
	int c;
	uint8_t zero_buffer[512];
	int transfer_sectors = nr_sectors;

	memset(zero_buffer, 0, 512);

	if ((hdd->sectors - offset) < transfer_sectors)
		transfer_sectors = hdd->sectors - offset;
	addr = (uint64_t)offset * 512;
	fseeko64(hdd->f, addr, SEEK_SET);
	for (c = 0; c < transfer_sectors; c++)
		fwrite(zero_buffer, 512, 1, hdd->f);

	if (nr_sectors != transfer_sectors)
		return 1;
	return 0;
}
