/*
** Copyright (C) 1999 - 2002 Albert L. Faber
**  
** 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.
*/

#include "StdAfx.h"
#include <id3.h>
#include <id3/tag.h>
#include <id3/misc_support.h>
#include "ID3Tag.h"
#include "config.h"
#include "resource.h"


INITTRACE( _T( "ID3Tag" ) );

// CONSRUCTOR
CID3Tag::CID3Tag( CString& strFileName )
{
	ENTRY_TRACE( _T( "CID3Tag::CID3Tag() with file name %s" ), strFileName );
	// Initialize the variables
	Init();

	// Assign file name
	m_strFileName=strFileName;

	EXIT_TRACE( _T( "CID3Tag::CID3Tag() with file name %s" ), strFileName );
}

// Init CID3Tag variables
void CID3Tag::Init()
{
	ENTRY_TRACE( _T( "CID3Tag::Init()" ) );

	// Initialize all strings and variables
    m_strTitle		= _T( "" );
    m_strArtist		= _T( "" );
    m_strAlbum		= _T( "" );
    m_strYear		= _T( "" );
    m_strComment	= _T( "" );
    m_strGenre		= _T( "" );
	m_nTrackNumber  = 0;
	m_nTagSize		= 0;
	m_nTotalTracks  = 0;

	m_bIsV2			= false;
	m_bIsV1			= false;

	EXIT_TRACE( _T( "CID3Tag::Init()" ) );
}


BOOL CID3Tag::OpenFile()
{
	ENTRY_TRACE( _T( "CID3Tag::OpenFile()" ) );

	// open file as binary for read write
	m_pFile = _tfopen( m_strFileName, _T( "r+b" ) );

	// Oeps, something didn't go well
	if ( NULL == m_pFile )
	{
		LTRACE( _T( "CID3Tag::OpenFile() Could not open file %s" ), m_strFileName );
		LTRACE( _T( "CID3Tag::OpenFile() Las error is %d" ), GetLastError() );
		return FALSE;
	}
	EXIT_TRACE( _T( "CID3Tag::OpenFile()" ) );

	return TRUE;
}

BOOL CID3Tag::OpenFile( CString strFileName )
{
	m_strFileName=strFileName;

	BOOL bReturn = OpenFile();

	CloseFile();

	return bReturn;
}

void CID3Tag::CloseFile()
{
	if (m_pFile)
		fclose(m_pFile);

	m_pFile = NULL;
}



// LoadTag method
BOOL CID3Tag::LoadTag()
{
	CString strLang;

	m_nTagSize = 0;

	try
	{
		ID3_Tag myTag;
		int ulFlag = ID3TT_ID3;
		char* pTmp = NULL;
		char* pTmp1= NULL;
		size_t nTmp = 0;


		LTRACE( _T( "CID3Tag::LoadTag() Tagging file %s" ), m_strFileName );

		m_nTagSize = myTag.Link( m_strFileName );

		pTmp = ID3_GetArtist( &myTag );
		if ( pTmp )	SetArtist( pTmp );
		delete [] pTmp;

		pTmp = ID3_GetAlbum( &myTag );
		if ( pTmp )	SetAlbum( pTmp );
		delete [] pTmp;

		pTmp = ID3_GetTitle( &myTag );
		if ( pTmp )	SetTitle( pTmp );
		delete [] pTmp;

		pTmp = ID3_GetYear( &myTag );
		if ( pTmp )	SetYear( pTmp );
		delete [] pTmp;

		pTmp = ID3_GetComment( &myTag );
		if ( pTmp )	SetComment( pTmp );

		delete [] pTmp;
		delete [] pTmp1;

		nTmp = ID3_GetGenreNum( &myTag );

		if ( nTmp != 0xFF )
		{
			int nIdx = -1;

			// Get genre number
			if ( -1 != ( nIdx = g_GenreTable.SearchID3V1ID( nTmp ) ) )
			{
				SetGenre( g_GenreTable.GetGenre( nIdx ) );
			}
			else
			{
				SetGenre( g_language.GetString( IDS_UNKNOWN ) );
			}
		}
		else
		{
			SetGenre( g_language.GetString( IDS_UNKNOWN )  );
		}

		pTmp = ID3_GetGenre( &myTag );
		if ( pTmp )	SetGenre( pTmp );
		delete [] pTmp;

		
  		pTmp = ID3_GetEncodedBy( &myTag );
 		if ( pTmp )	SetEncodedBy( pTmp );
 		delete [] pTmp;

  		pTmp = ID3_GetMCDI( &myTag );
 		if ( pTmp )	SetMCDI( pTmp );
 		delete [] pTmp;

		m_bIsV2 = myTag.HasV2Tag();
		m_bIsV1 = myTag.HasV1Tag();

		SetTrackNumber( ID3_GetTrackNum( &myTag  ) );
	}

	catch(ID3_Error err)
	{
		strLang = g_language.GetString( IDS_CANTLOADID3TAG );
		AfxMessageBox( strLang );
		LTRACE( _T( "CID3Tag::SaveTag_v2() Exception Occured! while writing tag into file %s error desciption %s" ),
					m_strFileName, 
					err.GetErrorDesc() );
		return FALSE;
	}
	return TRUE;
}


BOOL CID3Tag::SaveTag_v2()
{
	CString strLang;

	USES_CONVERSION;

	try
	{
		ID3_Tag myTag;

		LTRACE( _T( "CID3Tag::SaveTag_v2() Tagging file %s" ), m_strFileName );

		myTag.Link( m_strFileName );

		myTag.SetPadding( true );

      const CString& strArtist = GetArtist();
      if ( AsciiOnly( strArtist ) )
        ID3_AddArtist( &myTag, W2A(strArtist), true );
      else
        ID3_AddArtist( &myTag, strArtist, true );
      const CString& strAlbum = GetAlbum();
      if ( AsciiOnly( strAlbum ) )
        ID3_AddAlbum( &myTag, W2A(strAlbum), true );
      else
        ID3_AddAlbum( &myTag, strAlbum, true );
      const CString& strTitle = GetTitle();
      if ( AsciiOnly( strTitle ) )
        ID3_AddTitle( &myTag, W2A(strTitle), true );
      else
        ID3_AddTitle( &myTag, strTitle, true );
		ID3_AddYear( &myTag, W2A( GetYear() ), true );
		ID3_AddComment( &myTag, W2A( GetComment() ), "", true );
 		ID3_AddEncodedBy( &myTag, W2A( GetEncodedBy() ), true );
 		ID3_AddMCDI( &myTag, W2A( GetMCDI() ), true );
// 		ID3_AddMCDI( &myTag, (const char*)GetRawToc(), true );

		ID3_MyAddTrack(	&myTag,
						GetTrackNumber(),
						GetTotalTracks(),
						true,
						g_config.GetID3V2TrackNumber() );

		if ( IsV1Tag() ) 
		{
			BYTE nGenreIdx = g_GenreTable.SearchGenre( m_strGenre );
			BYTE nGenre    = g_GenreTable.GetID3V1ID( nGenreIdx );

			// set genre number for V1 tag
			ID3_AddGenre( &myTag, nGenre, true );

			// Update V1 tag
			myTag.Update( ID3TT_ID3V1 );
		}

		if ( IsV2Tag() ) 
		{
			// set genre string for V2 tag
			ID3_AddGenre( &myTag, W2A( m_strGenre ), true );

			if ( GetLengthInMs().GetLength() > 0 )
			{
				ID3_AddSongLen( &myTag, W2A( GetLengthInMs() ), true );
			}

			// Update V2 tag
			myTag.Update( ID3TT_ID3V2 );
		}

		// strip V2 tag if it is not requested
		if ( !IsV2Tag() && myTag.HasV2Tag() ) 
		{
			myTag.Strip( ID3TT_ID3V2 );
		}
	}

	catch( ID3_Error err )
	{
		strLang = g_language.GetString( IDS_CANTSAVEID3TAG );
		AfxMessageBox( strLang );
		LTRACE( _T( "CID3Tag::SaveTag_v2() Exception Occured! while writing tag into file %s error description %s " ),
					m_strFileName ,
					err.GetErrorDesc() );
		return FALSE;
	}
	return TRUE;
}



FILE* CID3Tag::SaveInitialV2Tag( const CString& strFileName, DWORD dwPadSize )
{
	FILE* pFile = NULL;

	pFile = _tfopen( strFileName, _T( "wb+" ) );

	if ( NULL == pFile )
		return NULL;

	if ( dwPadSize > 10 )
	{
		DWORD	dwTagSize = dwPadSize - 10;
		char	strHeader[10] = {'\0',};
		int		i = 0;

		// Tag identification
		strHeader[0] = 'I';
		strHeader[1] = 'D';
		strHeader[2] = '3';
	
		// Version number
		strHeader[3] = 3;
		strHeader[4] = 0;

		// Clear Flags byte
		strHeader[5] = 0;

		// Write tag length
		strHeader[6] = ((dwTagSize >> 21) & 0x7F );
		strHeader[7] = ((dwTagSize >> 14) & 0x7F );
		strHeader[8] = ((dwTagSize >>  7) & 0x7F );
		strHeader[9] = ((dwTagSize      ) & 0x7F );

		// Write header  
		fwrite( strHeader, sizeof( strHeader ), 1, pFile );

		// Write padding data
		for ( i=0;i< dwTagSize; i++ )
		{
			strHeader[0] = 0;
			fwrite( strHeader, 1, 1, pFile );
		}
	}
	return pFile;
}


BOOL CID3Tag::SaveTag( )
{
	return SaveTag_v2();
}


BOOL CID3Tag::CopyTags( const CString& strSrc,
						const CString& strDst )
{
	try
	{
        ID3_Tag myTag;
		int ulFlag = 0;

        myTag.Clear();

        myTag.Link( strSrc, ID3TT_ALL);
      
		if ( myTag.HasV1Tag()  ) 
			ulFlag|= ID3TT_ID3V1;
		if ( myTag.HasV2Tag()  ) 
			ulFlag|= ID3TT_ID3V2;

		if ( myTag.HasV1Tag() || myTag.HasV2Tag() )
		{
			myTag.Link( strDst, ID3TT_NONE);
	        myTag.Update( ulFlag );
		}
	}
	catch(ID3_Error err)
	{
		CString strTmp;
		strTmp.Format(	_T( " %s %d %d %s" ),
						err.GetErrorFile(),
						err.GetErrorLine(),
						err.GetErrorType(),
						err.GetErrorDesc() );

		AfxMessageBox( strTmp );
		LTRACE( _T( "CID3Tag::CopyTags () Exception Occured! while copying tag from %s to %s" ), strSrc, strDst );
		return FALSE;
	}
	return TRUE;
}

