/*
 * Humax HMT Tool
 * (c) af123, 2011-2016
 */

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include "lint.h"

int debug = 0;
const char *version = "2.0.11";
unsigned long sysopts = 0;

int
syntax()
{
	fprintf(stderr, "Humax HMT Tool v%s, by af123, 2011-2019.\n\n",
	    version);
	fprintf(stderr,
	    "Syntax: hmt [command] <filename> [filename] ...\n");
	fprintf(stderr,
	    "  Commands:\n"
            "    +/-new        Mark/unmark recording as new.\n"
            "    +/-lock       Mark/unmark recording as locked.\n"
            "    +/-guidance   Mark/unmark recording as having guidance.\n"
	);
	fprintf(stderr,
	    "    +/-protect    Enable/disable protection"
	    " (prevents decryption on copy).\n"
	    "    +/-encrypted  Mark/unmark recording as encrypted.\n"
	    "    +/-shrunk     Mark/unmark recording as shrunk.\n"
	    "    +/-dedup      Mark/unmark recording as deduped.\n"
	    "    +/-detectads  Mark/unmark recording as ad-detection-done.\n"
	    "    +/-thumbnail  Mark/unmark recording as thumbnail present.\n"
	);
	fprintf(stderr,
	    "    -p            Display parseable file information (see *).\n"
	    "    -list         Display file information (default).\n"
	    "    -bookmarks    Display bookmarks.\n"
	    "    +addbookmark=<seconds>[:<seconds>]...\n"
	    "    +setbookmarks=<seconds>[:<seconds>]...\n"
	    "    +clearbookmarks\n"
	    "    +settitle=<new title>\n"
	    "    +setsynopsis=<new synopsis>\n"
	    "    +setguidance=<new guidance>\n"
	);
	fprintf(stderr,
	    "    +setseries=<series,episode,episodes>\n"
	    "    +setfolder=<new folder> (patch hmt only)\n"
	    "    +setfilename=<new filename> (patch hmt only)\n"
	    "    +setgenre=<genre> (can just specifiy initial part)\n"
	    "    +setresume=<resume point (seconds)> "
		 "(-seconds to set from end)\n"
	);

	fprintf(stderr,
	    "\n"
	    "Generic patch commands:\n"
	    "    +patch8=offset:value     patch 8-bit value\n"
	    "    +patch16=offset:value    patch 16-bit value\n"
	    "    +patch32=offset:value    patch 32-bit value\n"
	    "  Offset and value can be preceded with 0x to indicate hex.\n"
	);

	fprintf(stderr,
	    "\n"
	    "Generic read commands:\n"
	    "    +read8=offset            read 8-bit value\n"
	    "    +read16=offset           read 16-bit value\n"
	    "    +read32=offset           read 32-bit value\n"
	    "  Offset can be preceded with 0x to indicate hex.\n"
	);

	fprintf(stderr,
	    "\n"
	    "* Parseable output is tab delimited and contains the following"
	    " fields:\n"
	    "        Title, Synopsis, HD/SD, LCN, Channel Name,\n"
	    "        Start time, End time, Flags, Guidance, Bookmark count,\n"
	    "        Scheduled start, Scheduled duration, Genre code,\n"
	    "        Resume point, Status/Reason.\n"
	);
	fprintf(stderr, "\n");
	return 0;
}

int
main(int argc, char **argv)
{
	enum {
		CMD_LIST = 0,
		CMD_NEW,
		CMD_LOCK,
		CMD_PROTECT,
		CMD_GUIDANCE,
		CMD_ENCRYPTED,
		CMD_THUMBNAIL,
		CMD_SHRUNK,
		CMD_DEDUP,
		CMD_DETECTADS,
		CMD_SETTITLE,
		CMD_SETSYNOPSIS,
		CMD_SETGUIDANCE,
		CMD_SETFOLDER,
		CMD_SETSERIES,
		CMD_SETFILENAME,
		CMD_SETGENRE,
		CMD_SETRESUME,
		CMD_BOOKMARKS,
		CMD_ADDBOOKMARK,
		CMD_SETBOOKMARKS,
		CMD_CLEARBOOKMARKS,
		CMD_PATCH,
		CMD_UNPATCH,
	} cmd = CMD_LIST;
	char *newstr = "";
	int i, toggle;

	if (argc > 1 && !strncmp(argv[1], "-d", 2))
	{
		if (argv[1][2] == '\0')
			debug = 1;
		else
			debug = atoi(argv[1] + 2);
		if (debug > 0)
		{
			printf("Set debug level to %d\n", debug);
			argc--, argv++;
		}
	}

	if (argc > 1 && !strcmp(argv[1], "-p"))
	{
		sysopts |= SYSOPT_PARSABLE;
		argc--, argv++;
	}

	if (argc < 2)
		return syntax();

	toggle = 0;
	switch (*argv[1])
	{
	    case '+':
		toggle = 1;
		/* Fall-through */
	    case '-':
		if (!strcmp(argv[1] + 1, "list"))
			cmd = CMD_LIST;
		else if (!strcmp(argv[1] + 1, "new"))
			cmd = CMD_NEW;
		else if (!strcmp(argv[1] + 1, "lock"))
			cmd = CMD_LOCK;
		else if (!strcmp(argv[1] + 1, "protect"))
			cmd = CMD_PROTECT;
		else if (!strcmp(argv[1] + 1, "guidance"))
			cmd = CMD_GUIDANCE;
		else if (!strcmp(argv[1] + 1, "encrypted"))
			cmd = CMD_ENCRYPTED;
		else if (!strcmp(argv[1] + 1, "shrunk"))
			cmd = CMD_SHRUNK;
		else if (!strcmp(argv[1] + 1, "dedup"))
			cmd = CMD_DEDUP;
		else if (!strcmp(argv[1] + 1, "detectads"))
			cmd = CMD_DETECTADS;
		else if (!strcmp(argv[1] + 1, "thumbnail"))
			cmd = CMD_THUMBNAIL;
		else if (!strcmp(argv[1] + 1, "bookmarks"))
			cmd = CMD_BOOKMARKS;
		else if (!strncmp(argv[1], "+patch", 6))
		{
			newstr = argv[1] + 6;
			cmd = CMD_PATCH;
		}
		else if (!strncmp(argv[1], "+read", 5))
		{
			newstr = argv[1] + 5;
			cmd = CMD_UNPATCH;
		}
		else if (!strncmp(argv[1], "+settitle=", 10))
		{
			newstr = argv[1] + 10;
			if (strlen(newstr) >= HMT_TITLE_LEN)
			{
				fprintf(stderr, "New title too long.\n");
				return 0;
			}
			cmd = CMD_SETTITLE;
		}
		else if (!strncmp(argv[1], "+setsynopsis=", 13))
		{
			newstr = argv[1] + 13;
			cmd = CMD_SETSYNOPSIS;
		}
		else if (!strncmp(argv[1], "+setguidance=", 13))
		{
			newstr = argv[1] + 13;
			if (strlen(newstr) >= HMT_GUIDANCE_LEN)
			{
				fprintf(stderr, "New guidance too long.\n");
				return 0;
			}
			cmd = CMD_SETGUIDANCE;
		}
		else if (!strncmp(argv[1], "+setseries=", 11))
		{
			newstr = argv[1] + 11;
			cmd = CMD_SETSERIES;
		}
		else if (!strncmp(argv[1], "+setfolder=", 11))
		{
			newstr = argv[1] + 11;
			if (strlen(newstr) >= HMT_FOLDER_LEN)
			{
				fprintf(stderr, "New folder too long.\n");
				return 0;
			}
			cmd = CMD_SETFOLDER;
		}
		else if (!strncmp(argv[1], "+setfilename=", 13))
		{
			newstr = argv[1] + 13;
			if (strlen(newstr) >= HMT_FILENAME_LEN)
			{
				fprintf(stderr, "New filename too long.\n");
				return 0;
			}
			cmd = CMD_SETFILENAME;
		}
		else if (!strncmp(argv[1], "+setgenre=", 10))
		{
			newstr = argv[1] + 10;
			cmd = CMD_SETGENRE;
		}
		else if (!strncmp(argv[1], "+setresume=", 11))
		{
			newstr = argv[1] + 11;
			cmd = CMD_SETRESUME;
		}
		else if (!strncmp(argv[1], "+addbookmark=", 13))
		{
			newstr = argv[1] + 13;
			cmd = CMD_ADDBOOKMARK;
		}
		else if (!strncmp(argv[1], "+setbookmarks=", 14))
		{
			newstr = argv[1] + 14;
			cmd = CMD_SETBOOKMARKS;
		}
		else if (!strncmp(argv[1], "+clearbookmarks", 15))
		{
			cmd = CMD_CLEARBOOKMARKS;
		}
		else
		{
			printf("Unknown command, %s\n", argv[1] + 1);
			return syntax();
		}
		argc--, argv++;
		break;
	}

	if (debug)
		printf("Command %d\n", cmd);

	for (i = 1; i < argc; i++)
	{
		struct hmt *hmt;

		if (!(hmt = open_file(argv[i],
		    cmd == CMD_LIST || cmd == CMD_BOOKMARKS)))
			continue;

		switch (cmd)
		{
		    case CMD_NEW:
			cmd_new(hmt, toggle);
			break;

		    case CMD_LOCK:
			cmd_lock(hmt, toggle);
			break;

		    case CMD_PROTECT:
			cmd_protect(hmt, toggle);
			break;

		    case CMD_ENCRYPTED:
			cmd_encrypted(hmt, toggle);
			break;

		    case CMD_SHRUNK:
			cmd_shrunk(hmt, toggle);
			break;

		    case CMD_DEDUP:
			cmd_dedup(hmt, toggle);
			break;

		    case CMD_DETECTADS:
			cmd_detectads(hmt, toggle);
			break;

		    case CMD_THUMBNAIL:
			cmd_thumbnail(hmt, toggle);
			break;

		    case CMD_SETTITLE:
			cmd_settitle(hmt, newstr);
			break;

		    case CMD_SETSYNOPSIS:
			cmd_setsynopsis(hmt, newstr);
			break;

		    case CMD_SETGUIDANCE:
			/* 0x03E0  2 byte 'Guide' flag for Media List.
			 * 0xFF00 = Guide off. 0x0101 = Guide on. */
			patch_byte(hmt, HMT_GUIDEFLAG, HMT_GUIDEFLAG_ON);
			patch_byte(hmt, HMT_GUIDEFLAG + 1, HMT_GUIDEFLAG_ON);
			patch_string(hmt, HMT_GUIDANCE, HMT_GUIDANCE_LEN,
			    newstr);
			break;

		    case CMD_SETSERIES:
			cmd_setseries(hmt, newstr);
			break;

		    case CMD_SETFOLDER:
			patch_string(hmt, HMT_FOLDER, HMT_FOLDER_LEN, newstr);
			break;

		    case CMD_SETFILENAME:
			patch_string(hmt, HMT_FILENAME, HMT_FILENAME_LEN,
			    newstr);
			break;

		    case CMD_BOOKMARKS:
			display_bookmarks(hmt);
			break;

		    case CMD_GUIDANCE:
			cmd_guidance(hmt, toggle);
			break;

		    case CMD_SETGENRE:
			cmd_setgenre(hmt, newstr);
			break;

		    case CMD_SETRESUME:
			cmd_setresume(hmt, newstr);
			break;

		    case CMD_ADDBOOKMARK:
			cmd_bookmarks(hmt, newstr, 1);
			display_bookmarks(hmt);
			break;

		    case CMD_SETBOOKMARKS:
			cmd_bookmarks(hmt, newstr, 0);
			display_bookmarks(hmt);
			break;

		    case CMD_CLEARBOOKMARKS:
			cmd_bookmarks(hmt, NULL, 0);
			display_bookmarks(hmt);
			break;

		    case CMD_PATCH:
			cmd_patch(hmt, newstr);
			break;

		    case CMD_UNPATCH:
			cmd_unpatch(hmt, newstr);
			break;

		    default:
			display_hmt(hmt);
		}

		close_file(hmt);
	}

	return 0;
}