/*
** Copyright (C) 2004 Bradey Honsinger
**  
** 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 "Util.h"
#include "TaskInfo.h"
#include "StatusReporter.h"

INITTRACE( _T( "StatusReporter" ) );

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// Global status reporter instance
CStatusReporter g_statusReporter;

CStatusReporter::CStatusReporter():
	m_bConnected( FALSE ),
	m_strHostname(),
	m_Socket(),
	m_strArtist(),
	m_strAlbum(),
	m_nTracks( 0 ),
	m_strTrack(),
	m_nTrack( 0 )
{
};
	
CStatusReporter::~CStatusReporter()
{
	if ( m_bConnected )
	{
		LTRACE( _T( "CStatusReporter: unexpected destruction!" ) );
		ASSERT( FALSE );
		Disconnect();
	}
};

void CStatusReporter::Connect()
{
	if ( CDEX_OK != GetHostname() )
	{
		::AfxMessageBox( _T( "Failed to get local host name!(CStatusReporter:Connect)" ) );
	};

	if ( CDEX_OK == OpenConnection() )
	{
 		m_bConnected = TRUE;
		SendMessageType( "Connect" );
		SendMessageValue( "Hostname", m_strHostname );
		SendMessageEnd();
	}
	else
	{
		::AfxMessageBox( _T( "Failed to connect to status server!(CStatusReporter:Connect)" ) );
	}
};
void CStatusReporter::Disconnect()
{
	SendMessageType( "Disconnect" );
	SendMessageEnd();

	CloseConnection();
	
	m_bConnected = FALSE;
};

void CStatusReporter::AlbumStart( const CTaskInfo& taskInfo )
{
	m_strArtist = taskInfo.GetArtist( );
	m_strAlbum = taskInfo.GetAlbum( );
	m_nTracks = taskInfo.GetTotalTracks( );

	CString strTracks;
	strTracks.Format( _T( "%d" ), m_nTracks );

	SendMessageType( "AlbumStart" );
	SendMessageValue( "Artist", m_strArtist );
	SendMessageValue( "Album", m_strAlbum );
	SendMessageValue( "Tracks", strTracks );
	SendMessageEnd();
};
void CStatusReporter::AlbumFinish( CDEX_ERR status, BOOL bCancelled )
{
	CString strCompletion = "OK";
	if ( bCancelled )
	{
		strCompletion = "Cancelled";
	} 
	else if ( CDEX_OK != status ) 
	{
		strCompletion = "Aborted";
	}
	
	SendMessageType( "AlbumFinish" );
	SendMessageValue( "Completion", strCompletion );
	SendMessageEnd();

	m_strArtist = "";
	m_strAlbum = "";
	m_nTracks = 0;
};

void CStatusReporter::TrackStart( const CTaskInfo& taskInfo )
{
	m_strTrack = taskInfo.GetTrackName( );
	m_nTrack = taskInfo.GetTrack( );
	CString strTrackNo;
	strTrackNo.Format( _T( "%d" ), m_nTrack );

	SendMessageType( "TrackStart" );
	SendMessageValue( "Name", m_strTrack );
	SendMessageValue( "Number", strTrackNo );
	SendMessageEnd();
};
void CStatusReporter::TrackFinish( CDEX_ERR status, BOOL bCancelled, int njitterErrors )
{
	CString strJitterErrors;
	strJitterErrors.Format( _T( "%d" ), njitterErrors );
	
	SendMessageType( "TrackFinish" );
	SendMessageValue( "JitterErrors", strJitterErrors );
	SendMessageEnd();

	m_strTrack = "";
	m_nTrack = 0;
};

void CStatusReporter::Stalled( STALLREASON reason )
{
	CString strReason;
	switch ( reason )
	{
		case STALLREASON_CDDB_NO_HITS:
			strReason += "cddb no hits";
			break;

		case STALLREASON_CDDB_MULTIPLE_HITS:
			strReason += "cddb multiple hits";
			break;

		case STALLREASON_FILE_EXISTS:
			strReason += "file exists";
			break;

		default:
			strReason += "unknown reason";
			ASSERT( FALSE );
			break;
	}

	SendMessageType( "Stalled" );
	SendMessageValue( "Reason", strReason );
	SendMessageEnd();
};


/*
	Private method implementations
*/

CDEX_ERR CStatusReporter::GetHostname()
{
	CDEX_ERR bReturn =	CDEX_OK;

	ENTRY_TRACE( _T( "CStatusReporter::GetHostname()" ) );

	TCHAR hostname[ MAX_COMPUTERNAME_LENGTH + 1 ];
	DWORD hostnameLength = sizeof( hostname ) / sizeof( TCHAR );

	if ( ::GetComputerName( hostname, &hostnameLength ) )
	{
		m_strHostname = hostname;
	}
	else
	{
		CString strError = GetLastErrorString();
		LTRACE( _T( "Failed to get local hostname: %s" ), strError );
							
		bReturn = CDEX_ERROR;
	}

	EXIT_TRACE( _T( "CStatusReporter::GetHostname(), return value %d" ), bReturn );

	return bReturn;
}

CDEX_ERR CStatusReporter::OpenConnection()
{
	CDEX_ERR bReturn =	CDEX_OK;
	
	ENTRY_TRACE( _T( "CStatusReporter::OpenConnection()" ) );

	// Init the WINSOCK library
	if ( !AfxSocketInit() )
	{
		LTRACE( _T( "Failed to initialize WinSock library" ) );
		bReturn = CDEX_ERROR;
	}
	else
	{
		// Clear all errors
		WSASetLastError( 0 );
		
		// Set host and port
		CString strServer = g_config.GetStatusServer();
		int nPort = g_config.GetStatusServerPort();
		
		// Create the CSocket
		if ( 0 == m_Socket.Create( ) )
		{
			LTRACE( _T( "Failed to create socket " ) );
			bReturn = CDEX_ERROR;
		}
		else
		{
			LTRACE( _T( "Open connection =\"%s\" Port=%d" ), strServer, nPort );

			// Try to connect
			if ( 0 == m_Socket.Connect( strServer, nPort )  )
			{
				CString strError = GetLastErrorString();
				LTRACE( _T( "Failed to connect to host: %s" ), strError );
									
				bReturn  = CDEX_ERROR;
			}
		}
	}	
	
	EXIT_TRACE( _T( "CStatusReporter::OpenConnection(), return value %d" ), bReturn );

	return bReturn;
}

void CStatusReporter::CloseConnection()
{
	ENTRY_TRACE( _T( "CStatusReporter::CloseConnection()" ) );

	// Close socket
	m_Socket.Close();
	
	EXIT_TRACE( _T( "CStatusReporter::CloseConnection()" ) );
}

CDEX_ERR CStatusReporter::SendMessageType( CString strMsgType  )
{
	return SendString( strMsgType + "\r\n" );
};

CDEX_ERR CStatusReporter::SendMessageValue( CString strName, CString strValue  )
{
	return SendString( strName + ": " + strValue + "\r\n" );
};

CDEX_ERR CStatusReporter::SendMessageEnd( )
{
	return SendString( "\r\n" );
};

CDEX_ERR CStatusReporter::SendString( CString strSend  )
{
	CDEX_ERR bReturn = CDEX_OK;

	USES_CONVERSION;

	LTRACE( _T( "Sending: %s" ), strSend );

	if ( SOCKET_ERROR == m_Socket.Send( W2A( strSend ), strSend.GetLength() ) )
	{
		CString strError = GetLastErrorString();
		LTRACE( _T( "Failed to send string: %s" ), strError );

		bReturn = CDEX_ERROR;
	}

	return bReturn;
};

/*
CDEX_ERR CStatusReporter::SendStatusMessage( CString strMessage )
{
	CDEX_ERR bReturn = CDEX_OK;

	if ( m_bConnected )
	{
		// host: artist - album - track (num/total): message
		CString status;
		status.Format( _T( "%s: %s - %s -%s (%d/%d): %s\r\n" ), 
				m_strHostname, 
				m_strArtist, m_strAlbum, m_strTrack, 
				m_nTrack, m_nTracks,
			strMessage 
			);

		bReturn = SendString( status );
	}
	else
	{
		LTRACE( _T( "Tried to send string when not connected: %s" ), strMessage );

		bReturn = CDEX_ERROR;
	}

	return bReturn;
};
*/
