#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include "swis.h"

#include "WimpLib:Task.h"
#include "WimpLib:Utils.h"

static char Text_Buf[4][1024];
static int  Text_Index = 0;

char* SPrintf(const char* pformat, ...)
{
	va_list arg;
	char* pText = &Text_Buf[Text_Index][0];

	va_start(arg, pformat);
	vsnprintf(pText, 1024, pformat, arg);
	va_end(arg);

	Text_Index += 1;
	Text_Index &= 3;

	return pText;
}

char* VSPrintf(const char* pformat, va_list arg)
{
	char* pText = &Text_Buf[Text_Index][0];

	vsnprintf(pText, 1024, pformat, arg);

	Text_Index += 1;
	Text_Index &= 3;

	return pText;
}

void String_StripBlanks(char* string)
{
	int len;
	int i;

	// strip trailing blanks
	for (len = strlen(string); (len > 0) && (string[len - 1] <= ' '); len--)
		;

	// count leading blanks
	for (i = 0; (i < len) && (string[i] <= ' '); i++) ;

	// remove leading blanks
	if (i > 0)
	{
		len = len - i;
		memmove(string, string + i, len);
	}
	string[len] = 0;

	// replace control characters by blanks
	for(i = 1; i < len; i++)
	{
		if (iscntrl(string[i]))
		{
			string[i] = ' ';
			break;
		}
	}
}

void String_ToLower(char* string, int count)
{
	int i;

	if (count < 0) count = strlen(string);

	for (i = 0; i < count; i++)
		string[i] = tolower(string[i]);
}

void String_Translate(char* string, const char* from, const char* to)
{
	int i, ilast;
	int j, jlast;

	ilast = strlen(string) - 1;
	jlast = strlen(from) - 1;

    for (i = ilast; i >= 0; i--)
    {
    	for (j = jlast; j >= 0; j--)
    	{
			if (string[i] == from[j])
			{
				string[i] = to[j];
				break;
			}
    	}
    }
}

int String_Collate(int flags, const char* pa, const char* pb, int maxlen)
{
	int val = 0;
	char a = 0, b = 0;
	char* pma = NULL;
	char* pmb = NULL;

	// dangerous acking
	if (maxlen >= 0)
	{
		if (maxlen < strlen(pa))
		{
			pma = (char*) pa + maxlen;
			a = *pma;
			*pma = 0;
		}
		if (maxlen < strlen(pb))
		{
			pmb = (char*) pb + maxlen;
			b = *pmb;
			*pmb = 0;
		}
	}

	if (_swix(Territory_Collate, _INR(0, 3) | _OUT(0)
			,Task_GetTerritoryNumber(), pa, pb, flags & 3
			, &val))
		val = strcmp(pa, pb);

	if (pma) *pma = a;
	if (pmb) *pmb = b;

	return val;
}

int FitInRange(int value, int min, int max)
{
	if (value < min)
		return min;
	if (value > max)
		return max;

	return value;
}

static _kernel_oserror err_ensure =
{0, ""};

const _kernel_oserror* RMEnsure(const char* name, int vers, const char* path)
{
	const _kernel_oserror* e;
	int* addr;
	const char* help;
	int count;
	int found_vers = -1;

	// find module in RMA
	e = _swix(OS_Module, _INR(0,1)|_OUT(3), 18, name, &addr);

	if (!e)
	{
		// check version
		help = (char*) addr;
		help += addr[5];
		count = 0;
		while(count < 16)
		{
			count++;
			if (*help == 9)
			{
				count += 7;
				count &= ~7;
			}
			help++;
		}
		if (help[1] == '.')
			found_vers = (help[0] - '0') * 100
			           + (help[2] - '0') * 10
			           + (help[3] - '0');
	}

	if (found_vers >= vers)
		return NULL;

	// load module in RMA
	e = _swix(OS_Module, _INR(0,1), 1, path);
	if (e) return e;


	// find module in RMA
	e = _swix(OS_Module, _INR(0,1)|_OUT(3), 18, name, &addr);
	if (e) return e;

	// check version
	found_vers = -1;
	help = (char*) addr;
	help += addr[5];
	count = 0;
	while(count < 16)
	{
		count++;
		if (*help == 9)
		{
			count += 7;
			count &= ~7;
		}
		help++;
	}
	if (help[1] == '.')
		found_vers = (help[0] - '0') * 100
		           + (help[2] - '0') * 10
		           + (help[3] - '0');

	if (found_vers < vers)
	{
		snprintf(err_ensure.errmess, sizeof(err_ensure.errmess)
		       , "Version %d.%02d of module %s is required.", vers / 100, vers % 100, name);
		return &err_ensure;
	}

	return NULL;
}

const _kernel_oserror* RMKill(const char* module)
{
	return _swix(OS_Module, _INR(0,1), 4, module);
}

const _kernel_oserror* StartTask(HTask* ptask, const char* command)
{
	return _swix(Wimp_StartTask, _IN(0)|_OUT(0), command, ptask);
}

