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

        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	<stdio.h>

#include	"base_ct.h"
#include	"gtracker.h"
#include	"log.h"
#include	"PatEvent.h"
#include	"PatEventField.h"
#include	"PatEventFieldNote.h"
#include	"PatEventFieldInstr.h"
#include	"PatEventFieldCmd.h"
#include	"PatEventFieldVol.h"
#include	"PatEventFieldVal2d.h"
#include	"PatEventFieldVal3d.h"
#include	"PatEventFieldValInt.h"
#include	"PatEventFieldVal4h.h"
#include	"PatEventFieldEffect4h.h"
#include	"PatEventFieldEffect6h.h"
#include	"PatEventFieldVal2h.h"
#include	"tracks.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:                                        */
/*==========================================================================*/

PatEvent::PatEvent ()
{
	_nbr_fields = 0;
	for (int cnt = 0; cnt < PatEvent_MAX_NBR_FIELDS; cnt ++)
	{
		_field_ptr_tab [cnt] = NULL;
	}
}



PatEvent::PatEvent (const PatEvent &other)
{
	_nbr_fields = other._nbr_fields;
	for (int cnt = 0; cnt < _nbr_fields; cnt ++)
	{
		_field_ptr_tab [cnt] = other._field_ptr_tab [cnt]->clone ();
	}
}



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

PatEvent::~PatEvent (void)
{
	clear ();
}



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

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

	if (_nbr_fields < 0)
	{
		LOG_printf ("PatEvent::check_ok: Error: _nbr_fields is < 0.\n");
		return (-1);
	}

	for (int cnt = 0; cnt < _nbr_fields; cnt ++)
	{
		if (_field_ptr_tab [cnt]->check_ok ())
		{
			return (-1);
		}
	}

	return (0);
}



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

void	PatEvent::self_display (void) const
{

	/*** A faire ***/

}



void	PatEvent::operator = (const PatEvent &other)
{
	if (&other == this)
	{
		return;
	}

	clear ();

	_nbr_fields = other._nbr_fields;
	for (int cnt = 0; cnt < _nbr_fields; cnt ++)
	{
		_field_ptr_tab [cnt] = other._field_ptr_tab [cnt]->clone ();
	}
}



int	PatEvent::operator == (const PatEvent &other) const
{
	for (int cnt = 0; cnt < _nbr_fields; cnt ++)
	{
		if (_field_ptr_tab [cnt] != other._field_ptr_tab [cnt])
		{
			return (false);
		}
	}

	return (true);
}



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



void	PatEvent::get_data (int track_type, BYTE *data_ptr) const
{
	int		field;
	int		ext_track_type;
	int		content;
	bool		found_flag;
	BYTE		*cur_data_ptr;
	PatEventField	*field_ptr;

	field = 0;
	field_ptr = NULL;
	cur_data_ptr = data_ptr;
	ext_track_type = GTK_get_ext_track_type (track_type, data_ptr);
	while ((content = TRK_note_content [ext_track_type] [field].content) >= 0)
	{
		found_flag = false;
		int				cnt = 0;
		while (cnt < _nbr_fields)
		{
			if (content == _field_ptr_tab [cnt]->get_type ())
			{
				found_flag = true;
				break;
			}
			++ cnt;
		}

		if (found_flag)
		{
			_field_ptr_tab [cnt]->get_data (cur_data_ptr);
			cur_data_ptr += _field_ptr_tab [cnt]->get_length ();
		}

		else
		{
			field_ptr = PatEventField::create_field (content);
			cur_data_ptr += field_ptr->get_length ();
			delete field_ptr;
			field_ptr = NULL;
		}

		ext_track_type = GTK_get_ext_track_type (track_type, data_ptr);
		field ++;
	}
}



void	PatEvent::set_data (int track_type, const BYTE *data_ptr)
{
	int		ext_track_type;
	int		field;
	int		content;
	PatEventField	*field_ptr;

	clear ();

	ext_track_type = GTK_get_ext_track_type (track_type, data_ptr);
	field = 0;
	field_ptr = NULL;
	while ((content = TRK_note_content [ext_track_type] [field].content) >= 0)
	{
		field_ptr = PatEventField::create_field (content);
		add_field (*field_ptr);
		delete field_ptr;
		field_ptr = NULL;

		_field_ptr_tab [field]->set_data (data_ptr);
		data_ptr += _field_ptr_tab [field]->get_length ();

		field ++;
	}
}



PatEventField	*PatEvent::get_field (int index) const
{
	if (index >= _nbr_fields)
	{
		return (NULL);
	}

	return (_field_ptr_tab [index]->clone ());
}



/* Index indique le debut de la recherche. Au retour,
	c'est l'indice trouve ou -1 */
PatEventField	*PatEvent::get_field_type (int type, int &index) const
{
	for (; index < _nbr_fields; index ++)
	{
		if (_field_ptr_tab [index]->get_type () == type)
		{
			return (_field_ptr_tab [index]->clone ());
		}
	}

	index = -1;
	return (NULL);
}



signed int	PatEvent::set_field (int index, const PatEventField *other_ptr)
{
	if (index < 0 || index >= _nbr_fields)
	{
		index = _nbr_fields;
		_nbr_fields ++;
	}
	else
	{
		delete _field_ptr_tab [index];
	}

	_field_ptr_tab [index] = other_ptr->clone ();
	if (_field_ptr_tab [index] == NULL)
	{
		LOG_printf ("PatEvent::set_field: Error: couldn't duplicate field.\n");
		return (-1);
	}

	return (0);
}



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



void	PatEvent::add_field (const PatEventField &other)
{
	_field_ptr_tab [_nbr_fields] = other.clone ();
	_nbr_fields ++;
}



void	PatEvent::clear (void)
{
	for ( ; _nbr_fields > 0; _nbr_fields --)
	{
		delete _field_ptr_tab [_nbr_fields - 1];
		_field_ptr_tab [_nbr_fields - 1] = NULL;
	}
}



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



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