// Game_Music_Emu $vers. http://www.slack.net/~ant/

#include "Gme_File.h"

/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module 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 Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */

#include "blargg_source.h"

void Gme_File::unload()
{
	clear_playlist(); // BEFORE clearing track count
	track_count_     = 0;
	raw_track_count_ = 0;
	Gme_Loader::unload();
}

Gme_File::Gme_File()
{
	type_           = NULL;
	user_data_      = NULL;
	user_cleanup_   = NULL;
	Gme_File::unload(); // clears fields
}

Gme_File::~Gme_File()
{
	if ( user_cleanup_ )
		user_cleanup_( user_data_ );
}

blargg_err_t Gme_File::post_load()
{
	if ( !track_count() )
		set_track_count( type()->track_count );
	return Gme_Loader::post_load();
}

void Gme_File::clear_playlist()
{
	playlist.clear();
	clear_playlist_();
	track_count_ = raw_track_count_;
}

void Gme_File::copy_field_( char out [], const char* in, int in_size )
{
	if ( !in || !*in )
		return;
	
	// remove spaces/junk from beginning
	while ( in_size && unsigned (*in - 1) <= ' ' - 1 )
	{
		in++;
		in_size--;
	}
	
	// truncate
	if ( in_size > max_field_ )
		in_size = max_field_;
	
	// find terminator
	int len = 0;
	while ( len < in_size && in [len] )
		len++;
	
	// remove spaces/junk from end
	while ( len && unsigned (in [len - 1]) <= ' ' )
		len--;
	
	// copy
	out [len] = 0;
	memcpy( out, in, len );
	
	// strip out stupid fields that should have been left blank
	if ( !strcmp( out, "?" ) || !strcmp( out, "<?>" ) || !strcmp( out, "< ? >" ) )
		out [0] = 0;
}

void Gme_File::copy_field_( char out [], const char* in )
{
	copy_field_( out, in, max_field_ );
}

blargg_err_t Gme_File::remap_track_( int* track_io ) const
{
	if ( (unsigned) *track_io >= (unsigned) track_count() )
		return BLARGG_ERR( BLARGG_ERR_CALLER, "invalid track" );
	
	if ( (unsigned) *track_io < (unsigned) playlist.size() )
	{
		M3u_Playlist::entry_t const& e = playlist [*track_io];
		*track_io = 0;
		if ( e.track >= 0 )
		{
			*track_io = e.track;
			// TODO: really needs to be removed?
			if ( !(type_->flags_ & 0x02) )
				*track_io -= e.decimal_track;
		}
		if ( *track_io >= raw_track_count_ )
			return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "invalid track in m3u playlist" );
	}
	else
	{
		check( !playlist.size() );
	}
	return blargg_ok;
}

blargg_err_t Gme_File::track_info( track_info_t* out, int track ) const
{
	out->track_count   = track_count();
	out->length        = -1;
	out->loop_length   = -1;
	out->intro_length  = -1;
	out->fade_length   = -1;
	out->play_length   = -1;
	out->repeat_count  = -1;
	out->song      [0] = 0;
	out->game      [0] = 0;
	out->author    [0] = 0;
	out->composer  [0] = 0;
	out->engineer  [0] = 0;
	out->sequencer [0] = 0;
	out->tagger    [0] = 0;
	out->copyright [0] = 0;
	out->date      [0] = 0;
	out->comment   [0] = 0;
	out->dumper    [0] = 0;
	out->system    [0] = 0;
	out->disc      [0] = 0;
	out->track     [0] = 0;
	out->ost       [0] = 0;
	
	copy_field_( out->system, type()->system );
	
	int remapped = track;
	RETURN_ERR( remap_track_( &remapped ) );
	RETURN_ERR( track_info_( out, remapped ) );
	
	// override with m3u info
	if ( playlist.size() )
	{
		M3u_Playlist::info_t const& i = playlist.info();
		copy_field_( out->game     , i.title );
		copy_field_( out->author   , i.artist );
		copy_field_( out->engineer , i.engineer );
		copy_field_( out->composer , i.composer );
		copy_field_( out->sequencer, i.sequencer );
		copy_field_( out->copyright, i.copyright );
		copy_field_( out->dumper   , i.ripping );
		copy_field_( out->tagger   , i.tagging );
		copy_field_( out->date     , i.date );
		
		M3u_Playlist::entry_t const& e = playlist [track];
		if ( e.length >= 0 ) out->length       = e.length;
		if ( e.intro  >= 0 ) out->intro_length = e.intro;
		if ( e.loop   >= 0 ) out->loop_length  = e.loop;
		if ( e.fade   >= 0 ) out->fade_length  = e.fade;
		if ( e.repeat >= 0 ) out->repeat_count = e.repeat;
		copy_field_( out->song, e.name );
	}
	
	// play_length
	out->play_length = out->length;
	if ( out->play_length <= 0 )
	{
		out->play_length = out->intro_length + 2 * out->loop_length; // intro + 2 loops
		if ( out->play_length <= 0 )
			out->play_length = 150 * 1000; // 2.5 minutes
	}
	
	return blargg_ok;
}