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

GRAOUMF TRACKER 2

Copyright (c) 1996 - 2002 Laurent de Soras

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.

Contact the author : laurent@ohmforce.com
More information about this license : http://www.gnu.org/licenses/gpl.html

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



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

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

#include	"base.h"
#include	"base_ct.h"
#include	"EditString.h"
#include	"Graphic.h"
#include	"intrface.h"
#include	"keyboard.h"
#include	"log.h"
#include	"memory.h"
#include	"mouse.h"
#include	"os.h"
#include	"resource.h"
#include	"String.h"



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



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



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



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

/* Pointeur sur l'objet affiche s'il existe, NULL sinon. */
EditString	*EditString::displayed_edit_string_ptr = NULL;



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



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



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

EditString::EditString (char *text_0, int object, int max_len, int type)
{
	_displayed_flag = false;
	_text_0 = text_0;
	_object = object;
	_max_len = max_len;
	_type = type;

	/* Reserve de la memoire pour la chaine de travail */
	_work_0 = (char *) MALLOC (max_len + 1);
	if (_work_0 == NULL)
	{
		LOG_printf ("EditString::EditString: Error: couldn't reserve workspace.\n");
		return;
	}
}



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

EditString::~EditString (void)
{
	_displayed_flag = false;

	if (_work_0 != NULL)
	{
		FREE (_work_0);
		_work_0 = NULL;
	}
}



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

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

	return (0);
}



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

void	EditString::self_display (void) const
{

	/*** A faire ***/

}



void	EditString::redraw (void)
{
	if (_displayed_flag)
	{
		refresh ();
	}
}



void	EditString::refresh (void)
{
	int		dest_pos;
	int		disp_flag;
	int		cursor_pos_2;
	int		src_pos;
	Graphic_FRAME_INFO	cursor =
	{
		0, 0, RSC_CHAR_W, RSC_CHAR_H,
		1, 1, 1, 1
	};

	if (_displayed_flag)
	{
		cursor.y = RSC_absolute_object_pixypos [_object];

		src_pos = _disp_pos;
		if (_type == EditString_TYPE_FIX)
		{
			if (_disp_pos > _point_pos)
			{
				src_pos --;
			}
		}
		else if (_type == EditString_TYPE_MSC)
		{
			if (_disp_pos > 2)
			{
				src_pos --;
				if (_disp_pos > 5)
				{
					src_pos --;
				}
			}
		}
		disp_flag = true;
		for (dest_pos = 0; dest_pos < _disp_len; dest_pos ++)
		{
			if (   _type == EditString_TYPE_MSC
			    && dest_pos + _disp_pos == 2
			    && disp_flag)
			{
				_string_0 [dest_pos] = ':';
				disp_flag = false;
			}
			else if (   (   (   _type == EditString_TYPE_FIX
			                 && dest_pos + _disp_pos == _point_pos)
			             || (   _type == EditString_TYPE_MSC
			                 && dest_pos + _disp_pos == 5))
			         && disp_flag)
			{
				_string_0 [dest_pos] = '.';
				disp_flag = false;
			}
			else
			{
				if (src_pos < _max_len)
				{
					_string_0 [dest_pos] = _work_0 [src_pos];
					src_pos ++;
				}
				else
				{
					_string_0 [dest_pos] = ' ';
				}
				disp_flag = true;
			}
		}
		RSC_display_object (_object);
		cursor_pos_2 = _cursor_pos - _disp_pos;
		if (_type == EditString_TYPE_FIX)
		{
			if (_cursor_pos >= _point_pos)
			{
				cursor_pos_2 ++;
			}
		}
		else if (_type == EditString_TYPE_MSC)
		{
			if (_cursor_pos >= 2)
			{
				cursor_pos_2 ++;
				if (_cursor_pos >= 4)
				{
					cursor_pos_2 ++;
				}
			}
		}
		cursor.x =   RSC_absolute_object_pixxpos [_object]
		           + cursor_pos_2 * RSC_CHAR_W;
		INTR_graph_ptr->display_xorbox (&cursor);
		INTR_graph_ptr->unlock_screen ();
	}
}



signed int	EditString::manage (void)
{
	char		*found;				/* Pointeur sur le resultat de la recherche d'un strchr () */
	int		string_len;			/* Longueur de la chaine d'entree */
	int		test_len;
	bool		point_flag;			/* Presence du point */
	LWORD		key;					/* Touche pressee par l'utilisateur */
	int		ascii_code;			/* Code ASCII de la touche pressee */
	int		scan_code;			/* Code scan de la touche pressee */
	signed int	op_len;			/* Longueur de texte a manipuler dans un champ */
	Mouse_CURRENT_STATE	mouse;

/*______________________________________________
 *
 * Initialisations
 *______________________________________________
 */

	_string_0 = RSC_get_string (_object);
	_disp_len = int (strlen (_string_0));
	test_len = RSC_get_width (_object) / RSC_CHAR_W;
	if (test_len > _disp_len)
	{
		RSC_set_string (_object, String (test_len).c_str ());
		_string_0 = RSC_get_string (_object);
		_disp_len = test_len;
	}

	/* Copie la chaine d'entree dans la chaine de travail et complete par des
		espaces. Tous les characteres "fixes" (separateurs) sont elimines. */
	if (_type == EditString_TYPE_MSC)
	{
		_work_0 [0] = _text_0 [0];
		_work_0 [1] = _text_0 [1];
		_work_0 [2] = _text_0 [3];
		_work_0 [3] = _text_0 [4];
		_work_0 [4] = _text_0 [6];
		_work_0 [5] = _text_0 [7];
		_max_len = 6;
		_disp_len = MIN ((int) strlen (_string_0), 8);
	}
	else
	{
		strncpy (_work_0, _text_0, _max_len);
		_disp_len = MIN ((int) strlen (_string_0), _max_len);
	}
	_work_0 [_max_len] = 0;
	string_len = int (strlen (_work_0));
	if (string_len < _max_len)
	{
		memset (_work_0 + string_len, ' ', _max_len - string_len);
	}

	/* Recherche la position du point. Si on est en virgule fixe, on le vire */
	point_flag = false;
	_point_pos = -1;
	if (_type == EditString_TYPE_FIX)
	{
		found = strchr (_work_0, '.');
		if (found == NULL)
		{
			if (_type == EditString_TYPE_FIX)
			{
				_type = EditString_TYPE_DEC;	/* Si pas de point en virgule fixe, edite un entier */
			}
		}
		else
		{
			point_flag = true;
			_point_pos = int (found - _work_0);
			if (_type == EditString_TYPE_FIX)
			{
				memmove (found, found + 1, strlen (found + 1));
				_max_len --;
				_work_0 [_max_len] = '\0';
			}
		}
	}
	if (   _type == EditString_TYPE_FIX
	    && _max_len < 1)
	{
		LOG_printf ("EDIT_edit_string: Error: input string has null length.\n");
		return (-1);
	}

	memset (_string_0, ' ', strlen (_string_0));
	_disp_pos = 0;
	_cursor_pos = 0;
	KEYB_flush_keyboard_buffer ();

	_displayed_flag = true;
	displayed_edit_string_ptr = this;
	redraw ();

/*______________________________________________
 *
 * Boucle principale
 *______________________________________________
 */

	for ( ; ; )
	{
		check_disp_pos ();
		refresh ();
		INTR_wait_mouse (true);

		/* Attente de la frappe d'une touche */
		while (! OS_key_pressed ())
		{
			INTR_graph_ptr->get_mouse (&mouse);

			/* Annulation */
			if (mouse.k != 0)
			{
				INTR_wait_mouse (true);
				displayed_edit_string_ptr = NULL;
				_displayed_flag = false;
				RSC_display_object (_object);
				return (-2);
			}
		}

		key = OS_get_key ();
		ascii_code = (int) (key & 0xFF);
		scan_code = (int) ((key >> 16) & 0xFF);

/*______________________________________________
 *
 * Touches speciales
 *______________________________________________
 */

		switch (scan_code)
		{
		/* Annulation */
		case	KEYB_SCANCODE_ESC:
			displayed_edit_string_ptr = NULL;
			_displayed_flag = false;
			RSC_display_object (_object);
			return (-2);
			break;

		/* Fleche gauche */
		case	KEYB_SCANCODE_LEFT:
			_cursor_pos --;
			_cursor_pos = MAX (_cursor_pos, 0);
			continue;
			break;

		/* Fleche droite */
		case	KEYB_SCANCODE_RIGHT:
			_cursor_pos ++;
			_cursor_pos = MIN (_cursor_pos, _max_len - 1);
			continue;
			break;

		/* Delete */
		case	KEYB_SCANCODE_DELETE:
			op_len = _max_len - _cursor_pos - 1;
			if (op_len > 0)
			{
				memmove (_work_0 + _cursor_pos, _work_0 + _cursor_pos + 1, op_len);
			}
			_work_0 [_max_len - 1] = ' ';
			continue;
			break;

		/* Backspace */
		case	KEYB_SCANCODE_BACKSPACE:
			if (_cursor_pos > 0)
			{
				op_len = _max_len - _cursor_pos;
				memmove (_work_0 + _cursor_pos - 1,
				         _work_0 + _cursor_pos,
				         op_len);
				_work_0 [_max_len - 1] = ' ';
				_cursor_pos --;
			}
			continue;
			break;

		/* Debut */
		case	KEYB_SCANCODE_CLRHOME:
			_cursor_pos = 0;
			continue;
			break;

		/* Fin */
		case	KEYB_SCANCODE_END:
			_cursor_pos = _max_len;
			while (   _work_0 [_cursor_pos - 1] == ' '
			       && _cursor_pos > 0)
			{
				_cursor_pos --;
			}
			_cursor_pos = MIN (_cursor_pos, _max_len - 1);
			continue;
			break;

		/* Page Up */
		case	KEYB_SCANCODE_PAGEUP:
			_cursor_pos -= _disp_len;
			_cursor_pos = MAX (_cursor_pos, 0);
			continue;
			break;

		/* Page Down */
		case	KEYB_SCANCODE_PAGEDOWN:
			_cursor_pos += _disp_len;
			_cursor_pos = MIN (_cursor_pos, _max_len - 1);
			continue;
			break;
		}

		/* Return */
		if (ascii_code == KEYB_ASCIICODE_RETURN)
		{
			if (_type == EditString_TYPE_MSC)
			{
				_text_0 [0] = _work_0 [0];
				_text_0 [1] = _work_0 [1];
				_text_0 [2] = ':';
				_text_0 [3] = _work_0 [2];
				_text_0 [4] = _work_0 [3];
				_text_0 [5] = '.';
				_text_0 [6] = _work_0 [4];
				_text_0 [7] = _work_0 [5];
				_text_0 [8] = '\0';
			}
			else if (_type == EditString_TYPE_FIX)
			{
				memcpy (_text_0, _work_0, _point_pos);
				_text_0 [_point_pos] = '.';
				strcpy (_text_0 + _point_pos + 1, _work_0 + _point_pos);
			}
			else
			{
				strcpy (_text_0, _work_0);
			}
			displayed_edit_string_ptr = NULL;
			_displayed_flag = false;
			RSC_display_object (_object);
			return (0);
		}

/*______________________________________________
 *
 * Accepte ou rejette le caractere en fonction
 * du type. Place le curseur si necessaire
 *______________________________________________
 */

		switch (_type)
		{
		case	EditString_TYPE_ALPHA:
			if (ascii_code < 32)
			{
				continue;
			}
			break;

		case	EditString_TYPE_HEXA:
			if (   (ascii_code < '0' || ascii_code > '9')
				 && (toupper (ascii_code) < 'A' || toupper (ascii_code) > 'F'))
			{
				continue;
			}
			break;

		case	EditString_TYPE_DEC:
			if (ascii_code < '0' || ascii_code > '9')
			{
				continue;
			}
			break;

		case	EditString_TYPE_FLO:
			if (   (ascii_code < '0' || ascii_code > '9')
			    && ascii_code != '-' && ascii_code != '.')
			{
				continue;
			}
			break;

		case	EditString_TYPE_FIX:
			if (ascii_code == '.')
			{
				if (point_flag)
				{
					_cursor_pos = _point_pos;
					continue;
				}
			}
			else if (ascii_code < '0' || ascii_code > '9')
			{
				continue;
			}
			break;

		case	EditString_TYPE_MSC:
			if (ascii_code == ':')
			{
				_cursor_pos = 2;
				continue;
			}
			else if (ascii_code == '.')
			{
				_cursor_pos = 4;
				continue;
			}
			else if (ascii_code < '0' || ascii_code > '9')
			{
				continue;
			}
			break;
		}

/*______________________________________________
 *
 * Insere le caractere et deplace ensuite le
 * curseur.
 *______________________________________________
 */

		op_len = _max_len - _cursor_pos;
		if (op_len > 1 && _type != EditString_TYPE_MSC)
		{
			memmove (_work_0 + _cursor_pos + 1, _work_0 + _cursor_pos, op_len - 1);
		}
		_work_0 [_cursor_pos] = ascii_code;
		_cursor_pos ++;
		_cursor_pos = MAX (MIN (_cursor_pos, _max_len - 1), 0);
	}
}



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



void	EditString::check_disp_pos (void)
{
	int		real_cursor_pos;

	real_cursor_pos = _cursor_pos;
	if (_type == EditString_TYPE_MSC)
	{
		if (_cursor_pos >= 4)
		{
			real_cursor_pos ++;
			if (_cursor_pos >= 2)
			{
				real_cursor_pos ++;
			}
		}
	}
	else if (_type == EditString_TYPE_FIX)
	{
		if (_cursor_pos >= _point_pos)
		{
			real_cursor_pos ++;
		}
	}

	_disp_pos = MIN (_disp_pos, real_cursor_pos);
	_disp_pos = MAX (_disp_pos, real_cursor_pos - _disp_len + 1);
}



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



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