#include <hpgcc49.h>



// Prevodni tabulky
//
#define  ROMAN_SROMT_INIT	"I" "V" "X" "L"  "C"  "D"  "M"
#define  ROMAN_SVALT_INIT	{1,  5,  10, 50, 100, 500, 1000}
//
static char const			sromt[] = ROMAN_SROMT_INIT;


// Maximalni velikost bufferu cislic
//
#define  ROMAN_RESULT_SIZE	40


// Navratove hodnoty funkci
//
#define  RTNVAL_OK			0
#define  RTNVAL_ERROR		1



/*============================================================================*\
                                ARABSKE --> RIMSKE
\*============================================================================*/


/*
 * VSTUPNI BOD
 */

static int a2r(unsigned value)
{
	unsigned	divisor;
    int         sidx,
				ridx;
    char        result[ROMAN_RESULT_SIZE];

	divisor = 1000;
	sidx = sizeof(sromt) / sizeof(*sromt) - 2;
	ridx = -1;
	do
	{
		unsigned    digit;

		digit = value / divisor;
		value -= digit * divisor;
		switch(digit)
		{
		case 4:
		case 9:
			result[++ridx] = sromt[sidx + 0];
			result[++ridx] = sromt[sidx + 1 + (digit == 9)];
			break;

		default:
			while(digit)
			{
				int     idx;

				idx = sidx;
				if(digit >= 5)
				{
					++idx;
					digit -= 5 - 1;
				}
				result[++ridx] = sromt[idx];
				--digit;
			}
		}
		sidx -= 2;
	} while((divisor /= 10) > 0);
	result[ridx + 1] = '\0';
	sat_stack_push_string(result);
	return(RTNVAL_OK);
}



/*============================================================================*\
                                RIMSKE --> ARABSKE
\*============================================================================*/


/*
 * ZJISTENI POCTU PREDCHOZICH CISLIC S MENSI HODNOTOU
 */

static int r2a_prevlessnum(int result[],
						   int ridx)
{
    int		resval,
			number;

	resval = result[ridx];
	number = 0;
	do
	{
		int		preval;

		preval = result[--ridx];
		if( preval < 0)
			preval = -preval;
		if(resval > preval)
			++number;
	} while(ridx > 0);
	return(number);
}



/*
 * CHYBA
 */

static int r2a_error(char const format[],
					 char const *valup,
					 char const *val0p)
{
	char	errtext[ROMAN_RESULT_SIZE];

	sprintf(errtext, format, valup);
	sat_stack_push_string(val0p);
	sat_stack_push_string(errtext);
	return(RTNVAL_ERROR);
}



/*
 * VSTUPNI BOD
 */

static int r2a(char const *valup)
{
    int					ridx,
						result[ROMAN_RESULT_SIZE];
    char const			*fndp,
						*val0p;
    static int const	svalt[] = ROMAN_SVALT_INIT;

	ridx = 0;
	val0p = valup;
	do
	{
        int		sidx;

		if((fndp = strchr(sromt, toupper(*valup))) == NULL)
			return(r2a_error("Unknown Digit: %s", valup, val0p));
		sidx = fndp - sromt;
		result[ridx] = svalt[sidx];
		if(ridx > 0)
			switch(r2a_prevlessnum(result, ridx))
			{
			case 1:
				result[ridx - 1] = -result[ridx - 1];

			case 0:
				break;

			default:
				return(r2a_error("Unexpected Digit: %s", valup, val0p));
			}
		++ridx;
	} while(*++valup != '\0');
	while(--ridx > 0)
		result[0] += result[ridx];
	sat_push_zint_llong(result[0]);
	return(RTNVAL_OK);
}



/*============================================================================*\
                                    PROGRAM
\*============================================================================*/


/*
 * TEST: CO JE NA STACKU
 */

static int what_is_on_stack()
{
	SAT_STACK_ELEMENT	elemv;

	if(sat_get_stack_element(1, &elemv))
		return(-1);
	return(elemv.prologue);
}


/*
 * CHYBA
 */

#define _ERROR_ARG_EMPTY	"Empty stack"
#define _ERROR_ARG_TYPE		"Bad type"
#define _ERROR_ARG_RANGE	"Bad range"
//
#define  Error_arg(k)		(sat_stack_push_string(_ERROR_ARG_##k), RTNVAL_ERROR)



/*
 * ZADANI "ZINT"
 */

static int val_zint()
{
	ULONGLONG	value;

	value = sat_pop_zint_llong();
	if(value - 1  <  3999)
		return(a2r(value));
	sat_push_zint_llong(value);
	return(Error_arg(RANGE));
}



/*
 * ZADANI "REAL"
 */

static int val_real()
{
	double		value;

	value = sat_pop_real();
	if(value >= 1.0)
		if(value <= 3999.0)
			return(a2r(round(value)));
	sat_push_real(value);
	return(Error_arg(RANGE));
}



/*
 * VSTUPNI BOD
 */

int main()
{
	int		test;

	if(sat_stack_depth() <= 0)
		test = Error_arg(EMPTY);
	else
		switch(what_is_on_stack())
		{
		case SAT_DOINT:
			test = val_zint();
			break;

		case SAT_DOREAL:
			test = val_real();
			break;

		case SAT_DOCSTR:
			test = r2a(sat_pop_str_alloc());
			break;

		default:
			test = Error_arg(TYPE);
		}
	sat_push_real(test);
	return(0);
}
