/*
===========================================================================
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2013 - 2015, OpenJK contributors

This file is part of the OpenJK source code.

OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

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, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

////////////////////////////////////////////////////////////////////////////////////////
// RAVEN STANDARD TEMPLATE LIBRARY
//  (c) 2002 Activision
//
//
// String
// ------
// Simple wrapper around a char[SIZE] array.
//
//
//
// NOTES:
//
//
//
////////////////////////////////////////////////////////////////////////////////////////
#if !defined(RATL_STRING_VS_INC)
#define RATL_STRING_VS_INC


////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////
#if !defined(RATL_COMMON_INC)
	#include "ratl_common.h"
#endif

namespace ratl
{

////////////////////////////////////////////////////////////////////////////////////////
// The String Class
////////////////////////////////////////////////////////////////////////////////////////
template<int ARG_CAPACITY>
class string_vs : public ratl_base
{
public:
    ////////////////////////////////////////////////////////////////////////////////////
	// Capacity Enum
    ////////////////////////////////////////////////////////////////////////////////////
	static const int CAPACITY			= ARG_CAPACITY;
private:
    ////////////////////////////////////////////////////////////////////////////////////
	// Data
    ////////////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
	char	mData[CAPACITY+4];
#else
	char	mData[CAPACITY];
#endif

	void FillTerminator()
	{
#ifdef _DEBUG
		mData[CAPACITY]='e';
		mData[CAPACITY+1]='n';
		mData[CAPACITY+2]='d';
		mData[CAPACITY+3]=0;
#endif
	}

public:

    ////////////////////////////////////////////////////////////////////////////////////
	// Constructor
    ////////////////////////////////////////////////////////////////////////////////////
	string_vs()
	{
		mData[0]=0;
		FillTerminator();
	}
#ifdef _DEBUG
	~string_vs()
	{
		//if you hit the below asserts, the end of the string was overwritten
		assert(mData[CAPACITY]=='e');
		assert(mData[CAPACITY+1]=='n');
		assert(mData[CAPACITY+2]=='d');
		assert(mData[CAPACITY+3]==0);
	}
#endif
    ////////////////////////////////////////////////////////////////////////////////////
	// Copy Constructor
    ////////////////////////////////////////////////////////////////////////////////////
	string_vs(const string_vs<CAPACITY> &o)
	{
		assert(str::len(o.mData)<CAPACITY);
		str::ncpy(mData, o.mData, CAPACITY);		// Safe String Copy
		mData[CAPACITY-1] = 0;					// Make Sure We Have A Null Terminated Str
		FillTerminator();
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Copy Constructor
    ////////////////////////////////////////////////////////////////////////////////////
	string_vs(const char *s)
	{
		assert(str::len(s)<CAPACITY);
		str::ncpy(mData, s, CAPACITY);		// Safe String Copy
		mData[CAPACITY-1] = 0;					// Make Sure We Have A Null Terminated Str
		FillTerminator();
	}


    ////////////////////////////////////////////////////////////////////////////////////
	//
    ////////////////////////////////////////////////////////////////////////////////////
	string_vs& operator=(const char *s)
	{
		assert(str::len(s)<CAPACITY);
		str::ncpy(mData, s, CAPACITY);			// Safe String Copy
		mData[CAPACITY-1] = 0;					// Make Sure We Have A Null Terminated Str
		FillTerminator();
		return *this;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Access To Raw Array
    ////////////////////////////////////////////////////////////////////////////////////
	char*			c_str()
	{
		return mData;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Access To Raw Array
    ////////////////////////////////////////////////////////////////////////////////////
	const char*		c_str() const
	{
		return mData;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Access To Raw Array
    ////////////////////////////////////////////////////////////////////////////////////
	operator const char *()
	{
		return mData;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Access To Raw Array
    ////////////////////////////////////////////////////////////////////////////////////
	const char*		operator*()
	{
		return mData;
	}


    ////////////////////////////////////////////////////////////////////////////////////
	// How Many Characters Can This Hold
    ////////////////////////////////////////////////////////////////////////////////////
	int				capacity() const
	{
		return CAPACITY;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Length
    ////////////////////////////////////////////////////////////////////////////////////
	int				length() const
	{
		assert(str::len(mData)<CAPACITY-1);
		return str::len(mData);
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Character Bracket Operator
    ////////////////////////////////////////////////////////////////////////////////////
	char			operator[](int index)
	{
		assert(index<CAPACITY);
		return mData[index];
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Equality Operator
    ////////////////////////////////////////////////////////////////////////////////////
	bool			operator==(const string_vs &o) const
	{
		if (!stricmp(mData,o.mData))
		{
			return true;
		}
		return false;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// InEquality Operator
    ////////////////////////////////////////////////////////////////////////////////////
	bool			operator!=(const string_vs &o) const
	{
		if (str::icmp(mData,o.mData)!=0)
		{
			return true;
		}
		return false;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Compare Less Than
    ////////////////////////////////////////////////////////////////////////////////////
	bool			operator<(const string_vs &o) const
	{
		if (str::icmp(mData,o.mData)<0)
		{
			return true;
		}
		return false;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// Compare Greater Than
    ////////////////////////////////////////////////////////////////////////////////////
	bool			operator>(const string_vs &o) const
	{
		if (str::icmp(mData,o.mData)>0)
		{
			return true;
		}
		return false;
	}

    ////////////////////////////////////////////////////////////////////////////////////
	//
    ////////////////////////////////////////////////////////////////////////////////////
	void			operator+=(const string_vs &o)
	{
		if ( (str::len(mData)+o.length())<CAPACITY )		// Only If It Is Safe
		{
			str::cat(mData, o.c_str());
		}
		else
		{
			assert(!"string_vs overflow\n");
		}
	}

    ////////////////////////////////////////////////////////////////////////////////////
	//
    ////////////////////////////////////////////////////////////////////////////////////
	void			operator+=(const char *s)
	{
		if ( (str::len(mData)+str::len(s))<CAPACITY )		// Only If It Is Safe
		{
			str::cat(mData, s);
		}
		else
		{
			assert(!"string_vs overflow\n");
		}
	}




    ////////////////////////////////////////////////////////////////////////////////////
	// Tokenizer
	//
	// The string tokenizer class is similar to an iterator in that it essentially
	// iterates over all the tokens in the string seperated by a common series of
	// delinating sequences.  For example:  " ,\t\n" would seperate tokens on spaces
	// commas, tabs and linefeeds.
	//
	// Iterating over string tokens is just like normal iteration:
	//
	// for (string_vs<CAPACITY>::tokenizer it=MyString.begin(" ,\t\n"); it!=MyString.end(); it++)
	// {
	//    const char* token = *it;
	// }
	//
	//
	// NOTE: This class is built upon the c library function strtok() which uses a
	// static working area, so having multiple tokenizers in multiple threads or just
	// plain at the same time is not safe.
	//
    ////////////////////////////////////////////////////////////////////////////////////
	class tokenizer
	{
		enum
		{
			TOKEN_GAP_LEN	= 15,
		};

	public:
		// Constructors
		//--------------
		tokenizer()							: mLoc(0)
		{}
		tokenizer(const char* t, const char* gap)
		{
			strncpy(mGap, gap, TOKEN_GAP_LEN);		// Safe String Copy
			mGap[TOKEN_GAP_LEN-1] = 0;				// Make Sure We Have A Null Terminated Str

			char*	temp = (char*)t;
			mLoc = str::tok(temp, mGap);
		}

		// Assignment Operator
		//---------------------
		void		operator= (const tokenizer &t)
		{
			mLoc	= t.mLoc;
			str::cpy(mGap, t.mGap);
		}

		// Equality Operators
		//--------------------
		bool		operator==(const tokenizer &t)		{return (mLoc==t.mLoc);}
		bool		operator!=(const tokenizer &t)		{return !(operator==(t));}



		// DeReference Operator
		//----------------------
		const char*	operator*()
		{
			assert(mLoc);
			return mLoc;
		}

		// Inc & Dec Operators
		//--------------------
		void		operator++(int)
		{
			assert(mLoc && mGap[0]);
			mLoc = str::tok(NULL, mGap);
		}

		// Data
		//------
	private:
		char*					mLoc;
		char					mGap[TOKEN_GAP_LEN];
	};


    ////////////////////////////////////////////////////////////////////////////////////
	// Get An Iterator To The First Token Seperated By Gap
    ////////////////////////////////////////////////////////////////////////////////////
	tokenizer	begin(const char* gap)
	{
		return tokenizer(mData, gap);
	}

    ////////////////////////////////////////////////////////////////////////////////////
	// The Invalid Iterator, Use As A Stop Condition In Your For Loops
    ////////////////////////////////////////////////////////////////////////////////////
	tokenizer	end()
	{
		return tokenizer();
	}

};


}

//fixme get rid of these
typedef ratl::string_vs<256> TString_vs;
typedef ratl::string_vs<128> TUIString_vs;

#endif