
// Project: webCDwriter - Network CD Writing
//	Simulation of cdrecord for testing CDWserver

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

const char product[] = "CdrecordDummy";
const char version[] = "1.9 (i686-pc-linux-gnu)";
char lastMode[20];
int lastVal = 0;

void log(const char *mode)
{
	FILE *out = fopen("/tmp/cdrecord.last", "a");
	if (out == NULL)
		return;

	int val = 0;
	if (strcmp(mode, lastMode) == 0)
		val = lastVal + 1;
	fprintf(out, "%s %d\n", mode, val);
	fclose(out);
}

void printError(const char *arg0,
	int cmd, int key, int code, int qual, const char *str)
{
	printf("%s: Eingabe-/Ausgabefehler.\n", arg0);
	printf("CDB: %02x 00 00 00 00 00\n", cmd);
	printf("Sense Key: 0x%x Not Ready, Segment 0\n", key);
	printf("Sense Code: 0x%02x Qual 0x%02x (%s) Fru 0x0\n",
		code, qual, str);
	printf("cmd finished after 0.001s timeout 40s\n");
}

int main(int argc, char *args[])
{
	char error[40] = "no";
	FILE *in = fopen("/tmp/cdrecord.config", "r");
	if (in != NULL)
	{
		while (1)
		{
			char lineStr[80];
			fgets(lineStr, sizeof lineStr, in);
			if (feof(in))
				break;
			sscanf(lineStr, "error=%s", error);
		}
		fclose(in);
	}

	in = fopen("/tmp/cdrecord.last", "r");
	if (in == NULL)
		strcpy(lastMode, "start");
	else
	{
		while (1)
		{
			char lineStr[80];
			fgets(lineStr, sizeof lineStr, in);
			if (feof(in))
				break;
			sscanf(lineStr, "%s %d", lastMode, &lastVal);
		}
		fclose(in);
	}

	int dev = 0, speed = 1, tsize = 0;
	int dummy = 0, multi = 0, useStdin = 0, waiti = 0;
	enum { eject, files, help, inq, load, msinfo,
		scanbus, toc, version }
		mode = help;
	for (int i = 1; i < argc; i++)
		if (strcmp(args[i], "-dummy") == 0)
			dummy = 1;
		else
		if (strncmp(args[i], "dev=", 4) == 0)
			dev = 1;
		else
		if (strcmp(args[i], "-eject") == 0)
			mode = eject;
		else
		if (strcmp(args[i], "-inq") == 0)
			mode = inq;
		else
		if (strcmp(args[i], "-load") == 0)
			mode = load;
		else
		if (strcmp(args[i], "-msinfo") == 0)
			mode = msinfo;
		else
		if (strcmp(args[i], "-multi") == 0)
			multi = 1;
		else
		if (strcmp(args[i], "-scanbus") == 0)
			mode = scanbus;
		else
		if (sscanf(args[i], "speed=%d", &speed) == 1)
			;
		else
		if (strcmp(args[i], "-toc") == 0)
			mode = toc;
		else
		if (sscanf(args[i], "tsize=%ds", &tsize) == 1)
			tsize *= 2048;
		else
		if (strcmp(args[i], "-version") == 0)
			mode = version;
		else
		if (strcmp(args[i], "-waiti") == 0)
			waiti = 1;
		else
		if (strcmp(args[i], "-") == 0)
		{
			useStdin = 1;
			mode = files;
		}
		else
		if (args[i][0] != '-')
			mode = files;

	if (mode != scanbus && mode != version && !dev)
		mode = help;

	switch (mode)
	{
		case eject:
		printf("ok\n");
		log("eject");
		return 0;

		case help:
		if (!dev)
			printf("%s: No CD/DVD-Recorder device specified.\n",
				args[0]);
		printf("%s: Usage: %s [options] track1...trackn\n",
			args[0], args[0]);
		log("help");
		return 0;

		case load:
		printf("ok\n");
		log("load");
		return 0;

		case msinfo:
		printf("blank\n");
		log("msinfo");
		return 0;

		case scanbus:
		printf("   0,0,0   0) *\n");
		printf("   0,1,0   1) 'dummy   ' 'unknown CDROM   ' CD-ROM\n");
		printf("   0,4,0   4) 'dummy   ' 'unknown CD-RW   ' CD-ROM\n");
		log("scanbus");
		return 0;

		case toc:
		printf("TOC\n");
		log("toc");
		return 0;

		case inq:
		if (strcmp(lastMode, "inq") != 0
			|| lastVal < 2)
			printError(args[0], 0x00, 0x2, 0x3A, 0x00,
				"medium not present");
		else
		{
			printf("Executing 'test unit ready' command\n");
			printf("CDB:  00 00 00 00 00 00\n");
			printf("cmd finished after 0.001s timeout 40s\n");
		}
		printf("Identifikation : 'dummy'\n");
		log("inq");
		return 0;

		case version:
		printf("%s %s\n", product, ::version);
		log("version");
		return 0;
	}

	log("write");
	printf("%s %s\n", product, ::version);
	if (strcmp(error, "reloadMedia") == 0)
		printf("%s: Drive needs to reload the media"
			" to return to proper status.\n", args[0]);
	else
	if (strcmp(error, "servoFailure") == 0)
	{
		printError(args[0], 0x5B, 0x4, 0x09, 0x01,
				"tracking servo failure");
		return 1;
	}

	// normal writing
	printf("TOC Type: 1 = CD-ROM\n");

	int bytesReadFromStdin = 0;
	if (useStdin && waiti)
	{
		printf("Waiting for data on stdin...\n");
		char buf[16 * 1024];
		int n = read(0, buf, sizeof buf);
		bytesReadFromStdin += n;
	}

	// calculate session size
	int trackNo = 0, sessionSize = 0;
	const char *trackType = "data";
	for (int i = 1; i < argc; i++)
	{
		struct stat statBuf;
		if (strcmp(args[i], "-audio") == 0)
			trackType = "audio";
		else
		if (strcmp(args[i], "-data") == 0)
			trackType = "data";
		else
		if (stat(args[i], &statBuf) == 0)
		{
			printf("Track %02d: %-5s %3d MB\n",
				++trackNo,
				trackType,
				statBuf.st_size / (1024 * 1024));
			sessionSize += statBuf.st_size;
		}
		else
		if (strcmp(args[i], "-") == 0)
		{
			printf("Track %02d: %-5s %3d MB\n",
				++trackNo,
				trackType,
				tsize / (1024 * 1024));
			sessionSize += tsize;
		}
	}
	int sessionSizeMB = sessionSize / (1024 * 1024);

	printf("Current Secsize: 2048\n");
	printf("ATIP info from disk:\n");
	printf("  Is not erasable\n");
	printf("Manuf. index: 24\n");
	int blocksTotal, blocksCurrent, blocksRemaining;
	blocksTotal = 335100;
	blocksCurrent = blocksTotal;
	blocksRemaining = blocksCurrent - sessionSize / 2048;
	printf("Blocks total: %d Blocks current: %d Blocks remaining: %d\n",
		blocksTotal, blocksCurrent, blocksRemaining);
	printf("Starting to write CD/DVD at speed %d in ", speed);
	if (dummy)
		printf("dummy");
	else
		printf("write");
	printf(" mode for ");
	if (multi)
		printf("multi");
	else
		printf("single");
	printf(" session.\n");

	for (int i = 9; i > 0; i--)
	{
		const char *mode = "real";
		if (dummy)
			mode = "dummy";
		printf("\rLast chance to quit, "
			"starting %s write in %d seconds.", mode, i);
		fflush(stdout);
		sleep(1);
	}
	printf("\n");

	printf("Starting new track at sector: 0\n");
	for (int i = 0; i <= sessionSizeMB; i++)
	{
		printf("\rTrack 01: %3d of %3d MB written (fifo 100%).",
			i, sessionSizeMB);
		fflush(stdout);
		if (useStdin)
			while (bytesReadFromStdin / (1024 * 1024) <= i + 1
				&& bytesReadFromStdin < tsize)
			{
				char buf[32 * 1024];
				int n = read(0, buf, sizeof buf);
				if (n == 0)
					break;
				bytesReadFromStdin += n;
			}
		usleep(1024 * 1000 * 1000 / (150 * speed));
	}
	printf("\n");
	printf("Writing  time: %8.3fs\n",
		1000 * sessionSizeMB / (150.0 * speed));
	printf("Fixating...\n");
	sleep(2);
	printf("Fixating time: %8.3fs\n", 2.0);
}
