/*****************************************************************************

        GRAOUMF TRACKER 2
        Author: Laurent de Soras, 1996-2016

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/



/*\\\ FICHIERS INCLUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include	"base.h"
#include	"base_ct.h"
#include	"log.h"
#include	"String.h"

#include	<cassert>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>



/*\\\ CONSTANTES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ CONSTANTES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ TYPES & STRUCTURES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ METHODES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: (constructeur)                                                 */
/*      Description: Initialise                                             */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*==========================================================================*/

String::String ()
{
	_text_0 = new char [1];
	if (_text_0 == NULL)
	{
		LOG_printf ("String::String: Error: couldn't allocate memory for string data.\n");
	}
	_text_0 [0] = '\0';
}



String::String (const String &other)
{
	_text_0 = new char [other.get_len () + 1];
	if (_text_0 == NULL)
	{
		LOG_printf ("String::String: Error: couldn't allocate memory for string data.\n");
	}
	strcpy (_text_0, other._text_0);
}



String::String (const char *text_0)
{
	_text_0 = new char [strlen (text_0) + 1];
	if (_text_0 == NULL)
	{
		LOG_printf ("String::String: Error: couldn't allocate memory for string data.\n");
	}
	strcpy (_text_0, text_0);
}



String::String (long length, char fill)
{
	_text_0 = NULL;

	if (length < 0)
	{
		LOG_printf ("String::String: Error: length can't be negative (%ld).\n", length);
		return;
	}

	_text_0 = new char [length + 1];
	if (_text_0 == NULL)
	{
		LOG_printf ("String::String: Error: couldn't allocate memory for string data.\n");
	}

	memset (_text_0, fill, length);
	_text_0 [length] = '\0';
}



/*==========================================================================*/
/*      Nom: (destructeur)                                                  */
/*      Description: Detruit                                                */
/*==========================================================================*/

String::~String (void)
{
	if (_text_0 != NULL)
	{
		delete [] _text_0;
		_text_0 = NULL;
	}
}



/*==========================================================================*/
/*      Nom: check_ok                                                       */
/*      Description: Verifie l'intergrite de l'objet.                       */
/*      Retour: 0 si l'objet parait correct.                                */
/*==========================================================================*/

signed int	String::check_ok (void) const
{
	if (this == NULL)
	{
		LOG_printf ("String::check_ok: Error: \"this\" pointer is NULL.\n");
		return (-1);
	}

	if (_text_0 == NULL)
	{
		LOG_printf ("String::check_ok: Error: _text_0 is NULL.\n");
		return (-1);
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: self_display                                                   */
/*      Description: Affiche "textuellement" le contenu courant de l'objet. */
/*==========================================================================*/

void	String::self_display (void) const
{

	/*** A faire ***/

}



const char *	String::c_str () const
{
	return (_text_0);
}



String	&String::operator = (const String &other)
{
	if (&other == this)
	{
		return (*this);
	}

	if (_text_0 != NULL)
	{
		delete [] _text_0;
	}

	_text_0 = new char [other.get_len () + 1];
	if (_text_0 == NULL)
	{
		LOG_printf ("String::operator =: Error: couldn't allocate memory for string data.\n");
	}
	strcpy (_text_0, other._text_0);

	return (*this);
}


int	String::operator == (const String &other) const
{
	return (strcmp (_text_0, other.c_str ()) == 0);
}



int	String::operator != (const String &other) const
{
	return (! (*this == other));
}



String	String::operator + (const char *other_0) const
{
	return (String (*this) += other_0);
}



String	String::operator + (const String &other) const
{
	return (String (*this) += other);
}



String	&String::operator += (const char *other_0)
{
	char		*temp_0;

	temp_0 = new char [strlen (_text_0) + strlen (other_0) + 1];
	if (temp_0 == NULL)
	{
		LOG_printf ("String::operator =: Error: couldn't allocate memory for string data.\n");
		return (*this);
	}
	strcpy (temp_0, _text_0);
	delete [] _text_0;
	_text_0 = temp_0;
	strcat (_text_0, other_0);

	return (*this);
}



String	&String::operator += (const String &other)
{
	return ((*this) += other.c_str ());
}



String	String::trim (void) const
{
	/* Cherche le debut */
	char *			temp_0 = _text_0;
	while (   *temp_0 != '\0'
	       && (   *temp_0 == ' '
	           || *temp_0 == '\t'
	           || *temp_0 == '\v'
	           || *temp_0 == '\n'))
	{
		temp_0 ++;
	}

	/* Cherche la fin */
	long			length = long (strlen (temp_0)) - 1;
	while (   length >= 0
	       && (   temp_0 [length] == ' '
	           || temp_0 [length] == '\t'
	           || temp_0 [length] == '\v'
	           || temp_0 [length] == '\n'))
	{
		length --;
	}
	length ++;

	/* Recopie les donnees utiles */
	String	new_str (length);
	memcpy (new_str._text_0, temp_0, length);
	new_str._text_0 [length] = '\0';

	return (new_str);
}



String	String::mid (long start, long length) const
{
	long				real_len = long (strlen (_text_0)) - start;
	real_len = MIN (real_len, length);
	real_len = MAX (real_len, 0);
	String	new_str (real_len);
	if (real_len > 0)
	{
		memcpy (new_str._text_0, _text_0 + start, real_len);
	}
	new_str._text_0 [real_len] = '\0';

	return (new_str);
}



String	String::left (long length) const
{
	long				real_len = long (strlen (_text_0));
	real_len = MIN (real_len, length);
	String	new_str (real_len);
	if (real_len > 0)
	{
		memcpy (new_str._text_0, _text_0, real_len);
	}
	new_str._text_0 [real_len] = '\0';

	return (new_str);
}



String	String::right (long length) const
{
	long				org_str_len = long (strlen (_text_0));
	long				real_len = MIN (org_str_len, length);
	real_len = MAX (real_len, 0);
	String	new_str (real_len);
	if (real_len > 0)
	{
		memcpy (new_str._text_0, _text_0 + org_str_len - real_len, real_len);
	}
	new_str._text_0 [real_len] = '\0';

	return (new_str);
}



String	String::after (long pos) const
{
	long				org_str_len = long (strlen (_text_0));
	pos ++;
	pos = MIN (pos, org_str_len);
	pos = MAX (pos, 0);

	return (String (_text_0 + pos));
}



long	String::find (char c, long start_pos) const
{
	assert (start_pos <= get_len ());

	const char *	dummy_0 = strchr (_text_0 + start_pos, c);
	if (dummy_0 == 0)
	{
		return (-1);
	}

	return (long (dummy_0 - _text_0));
}



long	String::find (const char *f_0, long start_pos) const
{
	assert (f_0 != 0);
	assert (f_0 [0] != '\0');
	assert (start_pos <= get_len ());

	const char *	dummy_0 = strstr (_text_0 + start_pos, f_0);
	if (dummy_0 == 0)
	{
		return (-1);
	}

	return (long (dummy_0 - _text_0));
}



long	String::rfind (char c, long start_pos) const
{
	const long		len = get_len ();
	assert (start_pos <= len);
	long				pos = len;
	if (start_pos >= 0)
	{
		pos = start_pos;
	}

	do
	{
		if (_text_0 [pos] == c)
		{
			break;
		}
		else
		{
			-- pos;
		}
	}
	while (pos >= 0);

	return (pos);
}



long	String::get_len (void) const
{
	return (long (strlen (_text_0)));
}



const char	String::operator [] (long pos) const
{
	assert (pos >= 0);
	assert (pos < get_len ());

	return (_text_0 [pos]);
}



void	String::erase (long start, long length)
{
	const long		slen = get_len ();
	assert (start >= 0);
	assert (length > 0);
	assert (start + length <= slen);

	const long		src = start + length;
	memmove (_text_0 + start, _text_0 + src, 1 + slen - src);
}



void	String::find_replace (const char *f_0, const char *r_0, long pos)
{
	assert (f_0 != 0);
	assert (r_0 != 0);
	assert (pos >= 0);
	assert (pos <= get_len ());
	const long		f_len = long (strlen (f_0));
	const long		r_len = long (strlen (r_0));
	assert (f_len > 0);

	const char *	result_0;
	do
	{
		result_0 = strstr (_text_0 + pos, f_0);
		if (result_0 != 0)
		{
			long			slen = get_len ();
			char *		txt2_0 = new char [slen + 1 - f_len + r_len];
			const long	f_pos = long (result_0 - _text_0);
			memcpy (txt2_0, _text_0, f_pos);
			memcpy (txt2_0 + f_pos, r_0, r_len);
			memcpy (txt2_0 + f_pos + r_len, _text_0 + f_pos + f_len, 1 + slen - (f_pos + f_len));
			delete [] _text_0;
			_text_0 = txt2_0;
		}
	}
	while (result_0 != 0);
}



/*\\\ METHODES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/****************************************************************************/
/*                                                                          */
/*                                                                          */
/*                                                                          */
/****************************************************************************/



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/
