#include <stdio.h>

#include "rovdefs.h"

typedef struct
{
	enum { VMTYPE_INTEGER, VMTYPE_FLOAT } type;
	union { int i; float f; } value;
} vmtype;

static const char *insnnames[] = {
	"end", "not", "and", "or", "jmp", "jmpif",
	"get", "set", "add", "sub", "equ", "lt", "gt", "lesseq", "greatereq", "push", "pop",
	"setstate", "nextstate", "stopmoving", "deleteme", "move", "moverandom",
	"hitscan", "hitsweep", "hitradius", "shoot", "playsound", "hurtother", "deleteother", "throwother", "dropitem", "droploot",
	"heal", "say", "warp", "warpto", "awardxp", "chance", "seesplayer", "enemywithin", "stateis", "otheris"
};
static const int numnames = sizeof(insnnames) / sizeof(insnnames[0]);

static int hasimm(unsigned char insn)
{
	switch (insn)
	{
	case INSN_LOGI_JMP:
	case INSN_LOGI_JMPIF:
	case INSN_CORE_GET:
	case INSN_CORE_SET:
	case INSN_CORE_PUSH:
	case INSN_ACT_SETSTATE:
	case INSN_ACT_SHOOT:
	case INSN_ACT_PLAYSOUND:
	case INSN_ACT_DROPITEM:
	case INSN_CND_STATEIS:
	case INSN_CND_OTHERIS:
		return 1;
	default:
		return 0;
	}
}
static vmtype readimm(FILE *fp, int insn)
{
	vmtype result;
	int size;

	int type = fgetc(fp);
	if (type == EOF) {
		fprintf(stderr, "Reached end of program before %s could find its immediate value", insnnames[insn]);
		exit(1);
	}

	switch (type) {
	case IMMTYPE_U8:
	case IMMTYPE_S8:
		result.type = VMTYPE_INTEGER;
		fread(&result.value.i, 1, 1, fp);
		break;
	case IMMTYPE_U16:
	case IMMTYPE_S16:
		result.type = VMTYPE_INTEGER;
		fread(&result.value.i, 2, 1, fp);
		break;
	case IMMTYPE_U32:
	case IMMTYPE_S32:
		result.type = VMTYPE_INTEGER;
		fread(&result.value.i, 4, 1, fp);
		break;
	case IMMTYPE_FLOAT32:
		result.type = VMTYPE_FLOAT;
		fread(&result.value.f, 4, 1, fp);
		break;
	default:
		fprintf(stderr, "Invalid immediate type %d", type);
		result.type = VMTYPE_INTEGER;
		result.value.i = -1;
		break;
	}

	return result;
}

int main(int argc, char *argv[])
{
	FILE *infile;
	int byte;

	if (argc < 2) {
		fprintf(stderr, "No input file specified\n");
		return 1;
	}
	
	infile = fopen(argv[1], "rb");
	if (!infile) {
		perror(argv[1]);
		return 1;
	}
	
	while ((byte = fgetc(infile)) != EOF) {
		int offs = ftell(infile) - 1;
		if (byte > numnames) {
			printf("Invalid instruction %d\n", byte);
			continue;
		}
		
		if (hasimm(byte)) {
			vmtype imm = readimm(infile, byte);
			if (imm.type == VMTYPE_INTEGER)
				printf("%06d\t%-12s\t%d\n", offs, insnnames[byte], imm.value.i);
			else
				printf("%06d\t%-12s\t%f\n", offs, insnnames[byte], imm.value.f);
		} else {
			printf("%06d\t%-12s\n", offs, insnnames[byte]);
		}
	}
	
	fclose(infile);
	
	return 0;
}