#include "ibm.h"
#include "fdd.h"
#include "disc.h"
#include "disc_img.h"
#include "disc_sector.h"

static struct
{
        FILE *f;
        // uint8_t track_data[2][20*1024];
        uint8_t track_data[2][50000];
        int sectors, tracks, sides;
        int sector_size;
        int rate;
	int xdf_type;	/* 0 = not XDF, 1-5 = one of the five XDF types */
	int hole;
	int byte_period;
        double bitcell_period_300rpm;
	uint32_t base;
} img[2];

#if 0
static uint8_t xdf_track0[5][3];
static uint8_t xdf_spt[5];
static uint8_t xdf_map[5][24][3];
#endif
static uint8_t xdf_track0[3][3];
static uint8_t xdf_spt[3];
static uint8_t xdf_map[3][24][3];
static uint16_t xdf_track0_layout[3][92] = {	{ 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800,
						  0x8101, 0x8201, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600,
						  0x0700, 0x0800,      0, 0x8301, 0x8401, 0x8501, 0x8601, 0x8701,
						  0x8801, 0x8901, 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01,
						  0x9001 },	/* 5.25" 2HD */
						{ 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800,
						  0x8900, 0x8A00, 0x8B00, 0x8101, 0x0100, 0x0200, 0x0300, 0x0400,
						  0x0500, 0x0600, 0x0700, 0x0800,      0,      0,      0, 0x8201,
						  0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, 0x8A01,
						  0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01,      0,      0,      0,
						       0,      0, 0x9001, 0x9101, 0x9201, 0x9301 },	/* 3.5" 2HD */
						{ 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800,
						  0x8900, 0x8A00, 0x8B00, 0x8C00, 0x0100, 0x0200, 0x0300, 0x0400,
						  0x0500, 0x0600, 0x0700, 0x0800, 0x9500, 0x9600, 0x9700,      0,
						       0,      0,      0,      0,      0,      0,      0,      0,
                                                       0,      0, 0x8D00, 0x8E00, 0x8F00, 0x9000,      0,      0,
						       0,      0,      0,      0,      0, 0x9800, 0x9900, 0x9A00,
						  0x9B00, 0x9C00, 0x9D00, 0x9E00, 0x8101, 0x8201, 0x8301, 0x8401,
						  0x8501, 0x8601, 0x8701, 0x9100, 0x9200, 0x9300, 0x9400, 0x8801,
						  0x8901, 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0x9001,
						  0x9101, 0x9201, 0x9301, 0x9401, 0x9501, 0x9601, 0x9701, 0x9801,
						  0x9901, 0x9A01, 0x9B01, 0x9C01, 0x9D01, 0x9E01, 0x9F01, 0xA001,
						  0xA101, 0xA201, 0xA301, 0xA401 },	/* 3.5" 2ED - sectors 0x91 to 0x94 of side 0 are not written to the IMG file but
											   we read them in from the null-filled areas in order to have them as XDFCOPY
											   still expects their existence even if it does nothing with them. */
						};

/* First dimension is possible sector sizes (0 = 128, 7 = 16384), second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). */
/* Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM single-RPM 5.25" drive by setting the rate to 250 kbps.
   Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM single-RPM drive by setting the rate rate to 300 kbps. */
static uint8_t maximum_sectors[8][6] = { { 26, 31, 38, 53, 64, 118 },	/*   128 */
                                         { 15, 19, 23, 32, 38,  73 },	/*   256 */
                                         {  7, 10, 12, 19, 23,  46 },	/*   512 */
                                         {  3,  5,  6,  9, 11,  22 },	/*  1024 */
                                         {  2,  2,  3,  4,  5,  11 },	/*  2048 */
                                         {  1,  1,  1,  2,  2,   5 },	/*  4096 */
					 {  0,  0,  0,  1,  1,   3 },	/*  8192 */
					 {  0,  0,  0,  0,  0,   1 } };	/* 16384 */

static int gap3_sizes[5][8][256] = {	[0][1][16] = 0x54,
				[0][2][18] = 0x6C,
				[0][2][19] = 0x48,
				[0][2][20] = 0x2A,
				[0][2][21] = 0x0C,
				// [0][2][23] = 0x7A,
				[0][2][23] = 0x01,
				// [0][2][24] = 0x38,
				[2][1][10] = 0x32,
				[2][1][11] = 0x0C,
				[2][1][15] = 0x36,
				[2][1][16] = 0x32,
				[2][2][8]  = 0x58,
				[2][2][9]  = 0x50,
				[2][2][10] = 0x2E,
				[2][2][11] = 0x02,
				[2][2][21] = 0x1C,
				[2][3][4]  = 0xF0,
				[2][3][5]  = 0x74,
				[3][2][36] = 0x53,
				[3][2][39] = 0x20,
				// [3][2][46] = 0x0E,
				[3][2][46] = 0x01,
				// [3][2][48] = 0x51,
				[4][1][32] = 0x36,
				[4][2][15] = 0x54,
				[4][2][17] = 0x23,
				[4][2][18] = 0x02,
				// [4][2][19] = 0x29,
				[4][2][19] = 0x01,
				[4][3][8]  = 0x74,
				[4][3][9]  = 0x74,
				[4][3][10] = 0x74
};

/* Needed for formatting! */
int img_realtrack(int drive, int track)
{
#ifdef MAINLINE
        if ((img[drive].tracks <= 41) && fdd_doublestep_40(drive))
#else
        if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive))
#endif
                track /= 2;

	return track;
}

void img_writeback(int drive, int track);

static int img_sector_size_code(int drive)
{
	switch(img[drive].sector_size)
	{
		case 128:
			return 0;
		case 256:
			return 1;
		default:
		case 512:
			return 2;
		case 1024:
			return 3;
		case 2048:
			return 4;
		case 4096:
			return 5;
		case 8192:
			return 6;
		case 16384:
			return 7;
	}
}

static int sector_size_code(int sector_size)
{
	switch(sector_size)
	{
		case 128:
			return 0;
		case 256:
			return 1;
		default:
		case 512:
			return 2;
		case 1024:
			return 3;
		case 2048:
			return 4;
		case 4096:
			return 5;
		case 8192:
			return 6;
		case 16384:
			return 7;
	}
}

void img_init()
{
        memset(img, 0, sizeof(img));
//        adl[0] = adl[1] = 0;
}

static void add_to_map(uint8_t *arr, uint8_t p1, uint8_t p2, uint8_t p3)
{
	arr[0] = p1;
	arr[1] = p2;
	arr[2] = p3;
}

static int xdf_maps_initialized = 0;

static void initialize_xdf_maps()
{
	// XDF 5.25" 2HD
	/* Adds, in this order: sectors per FAT, sectors per each side of track 0, difference between that and virtual sector number specified in BPB. */
	add_to_map(xdf_track0[0], 9, 17, 2);
	xdf_spt[0] = 3;
	/* Adds, in this order: side, sequential order (not used in PCem), sector size. */
	add_to_map(xdf_map[0][0], 0, 0, 3);
	add_to_map(xdf_map[0][1], 0, 2, 6);
	add_to_map(xdf_map[0][2], 1, 0, 2);
	add_to_map(xdf_map[0][3], 0, 1, 2);
	add_to_map(xdf_map[0][4], 1, 2, 6);
	add_to_map(xdf_map[0][5], 1, 1, 3);

	// XDF 3.5" 2HD
	add_to_map(xdf_track0[1], 11, 19, 4);
	xdf_spt[1] = 4;
	add_to_map(xdf_map[1][0], 0, 0, 3);
	add_to_map(xdf_map[1][1], 0, 2, 4);
	add_to_map(xdf_map[1][2], 1, 3, 6);
	add_to_map(xdf_map[1][3], 0, 1, 2);
	add_to_map(xdf_map[1][4], 1, 1, 2);
	add_to_map(xdf_map[1][5], 0, 3, 6);
	add_to_map(xdf_map[1][6], 1, 0, 4);
	add_to_map(xdf_map[1][7], 1, 2, 3);

	// XDF 3.5" 2ED
	add_to_map(xdf_track0[2], 22, 37, 9);
	xdf_spt[2] = 4;
	add_to_map(xdf_map[2][0], 0, 0, 3);
	add_to_map(xdf_map[2][1], 0, 1, 4);
	add_to_map(xdf_map[2][2], 0, 2, 5);
	add_to_map(xdf_map[2][3], 0, 3, 7);
	add_to_map(xdf_map[2][4], 1, 0, 3);
	add_to_map(xdf_map[2][5], 1, 1, 4);
	add_to_map(xdf_map[2][6], 1, 2, 5);
	add_to_map(xdf_map[2][7], 1, 3, 7);

#if 0
	// XXDF 3.5" 2HD
	add_to_map(xdf_track0[3], 12, 20, 4);
	xdf_spt[3] = 2;
	add_to_map(xdf_map[3][0], 0, 0, 5);
	add_to_map(xdf_map[3][1], 1, 1, 6);
	add_to_map(xdf_map[3][2], 0, 1, 6);
	add_to_map(xdf_map[3][3], 1, 0, 5);

	// XXDF 3.5" 2ED
	add_to_map(xdf_track0[4], 21, 39, 9);
	xdf_spt[4] = 2;
	add_to_map(xdf_map[4][0], 0, 0, 6);
	add_to_map(xdf_map[4][1], 1, 1, 7);
	add_to_map(xdf_map[4][2], 0, 1, 7);
	add_to_map(xdf_map[4][3], 1, 0, 6);
#endif

	xdf_maps_initialized = 1;
}

void img_load(int drive, char *fn)
{
        int size;
        double bit_rate_300;
	uint16_t bpb_bps;
	uint16_t bpb_total;
	uint8_t bpb_mid;	/* Media type ID. */
	uint8_t bpb_sectors;
	uint8_t bpb_sides;
	uint32_t bpt;
	uint8_t max_spt;	/* Used for XDF detection. */
	int temp_rate;
	char ext[4];
	int fdi;

	if (!xdf_maps_initialized)  initialize_xdf_maps();	/* Initialize XDF maps, will need them to properly register sectors in tracks. */

	ext[0] = fn[strlen(fn) - 3] | 0x60;
	ext[1] = fn[strlen(fn) - 2] | 0x60;
	ext[2] = fn[strlen(fn) - 1] | 0x60;
	ext[3] = 0;

	writeprot[drive] = 0;
        img[drive].f = fopen(fn, "rb+");
        if (!img[drive].f)
        {
                img[drive].f = fopen(fn, "rb");
                if (!img[drive].f)
                        return;
                writeprot[drive] = 1;
        }
        fwriteprot[drive] = writeprot[drive];

	if (strcmp(ext, "fdi") == 0)
	{
		/* This is a Japanese FDI image, so let's read the header */
		pclog("img_load(): File is a Japanese FDI image...\n");
		fseek(img[drive].f, 0x10, SEEK_SET);
		fread(&bpb_bps, 1, 2, img[drive].f);
		fseek(img[drive].f, 0x0C, SEEK_SET);
		fread(&size, 1, 4, img[drive].f);
		bpb_total = size / bpb_bps;
		fseek(img[drive].f, 0x08, SEEK_SET);
		fread(&(img[drive].base), 1, 4, img[drive].f);
		fseek(img[drive].f, img[drive].base + 0x15, SEEK_SET);
		bpb_mid = fgetc(img[drive].f);
		if (bpb_mid < 0xF0)  bpb_mid = 0xF0;
		fseek(img[drive].f, 0x14, SEEK_SET);
		bpb_sectors = fgetc(img[drive].f);
		fseek(img[drive].f, 0x18, SEEK_SET);
		bpb_sides = fgetc(img[drive].f);

		fdi = 1;
	}
	else
	{
		/* Read the BPB */
		pclog("img_load(): File is a raw image...\n");
		fseek(img[drive].f, 0x0B, SEEK_SET);
		fread(&bpb_bps, 1, 2, img[drive].f);
		fseek(img[drive].f, 0x13, SEEK_SET);
		fread(&bpb_total, 1, 2, img[drive].f);
		fseek(img[drive].f, 0x15, SEEK_SET);
		bpb_mid = fgetc(img[drive].f);
		fseek(img[drive].f, 0x18, SEEK_SET);
		bpb_sectors = fgetc(img[drive].f);
		fseek(img[drive].f, 0x1A, SEEK_SET);
		bpb_sides = fgetc(img[drive].f);

		img[drive].base = 0;
		fdi = 0;

	        fseek(img[drive].f, -1, SEEK_END);
	        size = ftell(img[drive].f) + 1;
	}

        img[drive].sides = 2;
        img[drive].sector_size = 512;

	img[drive].hole = 0;

	pclog("BPB reports %i sides and %i bytes per sector\n", bpb_sides, bpb_bps);

	if (((bpb_sides < 1) || (bpb_sides > 2) || (bpb_bps < 128) || (bpb_bps > 2048)) && !fdi)
	{
		/* The BPB is giving us a wacky number of sides and/or bytes per sector, therefore it is most probably
		   not a BPB at all, so we have to guess the parameters from file size. */

		if (size <= (160*1024))        { img[drive].sectors = 8;  img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; raw_tsize[drive] = 6250; }
	        else if (size <= (180*1024))   { img[drive].sectors = 9;  img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; raw_tsize[drive] = 6250; }
	        else if (size <= (320*1024))   { img[drive].sectors = 8;  img[drive].tracks = 40; bit_rate_300 = 250; raw_tsize[drive] = 6250; }
	        else if (size <= (360*1024))   { img[drive].sectors = 9;  img[drive].tracks = 40; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density*/
	        else if (size <= (640*1024))   { img[drive].sectors = 8;  img[drive].tracks = 80; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density 640k*/
	        else if (size < (1024*1024))   { img[drive].sectors = 9;  img[drive].tracks = 80; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density*/
	        else if (size <= 1228800)      { img[drive].sectors = 15; img[drive].tracks = 80; bit_rate_300 = (500.0 * 300.0) / 360.0; raw_tsize[drive] = 10416; } /*High density 1.2MB*/
	        else if (size <= 1261568)      { img[drive].sectors =  8; img[drive].tracks = 77; img[drive].sector_size = 1024; bit_rate_300 = (500.0 * 300.0) / 360.0; raw_tsize[drive] = 10416; } /*High density 1.25MB Japanese format*/
	        else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/
	        else if (size <= 1556480)      { img[drive].sectors = 19; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/
	        else if (size <= 1638400)      { img[drive].sectors = 10; img[drive].tracks = 80; img[drive].sector_size = 1024; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/
	        // else if (size == 1884160)      { img[drive].sectors = 23; img[drive].tracks = 80; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/
	        // else if (size == 1763328)      { img[drive].sectors = 21; img[drive].tracks = 82; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/
	        else if (size <= 2000000)   { img[drive].sectors = 21; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*DMF format - used by Windows 95 - changed by OBattler to 2000000, ie. the real unformatted capacity @ 500 kbps and 300 rpm */
	        else if (size <= 2949120)   { img[drive].sectors = 36; img[drive].tracks = 80; bit_rate_300 = 1000; raw_tsize[drive] = 25000; } /*E density*/

		temp_rate = 2;
		bpb_bps = img[drive].sector_size;
		bpt = bpb_bps * img[drive].sectors;
		if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][0] * bpb_bps))
		{
			temp_rate = 2;
			raw_tsize[drive] = 5208;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][1] * bpb_bps))
		{
			temp_rate = 2;
			raw_tsize[drive] = 6250;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][2] * bpb_bps))
		{
			temp_rate = 1;
			raw_tsize[drive] = 7500;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][3] * bpb_bps))
		{
			if (bpb_bps == 512)  max_spt = (bit_rate_300 == 500) ? 21 : 17;
			temp_rate = (bit_rate_300 == 500) ? 0 : 4;
			raw_tsize[drive] = (bit_rate_300 == 500) ? 12500 : 10416;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][4] * bpb_bps))
		{
			if (bpb_bps == 512)  max_spt = 21;
			pclog("max_spt is %i\n", max_spt);
			temp_rate = 0;
			raw_tsize[drive] = 12500;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][5] * bpb_bps))
		{
			if (bpb_bps == 512)  max_spt = 41;
			temp_rate = 3;
			raw_tsize[drive] = 25000;
		}
		else					/* Image too big, eject */
		{
			pclog("Image is bigger than can fit on an ED floppy, ejecting...\n");
			fclose(img[drive].f);
			return;
		}

		pclog("Temporary rate: %i (%i bytes per track)\n", temp_rate, bpt);

		img[drive].xdf_type = 0;
	}
	else
	{
		/* The BPB readings appear to be valid, so let's set the values. */
		/* Number of tracks = number of total sectors divided by sides times sectors per track. */
		if (fdi)
		{
			/* The image is a Japanese FDI, therefore we read the number of tracks from the header. */
			fseek(img[drive].f, 0x1C, SEEK_SET);
			fread(&(img[drive].tracks), 1, 4, img[drive].f);
		}
		else
		{
			img[drive].tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors));
		}
		/* The rest we just set directly from the BPB. */
		img[drive].sectors = bpb_sectors;
		img[drive].sides = bpb_sides;
		/* The sector size. */
		img[drive].sector_size = bpb_bps;
		/* Now we calculate bytes per track, which is bpb_sectors * bpb_bps. */
		bpt = (uint32_t) bpb_sectors * (uint32_t) bpb_bps;
		/* Now we should be able to calculate the bit rate. */
		pclog("The image has %i bytes per track\n", bpt);

		temp_rate = 2;
		if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][0] * bpb_bps))
		{
			bit_rate_300 = ((250.0 * 300.0) / 360.0);
			temp_rate = 2;
			raw_tsize[drive] = 5208;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][1] * bpb_bps))
		{
			bit_rate_300 = 250;
			temp_rate = 2;
			raw_tsize[drive] = 6250;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][2] * bpb_bps))
		{
			bit_rate_300 = 300;
			temp_rate = 1;
			raw_tsize[drive] = 7500;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][3] * bpb_bps))
		{
			bit_rate_300 = (bpb_mid == 0xF0) ? 500 : ((500.0 * 300.0) / 360.0);
			if (bpb_bps == 512)  max_spt = (bit_rate_300 == 500) ? 21 : 17;
			temp_rate = (bit_rate_300 == 500) ? 0 : 4;
			raw_tsize[drive] = (bit_rate_300 == 500) ? 12500 : 10416;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][4] * bpb_bps))
		{
			bit_rate_300 = 500;
			if (bpb_bps == 512)  max_spt = 21;
			pclog("max_spt is %i\n", max_spt);
			temp_rate = 0;
			raw_tsize[drive] = 12500;
		}
		else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][5] * bpb_bps))
		{
			bit_rate_300 = 1000;
			if (bpb_bps == 512)  max_spt = 41;
			temp_rate = 3;
			raw_tsize[drive] = 25000;
		}
		else					/* Image too big, eject */
		{
			pclog("Image is bigger than can fit on an ED floppy, ejecting...\n");
			fclose(img[drive].f);
			return;
		}

		if (bpb_bps == 512)			/* BPB reports 512 bytes per sector, let's see if it's XDF or not */
		{
			if (bit_rate_300 <= 300)	/* Double-density disk, not XDF */
			{
				img[drive].xdf_type = 0;
			}
			else
			{
				pclog("bpb_sectors is %i\n", bpb_sectors);
				if (bpb_sectors > max_spt)
				{
					switch(bpb_sectors)
					{
						case 19:	/* High density XDF @ 360 rpm */
							img[drive].xdf_type = 1;
							break;
						case 23:	/* High density XDF @ 300 rpm */
							img[drive].xdf_type = 2;
							pclog("XDF type is 2 @ %i kbps\n", bit_rate_300);
							break;
#if 0
						case 24:	/* High density XXDF @ 300 rpm */
							img[drive].xdf_type = 4;
							break;
#endif
						case 46:	/* Extended density XDF */
							img[drive].xdf_type = 3;
							break;
#if 0
						case 48:	/* Extended density XXDF */
							img[drive].xdf_type = 5;
							break;
#endif
						default:	/* Unknown, as we're beyond maximum sectors, get out */
							fclose(img[drive].f);
							return;
					}
				}
				else			/* Amount of sectors per track that fits into a track, therefore not XDF */
				{
					img[drive].xdf_type = 0;
				}
			}
		}
		else					/* BPB reports sector size other than 512, can't possibly be XDF */
		{
			img[drive].xdf_type = 0;
		}
	}

	gap2_size[drive] = (temp_rate == 3) ? 41 : 22;
	pclog("GAP2 size: %i bytes\n", gap2_size[drive]);
	gap3_size[drive] = gap3_sizes[temp_rate][sector_size_code(img[drive].sector_size)][img[drive].sectors];
	if (gap3_size)
	{
		pclog("GAP3 size: %i bytes\n", gap3_size[drive]);
	}
	else
	{
		// fclose(img[drive].f);
		gap3_size[drive] = 40;
		pclog("WARNING: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41);
	}
	gap4_size[drive] = raw_tsize[drive] - (((pre_gap + gap2_size[drive] + pre_data + img[drive].sector_size + post_gap + gap3_size[drive]) * img[drive].sectors) + pre_track);
	pclog("GAP4 size: %i bytes\n", gap4_size[drive]);
	if (img[drive].xdf_type)
	{
		gap4_size[drive] = 1;
	}

	if (bit_rate_300 == 250)
	{
		img[drive].hole = 0;
		/* If drive does not support 300 RPM, the medium is to be read at a period of 26 (300 kbps). */
		img[drive].byte_period = 29;
	}
	else if (bit_rate_300 == 300)
	{
		img[drive].hole = 0;
		img[drive].byte_period = 26;
	}
	else if (bit_rate_300 == 1000)
	{
		img[drive].hole = 2;
		img[drive].byte_period = 8;
	}
	else if (bit_rate_300 < 250)
	{
		img[drive].hole = 0;
		img[drive].byte_period = 32;
	}
	else
	{
		img[drive].hole = 1;
		img[drive].byte_period = 16;
	}

	if (img[drive].xdf_type)			/* In case of XDF-formatted image, write-protect */
	{
                writeprot[drive] = 1;
	        fwriteprot[drive] = writeprot[drive];
	}

        drives[drive].seek        = img_seek;
        drives[drive].readsector  = disc_sector_readsector;
        drives[drive].writesector = disc_sector_writesector;
        drives[drive].readaddress = disc_sector_readaddress;
        drives[drive].hole        = img_hole;
        drives[drive].byteperiod  = img_byteperiod;
        drives[drive].poll        = disc_sector_poll;
        drives[drive].format      = disc_sector_format;
        drives[drive].realtrack   = img_realtrack;
        drives[drive].stop        = disc_sector_stop;
        disc_sector_writeback[drive] = img_writeback;
        
        img[drive].bitcell_period_300rpm = 1000000.0 / bit_rate_300*2.0;
        pclog("bit_rate_300=%g\n", bit_rate_300);
        pclog("bitcell_period_300=%g\n", img[drive].bitcell_period_300rpm);
//        img[drive].bitcell_period_300rpm = disc_get_bitcell_period(img[drive].rate);
        pclog("img_load %d %p sectors=%i tracks=%i sides=%i sector_size=%i hole=%i\n", drive, drives, img[drive].sectors, img[drive].tracks, img[drive].sides, img[drive].sector_size, img[drive].hole);
}

int img_hole(int drive)
{
	return img[drive].hole;
}

int img_byteperiod(int drive)
{
	if (img[drive].byte_period == 29)
	{
		return (fdd_get_type(drive) & 1) ? 32 : 26;
	}
	return img[drive].byte_period;
}

void img_close(int drive)
{
        if (img[drive].f)
                fclose(img[drive].f);
        img[drive].f = NULL;
}

void img_seek(int drive, int track)
{
        int side;
	int current_xdft = img[drive].xdf_type - 1;

	uint8_t sectors_fat, effective_sectors, sector_gap;		/* Needed for XDF */

	int sector, current_pos, sh, sr, spos, sside;
        
        if (!img[drive].f)
                return;
        // pclog("Seek drive=%i track=%i sectors=%i sector_size=%i sides=%i\n", drive, track, img[drive].sectors,img[drive].sector_size, img[drive].sides);
//        pclog("  %i %i\n", drive_type[drive], img[drive].tracks);
#ifdef MAINLINE
        if ((img[drive].tracks <= 41) && fdd_doublestep_40(drive))
#else
        if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive))
#endif
                track /= 2;

	// pclog("Disk seeked to track %i\n", track);
        disc_track[drive] = track;

        if (img[drive].sides == 2)
        {
                fseek(img[drive].f, img[drive].base + (track * img[drive].sectors * img[drive].sector_size * 2), SEEK_SET);
		// pclog("Seek: Current file position (H0) is: %08X\n", ftell(img[drive].f));
                fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
		// pclog("Seek: Current file position (H1) is: %08X\n", ftell(img[drive].f));
                fread(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
        }
        else
        {
                fseek(img[drive].f, img[drive].base + (track * img[drive].sectors * img[drive].sector_size), SEEK_SET);
                fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
        }
        
        disc_sector_reset(drive, 0);
        disc_sector_reset(drive, 1);
        
	if (img[drive].xdf_type)
	{
		sectors_fat = xdf_track0[current_xdft][0];
		effective_sectors = xdf_track0[current_xdft][1];
		sector_gap = xdf_track0[current_xdft][2];

		if (!track)
		{
			/* Track 0, register sectors according to track 0 layout. */
			current_pos = 0;
			for (sector = 0; sector < (img[drive].sectors * 2); sector++)
			{
				if (xdf_track0_layout[current_xdft][sector])
				{
					sh = xdf_track0_layout[current_xdft][sector] & 0xFF;
					sr = xdf_track0_layout[current_xdft][sector] >> 8;
					spos = current_pos;
					sside = 0;
					if (spos > (img[drive].sectors * img[drive].sector_size))
					{
						spos -= (img[drive].sectors * img[drive].sector_size);
						sside = 1;
					}
		                        disc_sector_add(drive, sh, track, sh, sr, 2,
       			                                img[drive].bitcell_period_300rpm, 
               			                        &img[drive].track_data[sside][spos]);
				}
				current_pos += 512;
			}
#if 0
			/* Track 0, register sectors according to track 0 map. */
			/* First, the "Side 0" buffer, will also contain one sector from side 1. */
			current_pos = 0;
	                for (sector = 0; sector < sectors_fat; sector++)
			{
				if ((sector+0x81) >= 0x91)
				{
		                        disc_sector_add(drive, 0, track, 0, sector+0x85, 2,
       			                                img[drive].bitcell_period_300rpm, 
               			                        &img[drive].track_data[0][current_pos]);
				}
				else
				{
		                        disc_sector_add(drive, 0, track, 0, sector+0x81, 2,
       			                                img[drive].bitcell_period_300rpm, 
               			                        &img[drive].track_data[0][current_pos]);
				}
				current_pos += 512;
			}
                        disc_sector_add(drive, 1, track, 1, 0x81, 2,
				img[drive].bitcell_period_300rpm, 
				&img[drive].track_data[0][current_pos]);
			current_pos += 512;
	                for (sector = 0; sector < 7; sector++)
			{
	                        disc_sector_add(drive, 0, track, 0, sector+1, 2,
       		                                img[drive].bitcell_period_300rpm, 
               		                        &img[drive].track_data[0][current_pos]);
				current_pos += 512;
			}
                        disc_sector_add(drive, 0, track, 0, 0x9B, 2,
				img[drive].bitcell_period_300rpm, 
				&img[drive].track_data[0][current_pos]);
			current_pos += 512;
                        disc_sector_add(drive, 0, track, 0, 0x9C, 2,
				img[drive].bitcell_period_300rpm, 
				&img[drive].track_data[0][current_pos]);
			current_pos += 512;
                        disc_sector_add(drive, 0, track, 0, 0x9D, 2,
				img[drive].bitcell_period_300rpm, 
				&img[drive].track_data[0][current_pos]);
			current_pos += 512;
                        disc_sector_add(drive, 0, track, 0, 0x9E, 2,
				img[drive].bitcell_period_300rpm, 
				&img[drive].track_data[0][current_pos]);
			current_pos += 512;
			/* Now the "Side 1" buffer, will also contain one sector from side 0. */
			current_pos = 0;
	                for (sector = 0; (sector < effective_sectors - 1); sector++)
			{
	                        disc_sector_add(drive, 1, track, 1, sector+0x82, 2,
       		                                img[drive].bitcell_period_300rpm, 
               		                        &img[drive].track_data[1][current_pos]);
				current_pos += 512;
			}
                        disc_sector_add(drive, 0, track, 0, 8, 2,
				img[drive].bitcell_period_300rpm, 
				&img[drive].track_data[1][current_pos]);
			current_pos += 512;
#endif
		}
		else
		{
			/* Non-zero track, this will have sectors of various sizes. */
			/* First, the "Side 0" buffer. */
			current_pos = 0;
	                for (sector = 0; sector < xdf_spt[current_xdft]; sector++)
			{
	                        disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0],
						xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2],
       		                                img[drive].bitcell_period_300rpm, 
               		                        &img[drive].track_data[0][current_pos]);
				current_pos += (128 << xdf_map[current_xdft][sector][2]);
			}
			/* Then, the "Side 1" buffer. */
			current_pos = 0;
	                for (sector = xdf_spt[current_xdft]; sector < (xdf_spt[current_xdft] << 1); sector++)
			{
	                        disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0],
						xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2],
       		                                img[drive].bitcell_period_300rpm, 
               		                        &img[drive].track_data[1][current_pos]);
				current_pos += (128 << xdf_map[current_xdft][sector][2]);
			}
		}
	}
	else
	{                
	        for (side = 0; side < img[drive].sides; side++)
       		{
	                for (sector = 0; sector < img[drive].sectors; sector++)
        	                disc_sector_add(drive, side, track, side, sector+1, img_sector_size_code(drive),
       	        	                        img[drive].bitcell_period_300rpm, 
               	        	                &img[drive].track_data[side][sector * img[drive].sector_size]);
		}
	}
	for (side = img[drive].sides - 1; side >= 0; side--)
	{
		disc_sector_prepare_track_layout(drive, side);
	}
}

void img_writeback(int drive, int track)
{
        if (!img[drive].f)
                return;
                
        if (img[drive].xdf_type)
                return; /*Should never happen*/

        if (img[drive].sides == 2)
        {
                fseek(img[drive].f, img[drive].base + (track * img[drive].sectors * img[drive].sector_size * 2), SEEK_SET);
                fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
                fwrite(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
        }
        else
        {
                fseek(img[drive].f, img[drive].base + (track * img[drive].sectors * img[drive].sector_size), SEEK_SET);
                fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
        }
}

