// ----------------------------------------
// DCM2NTRQ
// Command-line to to patch NTRQ with DPCM
// ----------------------------------------

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_SAMPLES 0x40
#define NTRQ_DPCM_ADDRESS 0xC900
#define NTRQ_ROM_HEADER 0x10
#define NSFBIN_DPCM_ADDRESS 0x4900
#define NSFBIN_HEADER 0x80
#define NTRQ_DPCM_END 0xFE00
#define MAX_DPCM_BANK_SIZE (NTRQ_DPCM_END - NTRQ_DPCM_ADDRESS)

int getFileSize (FILE *file)
{
	int size;
	fseek(file, 0, SEEK_END);
	size = ftell(file);
	fseek(file, 0, SEEK_SET);
	return size;
}

struct sample {
	char name[128];
	unsigned int address;
	unsigned int length;
};

int main (int argc, const char * argv[]) {
	FILE *file;
	FILE *sample;
	char *ptr;
	char line [128];
	unsigned int sampleNumber;
	char *fileBuffer;
	struct sample sampleArray[MAX_SAMPLES];
	
	unsigned int ROM_SIZE;
	unsigned int bankSize = 0;
	unsigned int sampleSize = 0;
	unsigned int currentSampleAddress;;
	
	const char *inputName;
	const char *outputName;
	const char *patchNSF;


	if (argc < 4) {
	  printf("\n");
	  printf("DCM2NTRQ V1.0: NTRQ ROM Patcher\n\n");
	  printf("Usage : DCM2NTRQ <patchfile.txt> <output.nes> <patch NSF exporter y/n>\n\n");
	  printf("- 'patchfile.txt' needs to be a plain text file that is a list of DCM samples, one per line, that you would like to patch the NTRQ ROM with.\n\n"); 
	  printf("- 'output.nes' is the patched ROM filename.\n\n");
	  printf("- 'y/n' to specify whether or not you want the NSF exporter patching too.\n\n");
	printf("** NTRQ.NES and NTRQNSF.BIN are required in the folder/directory where you run the patcher. **\n\n\n");
	return 0;
	}	
	
	inputName = argv[1];
	outputName = argv[2];
	
	if (argc == 4) {
		patchNSF = argv[3];
	}
	
	//Quick, crude check to make sure maximum bank size not exceeded
	file = fopen (inputName,"r");
	if (file==NULL)
	{
		printf("\n\nError, could not open sample list %s\n\n", inputName);
		fclose(file);
		return 0;
	}
	printf("\nJust checking that your samples will all fit!\n\n");
	sampleNumber = 0;
	currentSampleAddress = 0x0000;
	while (fgets(line, sizeof line, file) !=NULL)
	{
		//Replace "newline" char with string terminator
		if( (ptr = strchr(line, '\n')) != NULL) *ptr = '\0';

		//Open and get size
		sample = fopen(line, "rb");
		if (sample == NULL)
		{
			printf("\nError, could not open file %s\n\n", line);
			fclose (sample);
			return 0;
		}
		sampleSize = getFileSize(sample);
		fclose (sample);
		
		//Store information about sample in array for patching process
		strncpy(sampleArray[sampleNumber].name, line, 128);
		sampleArray[sampleNumber].address = currentSampleAddress;
		sampleArray[sampleNumber].length = sampleSize;
		
		//Compute bank size		
		bankSize = bankSize + sampleSize;
		printf("%s ", sampleArray[sampleNumber].name);
		printf(": addr:%X size=%d\n", sampleArray[sampleNumber].address, sampleArray[sampleNumber].length);
		currentSampleAddress += sampleSize;
		sampleNumber++;
	}
	fclose(file);
	

	printf("\nMaximum bank size: %d", MAX_DPCM_BANK_SIZE);
	printf("\nYour bank size: %d\n", bankSize);

	if (currentSampleAddress > NTRQ_DPCM_END)
	{
		printf("\nYou were a bit optimistic, bank is %d bytes too big! Quitting.\n\n", abs(NTRQ_DPCM_END-currentSampleAddress));
		return -1;
	}

	//Bank size is OK so patch ROM & NSF binary
	
	printf("\nBank size is OK\n\n");
	printf("PATCHING ROM : NTRQ.NES\n\n");
	
	//Need "extra" address in table so that NES code can calculate sample length
	sampleArray[sampleNumber].address = currentSampleAddress;
	sampleNumber++;

	//Read ROM into buffer
	file = fopen("ntrq.nes", "rb");
	if (file==NULL)
	{
		printf("\n\nError, could not find NTRQ ROM, ntrq.nes\n\n");
		fclose(file);
		return 0;
	}
	ROM_SIZE = getFileSize(file);
	fileBuffer = malloc(ROM_SIZE);
	fread(fileBuffer, 1, ROM_SIZE, file);	
	fclose (file);
	
	// Write new sample address table into ROM (buffer)
	int a;
	unsigned char dpcmAddress;
	for (a=0;a<sampleNumber;a++)
	{
		dpcmAddress = ((sampleArray[a].address + 0x40 + NTRQ_DPCM_ADDRESS) >> 6) & 0xFF;
		//printf("%X\n", (unsigned char)dpcmAddress);
		fileBuffer[NTRQ_DPCM_ADDRESS + NTRQ_ROM_HEADER + a]=dpcmAddress;
	}
	
	char *sampleBuffer;
	
	currentSampleAddress = NTRQ_DPCM_ADDRESS + NTRQ_ROM_HEADER + MAX_SAMPLES; //0x40
	for (a=0;a<(sampleNumber-1);a++)
	{
		// Read sample into memory
		sample = fopen(sampleArray[a].name,"rb");
		sampleBuffer = malloc(sampleArray[a].length);
		fread(sampleBuffer, 1, sampleArray[a].length, sample);
		fclose(sample);
		
		// Patch ROM with sample data 
		memcpy(&fileBuffer[currentSampleAddress], sampleBuffer, sampleArray[a].length);
		currentSampleAddress += sampleArray[a].length;
		free (sampleBuffer);
	}
	
	//Write buffer to ROM
	file = fopen(outputName,"wb");
	if (file==NULL)
	{
		printf("\n\nError, could not open output file, %s\n\n", outputName);
		fclose(file);
		free (fileBuffer);
		return 0;
	}
	fwrite(fileBuffer, 1, ROM_SIZE, file);
	fclose(file);
	//Free file buffer
	free (fileBuffer);
	
	//printf("\n%c\n", *patchNSF);
	
	if ((*patchNSF != 'y') && (*patchNSF != 'Y'))
	{
		printf("Not patching NSF exporter binary.\n\n");
		return 0;
	} else
	{
		//Read NSF binary into buffer
		printf("\nPatching NTRQNSF.BIN...\n\n");
		file = fopen("NTRQNSF.BIN", "rb");
		if (file==NULL)
		{
			printf("\n\nError, could not open NTRQNSF.BIN to patch it.\n\n");
			fclose(file);
			return 0;
		}
		ROM_SIZE = getFileSize(file);
		fileBuffer = malloc(ROM_SIZE);
		fread(fileBuffer, 1, ROM_SIZE, file);	
		fclose (file);
	
		// Write new sample address table into ROM (buffer)
		for (a=0;a<sampleNumber;a++)
		{
			dpcmAddress = ((sampleArray[a].address + 0x40 + NTRQ_DPCM_ADDRESS) >> 6) & 0xFF;
			//printf("%X\n", (unsigned char)dpcmAddress);
			fileBuffer[NSFBIN_DPCM_ADDRESS + NSFBIN_HEADER + a]=dpcmAddress;
		}
	
		currentSampleAddress = NSFBIN_DPCM_ADDRESS + NSFBIN_HEADER + MAX_SAMPLES; //0x40
		for (a=0;a<(sampleNumber-1);a++)
		{
			// Read sample into memory
			sample = fopen(sampleArray[a].name,"rb");
			sampleBuffer = malloc(sampleArray[a].length);
			fread(sampleBuffer, 1, sampleArray[a].length, sample);
			fclose(sample);
		
			// Patch ROM with sample data 
			memcpy(&fileBuffer[currentSampleAddress], sampleBuffer, sampleArray[a].length);
			currentSampleAddress += sampleArray[a].length;
			free (sampleBuffer);
		}
	
		//Write buffer to ROM
		file = fopen("NTRQNSF.BIN","wb");
		if (file==NULL)
		{
			printf("\n\nError, could not open NTRQNSF.BIN for writing.\n\n");
			fclose (file);
			free (fileBuffer);
			return 0;
		}
		fwrite(fileBuffer, 1, ROM_SIZE, file);
		fclose(file);
		//Free file buffer
		free (fileBuffer);		
	}
	
	
	return 0;
}
