/*
 * $RCSfile: os.cpp $
 *
 * $Author: marcel $
 *
 * $Revision: 1.4 $
 *
 * $Date: 1995/03/31 15:56:31 $
 *
 * $Locker: marcel $
 *
 * $State: Exp $
 *
 * Amiga version
 *
 * Copyright © 1995 Marcel Offermans
 *
 * tabsize = 5
 */

/* includes */
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <dos.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "track.h"
#include "os.h"
#include "car.h"

#define TEMPLATE		"TRACK,DRIVERS/M,CARS/N,LAPS/N,RACES/N,KEEPORDER/S,NOREALTIME/S,NODISPLAY/S,NORANDOMSEED/S"
#define OPT_TRACK		0
#define OPT_DRIVERS		1
#define OPT_CARS		2
#define OPT_LAPS		3
#define OPT_RACES		4
#define OPT_KEEPORDER	5
#define OPT_NOREALTIME	6
#define OPT_NODISPLAY	7
#define OPT_NORANDOMSEED	8
#define OPT_COUNT		9

/* externals */
extern con_vec(*drovers[])(situation);
extern char *nam_ptr[];
void print_help_file(void);
int find_name(char *);

/* globals */
static char			version_ptr[]			= "\0$VER: RARS_Amiga 2.0 " __AMIGADATE__ ;
static int			rndmiz				= 1;
struct RDArgs *		args_ptr				= NULL;
struct IntuiMessage *	imsg_ptr				= NULL;
struct IntuiMessage		imsg;
LONG					opts[OPT_COUNT];
ULONG				idcmpmask;
ULONG				signals;

/* initialize the random number generator based on the current time */
void randomizer(void)
{
	unsigned int clock[2];
	timer(clock);
	srand(clock[1]);
	return;
}

/* return a random number between 0 and limit */
double random(int limit)
{
	return(((double)rand() / (double)RAND_MAX) * (double)limit);
}

/* convert integer to ascii */
void itoa(int value, char *buffer_ptr, int base)
{
	if (base == 10)
	{
		stci_d(buffer_ptr, value);
	}
}

/* get arguments by using a standard command line template */
void get_args(int argc, char* argv[])
{
	int i, n;
	char *temp_ptr;
	colors temp_clr;
	con_vec(*temp_drv)(situation);
	char **driver_ptr_ptr;

	/* set up defaults */
	strcpy(trackfile, "trackfil.trk");
	lap_count = 4;
	car_count = 6;
	real_speed = 1;
	race_count = 2;
	keep_order = 0;

	/* get arguments */
	if (args_ptr = ReadArgs(TEMPLATE, opts, NULL))
	{
		if (opts[OPT_TRACK])
		{
			/* track file name */
			strcpy(trackfile, (char *)opts[OPT_TRACK]);
		}
		if (opts[OPT_DRIVERS])
		{
			/* list of drivers in the race */
			driver_ptr_ptr = (char **)opts[OPT_DRIVERS];
			for (n = 0; n < MAXCARS; n++)
			{
				if (driver_ptr_ptr[n] == NULL)
				{
					break;
				}
				if ((i = find_name(driver_ptr_ptr[n])) < 0)
				{
					break;
				}
				temp_ptr = nam_ptr[n];
				nam_ptr[n] = nam_ptr[i];
				nam_ptr[i] = temp_ptr;
				temp_clr = car_clrs[n];
				car_clrs[n] = car_clrs[i];
				car_clrs[i] = temp_clr;
				temp_drv = drovers[n];
				drovers[n] = drovers[i];
				drovers[i] = temp_drv;
			}
			/* if any drivers were found, set the number of cars to the number of drivers */
			if (n > 0)
			{
				car_count = n;
			}
		}
		if (opts[OPT_LAPS])
		{
			/* number of laps to go */
			lap_count = (int)(*((LONG *)opts[OPT_LAPS]));

			/* check bounds of user input */
			if (lap_count <= 0)
			{
				lap_count = 1;
			}
		}
		if (opts[OPT_CARS])
		{
			/* number of cars in the race */
			car_count = (int)(*((LONG *)opts[OPT_CARS]));

			/* check bounds of user input */
			if (car_count < 0)
			{
				/* zero cars is legal, and only shows you the track */
				car_count = 0;
			}
			else if (car_count > MAXCARS)
			{
				car_count = MAXCARS;
			}
		}
		if (opts[OPT_RACES])
		{
			/* number of races to go */
			race_count = (int)(*((LONG *)opts[OPT_RACES]));

			/* check bounds of user input */
			if (race_count <= 0)
			{
				race_count = 1;
			}
		}
		if (opts[OPT_NOREALTIME])
		{
			/* run as fast as possible instead of real-time */
			real_speed = 0;
		}
		if (opts[OPT_NORANDOMSEED])
		{
			/* don't set a new random seed every time */
			rndmiz = 0;
		}
		if (opts[OPT_NODISPLAY])
		{
			/* don't use a graphics display */
			no_display = 1;
		}
		if (opts[OPT_KEEPORDER])
		{
			/* keep the starting order */
			keep_order = 1;
		}
	}
}

/* blocks until one character is read from the keyboard */
int get_ch(void)
{
	if (!available)
	{
		/* if there's no graphics display, we don't handle the keyboard */
		return(0);
	}

	/* wait for a message if we don't have a cached message yet */
	while (imsg_ptr == NULL)
	{
		signals = Wait(idcmpmask);
		if (signals & idcmpmask)
		{
			imsg_ptr = (struct IntuiMessage *)GetMsg(window_ptr->UserPort);
			if (imsg_ptr)
			{
				CopyMem((char *)imsg_ptr, (char *)&imsg, (long)sizeof(struct IntuiMessage));
				ReplyMsg((struct Message *)imsg_ptr);
			}
		}
	}
	return(imsg.Code);
}

/* this routine returns non-zero if there's input available for get_ch() and 0 if not */
int kb_hit(void)
{
	if (!available)
	{
		/* if there's no graphics display, we don't handle the keyboard */
		return(0);
	}

	imsg_ptr = (struct IntuiMessage *)GetMsg(window_ptr->UserPort);
	if (imsg_ptr)
	{
		/* we received a message, so now we have to cache it until get_ch() is called */
		CopyMem((char *)imsg_ptr, (char *)&imsg, (long)sizeof(struct IntuiMessage));
		ReplyMsg((struct Message *)imsg_ptr);
		return(1);
	}
	else
	{
		return(0);
	}
}

/* busy wait for a tick to go by */
void one_tick(int initialize = 0)
{
	static unsigned int pre_clock[2];
	static unsigned int cur_clock[2];

	if (initialize)
	{
		timer(pre_clock);
	}
	else
	{
		do
		{
			timer(cur_clock);
		}
		while (cur_clock[1] + 1000000 * (cur_clock[0] - pre_clock[0]) < pre_clock[1] + (int)(delta_time * 1000000));

		pre_clock[0] = cur_clock[0];
		pre_clock[1] = cur_clock[1];
	}
}
