/**
 * Kohi Version Generator.
 */

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

void print_use (void) {
	printf(
		"Kohi Version Generator Utility\n"
		"   usage: 'versiongen -n|<filename> [-outfile=<write_filename>]'\n "
		"   -n : Numeric-only mode that emits only numbers. Note that only a build and revision are generated.\n"
		"examples:\n"
		"   'versiongen version.txt' generates something like '1.3.0.22278-12345' (where the contents of version.txt are '1.3.0')\n"
		"   'versiongen -n' generates something like '2227812345'.\n"
		"   'versiongen version.txt -outfile=version.h -build_type=D does the same thing as 'versiongen version.txt', but writes out to the outfile, including a comment and #define KVERSION <version>, and also specifies build type (D=Debug, R=Release, anything else=Unknown)");
}

// NOTE: This is intentionally kept to a small number to prevent injection of any kind.
#define MAX_VERSION_FILE_READ_SIZE 20

int main (int argc, const char **argv) {
	int b_numeric_mode = 0;
	const char *version_text_file = 0;
	char *out_file = 0;
	char *bt = 0;

	// Account for null terminator
	char read_version[MAX_VERSION_FILE_READ_SIZE + 1] = {0};
	if (argc >= 2) {
		if ((argv[1][0] == '-') && (argv[1][1] == 'n')) {
			b_numeric_mode = 1;
		} else {
			version_text_file = argv[1];
			if (argc >= 3) {
				int len = strlen(argv[2]);
				out_file = malloc(len - 9 + 1);
				strncpy(out_file, argv[2] + 9, len - 9);
				out_file[len - 9] = 0;
				printf("out_file: '%s'\n", out_file);
			}

			if (argc == 4) {
				int len = strlen(argv[3]);
				bt = malloc(len - 12 + 1);
				strncpy(bt, argv[3] + 12, len - 12);
				bt[len - 12] = 0;
				printf("build_type: '%s'\n", bt);
			}
			// Read the text from the version file.
			FILE *f = fopen(version_text_file, "r");
			if (!f) {
				printf("Error opening verion file: %s. Using a default version of 0.0.0.", version_text_file);
				strncpy(read_version, "0.0.0", 7);
				read_version[6] = 0;
			} else {
				fseek(f, 0, SEEK_END);
				long fsize = ftell(f);
				// Clamp
				if (fsize > MAX_VERSION_FILE_READ_SIZE) {
					fsize = MAX_VERSION_FILE_READ_SIZE;
				}
				fseek(f, 0, SEEK_SET);

				size_t result = fread(read_version, 1, fsize, f);
				if (!result) {
					printf("Error reading version file. Cannot proceed.");
					return 1;
				}
				fclose(f);
				for (int i = fsize - 1; i >= 0; --i) {
					char c = read_version[i];
					if (c == '\n' || c == '\r' || c == 0 || c == ' ') {
						read_version[i] = 0;
					}
				}
			}
		}
	} else {
		print_use();
		return 1;
	}

	time_t timer;
	struct tm *tm_info;

	timer = time(0);
	tm_info = localtime(&timer);

	int revision = (tm_info->tm_hour * 60 * 60) + (tm_info->tm_min * 60) + tm_info->tm_sec;

	if (out_file) {
		FILE *wf = fopen(out_file, "w");
		char buf[256] = {0};
		memset(buf, 0, 256);

		if (b_numeric_mode) {
			// BUILDREV
			// build = last 2 of year and day of year
			// rev = number of seconds since midnight
			sprintf(buf, "#define KVERSION \"%02d%02d%05d\"\n", tm_info->tm_year % 100, tm_info->tm_yday, revision);
		} else {
			// MAJOR.MINOR.PATCH.BUILD-REV
			// build = last 2 of year and day of year
			// rev = number of seconds since midnight
			sprintf(buf, "#define KVERSION \"%s.%02d%02d-%05d\"\n", read_version, tm_info->tm_year % 100, tm_info->tm_yday, revision);
		}
		const char *comment = "// NOTE: This file is automatically generated by the build process and should not be checked in.\n";
		fwrite(comment, strlen(comment), 1, wf);
		fwrite(buf, strlen(buf), 1, wf);

		// Build type.
		const char *build_type = "Unknown";
		if (strcmp(bt, "D") == 0 || strcmp(bt, "d") == 0) {
			build_type = "Debug";
		} else if (strcmp(bt, "R") == 0 || strcmp(bt, "r") == 0) {
			build_type = "Release";
		}

		memset(buf, 0, 256);
		sprintf(buf, "#define KBUILDTYPE \"%s\"\n", build_type);
		fwrite(buf, strlen(buf), 1, wf);

		fclose(wf);
	} else {
		if (b_numeric_mode) {
			// BUILDREV
			// build = last 2 of year and day of year
			// rev = number of seconds since midnight
			printf("%02d%02d%05d", tm_info->tm_year % 100, tm_info->tm_yday, revision);
		} else {
			// MAJOR.MINOR.PATCH.BUILD-REV
			// build = last 2 of year and day of year
			// rev = number of seconds since midnight
			printf("%s.%02d%02d-%05d", read_version, tm_info->tm_year % 100, tm_info->tm_yday, revision);
		}
	}
	return 0;
}
