#include <alloca.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <newt.h>
#include <popt.h>
#include <unistd.h>

#include "lang.h"
#include "loader.h"
#include "kickstart.h"

struct ksCommandNames {
    int code;
    char * name;
} ;

struct ksCommand {
    int code, argc;
    char ** argv;
};

struct ksCommandNames ksTable[] = {
    { KS_CMD_NFS, "nfs" },
    { KS_CMD_CDROM, "cdrom" },
    { KS_CMD_DEVICE, "device" },
    { KS_CMD_HD, "harddrive" },
    { KS_CMD_TEXT, "text" },
    { KS_CMD_URL, "url" },
    { KS_CMD_NETWORK, "network" },
    { KS_CMD_DEVICE, "device" },
    { KS_CMD_XDISPLAY, "xdisplay" },
    { KS_CMD_DRIVERDISK, "driverdisk" },
    { KS_CMD_NONE, NULL }
};

struct ksCommand * commands = NULL;
int numCommands = 0;

int ksReadCommands(char * cmdFile) {
    int fd;
    char * buf;
    struct stat sb;
    char * start, * end, * chptr;
    char oldch;
    int line = 0;
    char ** argv; 
    int argc;
    int inPackages = 0;
    struct ksCommandNames * cmd;
    int commandsAlloced = 5;

    if ((fd = open(cmdFile, O_RDONLY)) < 0) {
	newtWinMessage(_("Kickstart Error"), _("OK"), 
			_("Error opening: kickstart file %s: %s"), cmdFile, 
			strerror(errno));
	return LOADER_ERROR;
    }

    fstat(fd, &sb);

    buf = alloca(sb.st_size + 1);
    if (read(fd, buf, sb.st_size) != sb.st_size) {
	newtWinMessage(_("Kickstart Error"), _("OK"), 
			_("Error reading contents of kickstart file %s: %s"),
			cmdFile, strerror(errno));
	close(fd);
	return LOADER_ERROR;
    }

    close(fd);

    buf[sb.st_size] = '\0';

    commands = malloc(sizeof(*commands) * commandsAlloced);

    start = buf;
    while (*start && !inPackages) {
	line++;

	if (!(end = strchr(start, '\n')))
	    end = start + strlen(start);

	oldch = *end;
	*end = '\0';

	while (*start && isspace(*start)) start++;

	chptr = end - 1;
	while (chptr > start && isspace(*chptr)) chptr--;

	if (isspace(*chptr)) 
	    *chptr = '\0';
	else
	    *(chptr + 1) = '\0';

	if (!*start || *start == '#') {
	    /* no nothing */
	} else if (!strcmp(start, "%packages")) {
	    inPackages = 1;
	} else {
	    if (poptParseArgvString(start, &argc, (const char ***) &argv) || !argc) {
		newtWinMessage(_("Kickstart Error"), _("OK"), 
			       _("Error on line %d of kickstart file %s."),
				argv[0], line, cmdFile);
	    } else {
		for (cmd = ksTable; cmd->name; cmd++)
		    if (!strcmp(cmd->name, argv[0])) break;

		if (cmd->name) {
		    if (numCommands == commandsAlloced) {
			commandsAlloced += 5;
			commands = realloc(commands,
					   sizeof(*commands) * commandsAlloced);
		    }

		    commands[numCommands].code = cmd->code;
		    commands[numCommands].argc = argc;
		    commands[numCommands].argv = argv;
		    numCommands++;
		}
	    }
	}

	if (oldch)
	    start = end + 1;
	else
	    start = end;
    }

    return 0;
}

int ksHasCommand(int cmd) {
    int i = 0;

    while (i < numCommands) {
	if (commands[i].code == cmd) return 1;
	i++;
    }

    return 0;
}

int ksGetCommand(int cmd, char ** last, int * argc, char *** argv) {
    int i = 0;

    if (last) {
	for (i = 0; i < numCommands; i++) {
	    if (commands[i].argv == last) break;
	}

	i++;
    }

    while (i < numCommands) {
	if (commands[i].code == cmd) {
	    if (argv) *argv = commands[i].argv;
	    if (argc) *argc = commands[i].argc;
	    return 0;
	}
	i++;
    }

    return 1;
}
