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

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	"archi.h"
#include	"base.h"
#include	"base_ct.h"
#include	"ClipBPat.h"
#include	"List.h"
#include	"log.h"
#include	"PatEvent.h"
#include	"PatSelection.h"
#include	"patt.h"
#include	"UndoCell.h"
#include	"UndoCellList.h"
#include	"UndoCellPatClear.h"
#include	"UndoCellPatPaste.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:                                        */
/*==========================================================================*/

ClipBPat::ClipBPat ()
{
	_nbr_tracks = 0;
	_nbr_lines = 0;
	_event_ptr = NULL;
}



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

ClipBPat::~ClipBPat (void)
{
	empty ();
}



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

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

	if (_event_ptr == NULL && _nbr_tracks != 0 && _nbr_lines != 0)
	{
		LOG_printf ("ClipBPat::check_ok: Error: _event_ptr pointer is NULL.\n");
		return (-1);
	}

	return (0);
}



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

void	ClipBPat::self_display (void) const
{

	/*** A faire ***/

}



signed int	ClipBPat::copy (const PatSelection &src_sel)
{
	int		line_cnt;
	int		track_cnt;
	int		track_type;
	PatEvent	*cur_evt_ptr;

	/* D'abord, on vide l'ancien contenu du clipboard */
	empty ();

	/* On recueille les infos sur le morceau a copier */
	_nbr_lines = src_sel.get_nbr_lines ();
	_nbr_tracks = src_sel.get_nbr_col ();
	track_type = src_sel.get_track_type ();
	_event_ptr = new PatEvent [(long)_nbr_lines * _nbr_tracks];
	if (_event_ptr == NULL)
	{
		LOG_printf ("ClipBPat::copy: Error: couldn't allocate memory for note array.\n");
		return (-1);
	}

	/* Copie le morceau de pattern */
	cur_evt_ptr = _event_ptr;
	for (line_cnt = 0; line_cnt < _nbr_lines; line_cnt ++)
	{
		for (track_cnt = 0; track_cnt < _nbr_tracks; track_cnt ++)
		{
			cur_evt_ptr->set_data (track_type,
			                       (UBYTE *) src_sel.get_note_ptr (track_cnt, line_cnt));
			cur_evt_ptr ++;
		}
	}

	return (0);
}



signed int	ClipBPat::cut (const PatSelection &src_sel, UndoCell **undo_ptr_ptr)
{
	int		track_type;
	int		line_cnt;
	int		track_cnt;
	int		pattern;
	int		track_nbr;
	int		first_line;
	List		undo_list;

	/* On commence par copier les donnees */
	if (copy (src_sel))
	{
		LOG_printf ("ClipBPat::cut: Error: couldn't copy selection into clipboard.\n");
		return (-1);
	}

	/* Maintenant on efface toute la selection */
	track_type = src_sel.get_track_type ();
	pattern = src_sel.get_pattern ();
	first_line = src_sel.get_start_line ();
	for (track_cnt = 0; track_cnt < _nbr_tracks; track_cnt ++)
	{
		track_nbr = src_sel.get_track (track_cnt);

		/* Sauvegarde de la piste pour l'undo */
		undo_list.add (&UndoCellPatClear (track_type, pattern, first_line, track_nbr, _nbr_lines));

		for (line_cnt = 0; line_cnt < _nbr_lines; line_cnt ++)
		{
			PAT_clear_note (track_type, pattern, first_line + line_cnt, track_nbr);
		}
	}

	if (undo_ptr_ptr != NULL)
	{
		*undo_ptr_ptr = new UndoCellList (undo_list);
	}

	return (0);
}



signed int	ClipBPat::paste (const PatSelection &dest_sel, UndoCell **undo_ptr_ptr) const
{
	int		track;
	int		top_line;
	int		line_cnt;
	int		track_cnt;
	int		nbr_dest_tracks;
	int		nbr_dest_lines;
	int		track_type;
	int		pattern;
	List		undo_list;
	PatEvent	*cur_evt_ptr;

	/* Clipboard vide: on se casse direct */
	if (! is_empty ())
	{
		track_type = dest_sel.get_track_type ();

		/* Reduit l'operation au plus petit bloc des deux */
		nbr_dest_lines = dest_sel.get_nbr_lines ();
		nbr_dest_lines = MIN (nbr_dest_lines, _nbr_lines);
		nbr_dest_tracks = dest_sel.get_nbr_col ();
		nbr_dest_tracks = MIN (nbr_dest_tracks, _nbr_tracks);

		/* Sauvegarde pour l'undo */
		if (undo_ptr_ptr != NULL)
		{
			top_line = dest_sel.get_start_line ();
			pattern = dest_sel.get_pattern ();
			for (track_cnt = 0; track_cnt < nbr_dest_tracks; track_cnt ++)
			{
				track = dest_sel.get_track (track_cnt);
				undo_list.add (&UndoCellPatPaste (track_type, pattern, top_line, track, nbr_dest_lines));
			}
		}
		
		/* Colle le morceau de pattern */
		for (line_cnt = 0; line_cnt < nbr_dest_lines; line_cnt ++)
		{
			cur_evt_ptr = _event_ptr + (long)line_cnt * _nbr_tracks;
			for (track_cnt = 0; track_cnt < nbr_dest_tracks; track_cnt ++)
			{
				cur_evt_ptr->get_data (dest_sel.get_track_type (),
				                       (UBYTE *) dest_sel.get_note_ptr (track_cnt, line_cnt));
				cur_evt_ptr ++;
			}
		}

		if (undo_ptr_ptr != NULL)
		{
			*undo_ptr_ptr = new UndoCellList (undo_list);
		}
	}

	return (0);
}



signed int	ClipBPat::empty (void)
{
	if (_event_ptr != NULL)
	{
		delete []	_event_ptr;
		_event_ptr = NULL;
	}
	_nbr_tracks = 0;
	_nbr_lines = 0;

	return (0);
}



bool ClipBPat::is_empty (void) const
{
	return (_event_ptr == NULL);
}



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



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



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