/*
 *  QWProgs-DM
 *  Copyright (C) 2004  [sd] angel
 *
 *  This code is based on QuakeWorld DM mod code by Id Software, Inc.
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *  $Id$
 */

// q_shared.c -- stateless support routines that are included in each code dll
#include "q_shared.h"

/*
 ============================================================================

 BYTE ORDER FUNCTIONS

 ============================================================================
 */
/*
 // can't just use function pointers, or dll linkage can
 // mess up when qcommon is included in multiple places
 static short	(*_BigShort) (short l);
 static short	(*_LittleShort) (short l);
 static int		(*_BigLong) (int l);
 static int		(*_LittleLong) (int l);
 static qint64	(*_BigLong64) (qint64 l);
 static qint64	(*_LittleLong64) (qint64 l);
 static float	(*_BigFloat) (const float *l);
 static float	(*_LittleFloat) (const float *l);

 short	BigShort(short l){return _BigShort(l);}
 short	LittleShort(short l) {return _LittleShort(l);}
 int		BigLong (int l) {return _BigLong(l);}
 int		LittleLong (int l) {return _LittleLong(l);}
 qint64 	BigLong64 (qint64 l) {return _BigLong64(l);}
 qint64 	LittleLong64 (qint64 l) {return _LittleLong64(l);}
 float	BigFloat (const float *l) {return _BigFloat(l);}
 float	LittleFloat (const float *l) {return _LittleFloat(l);}
 */

extern void G_Error(const char *fmt, ...) PRINTF_FUNC(1);

short ShortSwap(short l)
{
	byte b1, b2;

	b1 = l & 255;
	b2 = (l >> 8) & 255;

	return ((b1 << 8) + b2);
}

short ShortNoSwap(short l)
{
	return l;
}

int LongSwap(int l)
{
	byte b1, b2, b3, b4;

	b1 = l & 255;
	b2 = (l >> 8) & 255;
	b3 = (l >> 16) & 255;
	b4 = (l >> 24) & 255;

	return (((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4);
}

int LongNoSwap(int l)
{
	return l;
}

qint64 Long64Swap(qint64 ll)
{
	qint64 result;

	result.b0 = ll.b7;
	result.b1 = ll.b6;
	result.b2 = ll.b5;
	result.b3 = ll.b4;
	result.b4 = ll.b3;
	result.b5 = ll.b2;
	result.b6 = ll.b1;
	result.b7 = ll.b0;

	return result;
}

qint64 Long64NoSwap(qint64 ll)
{
	return ll;
}

typedef union
{
	float f;
	unsigned int i;
} _FloatByteUnion;

float FloatSwap(const float *f)
{
	const _FloatByteUnion *in;
	_FloatByteUnion out;

	in = (_FloatByteUnion*) f;
	out.i = LongSwap(in->i);

	return out.f;
}

float FloatNoSwap(const float *f)
{
	return *f;
}

/*
 ================
 Swap_Init
 ================
 */
/*
 void Swap_Init (void)
 {
 byte	swaptest[2] = {1,0};

 // set the byte swapping variables in a portable manner
 if ( *(short *)swaptest == 1)
 {
 _BigShort = ShortSwap;
 _LittleShort = ShortNoSwap;
 _BigLong = LongSwap;
 _LittleLong = LongNoSwap;
 _BigLong64 = Long64Swap;
 _LittleLong64 = Long64NoSwap;
 _BigFloat = FloatSwap;
 _LittleFloat = FloatNoSwap;
 }
 else
 {
 _BigShort = ShortNoSwap;
 _LittleShort = ShortSwap;
 _BigLong = LongNoSwap;
 _LittleLong = LongSwap;
 _BigLong64 = Long64NoSwap;
 _LittleLong64 = Long64Swap;
 _BigFloat = FloatNoSwap;
 _LittleFloat = FloatSwap;
 }

 }
 */

/*
 ============================================================================

 LIBRARY REPLACEMENT FUNCTIONS

 ============================================================================
 */

int Q_isprint(int c)
{
	if ((c >= 0x20) && (c <= 0x7E))
	{
		return (1);
	}

	return (0);
}

int Q_islower(int c)
{
	if ((c >= 'a') && (c <= 'z'))
	{
		return (1);
	}

	return (0);
}

int Q_isupper(int c)
{
	if ((c >= 'A') && (c <= 'Z'))
	{
		return (1);
	}

	return (0);
}

int Q_isalpha(int c)
{
	if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
	{
		return (1);
	}

	return (0);
}

char* Q_strrchr(const char *string, int c)
{
	char cc = c;
	char *s;
	char *sp = (char*) 0;

	s = (char*) string;

	while (*s)
	{
		if (*s == cc)
		{
			sp = s;
		}

		s++;
	}

	if (cc == 0)
	{
		sp = s;
	}

	return sp;
}

/*
 =============
 Q_strncpyz
 
 Safe strncpy that ensures a trailing zero
 =============
 */
void Q_strncpyz(char *dest, const char *src, int destsize)
{
	// bk001129 - also NULL dest
	if (!dest)
	{
		G_Error("Q_strncpyz: NULL dest");
	}

	if (!src)
	{
		G_Error("Q_strncpyz: NULL src");
	}

	if (destsize < 1)
	{
		G_Error("Q_strncpyz: destsize < 1");
	}

	strncpy(dest, src, destsize - 1);
	dest[destsize - 1] = 0;
}

int Q_stricmpn(const char *s1, const char *s2, int n)
{
	int c1, c2;

	// bk001129 - moved in 1.17 fix not in id codebase
	if (s1 == NULL)
	{
		if (s2 == NULL)
		{
			return 0;
		}
		else
		{
			return -1;
		}
	}
	else if (s2 == NULL)
	{
		return 1;
	}

	do
	{
		c1 = *s1++;
		c2 = *s2++;

		if (!n--)
		{
			return 0;		// strings are equal until end point
		}

		if (c1 != c2)
		{
			if ((c1 >= 'a') && (c1 <= 'z'))
			{
				c1 -= ('a' - 'A');
			}

			if ((c2 >= 'a') && (c2 <= 'z'))
			{
				c2 -= ('a' - 'A');
			}

			if (c1 != c2)
			{
				return ((c1 < c2) ? -1 : 1);
			}
		}
	} while (c1);

	return 0;		// strings are equal
}

int Q_strncmp(const char *s1, const char *s2, int n)
{
	int c1, c2;

	do
	{
		c1 = *s1++;
		c2 = *s2++;

		if (!n--)
		{
			return 0;		// strings are equal until end point
		}

		if (c1 != c2)
		{
			return ((c1 < c2) ? -1 : 1);
		}
	} while (c1);

	return 0;		// strings are equal
}

int Q_stricmp(const char *s1, const char *s2)
{
	return ((s1 && s2) ? Q_stricmpn(s1, s2, 99999) : -1);
}

char* Q_strlwr(char *s1)
{
	char *s;

	s = s1;
	while (*s)
	{
		*s = tolower(*s);
		s++;
	}

	return s1;
}

char* Q_strupr(char *s1)
{
	char *s;

	s = s1;
	while (*s)
	{
		*s = toupper(*s);
		s++;
	}

	return s1;
}

// never goes past bounds or leaves without a terminating 0
void Q_strcat(char *dest, int size, const char *src)
{
	int l1;

	l1 = strlen(dest);
	if (l1 >= size)
	{
		G_Error("Q_strcat: already overflowed");
	}

	Q_strncpyz(dest + l1, src, size - l1);
}
