// TTSDlg.cpp : インプリメンテーション ファイル
//

#include "stdafx.h"
#include "remotetest.h"
#include "TTSDlg.h"
#include "RemoteTestDlg.h"
#include "VAIBOTTS.h"
#include "TTSLexiconDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTTSDlg dialog


CTTSDlg::CTTSDlg(CVAIBO* vaibo, CWnd* pParent /*=NULL*/)
	: CDialog(CTTSDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTTSDlg)
	//}}AFX_DATA_INIT
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    m_vaibo = vaibo;
    m_pDlgLexicon = NULL;

    m_isSendFTP = false;
    m_isPlayWave = false;
}


void CTTSDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTTSDlg)
    DDX_Control(pDX, IDC_COMBO_ENGINE, m_ComboEngine);
    DDX_Control(pDX, IDC_COMBO_FORMAT, m_ComboFormat);
    DDX_Control(pDX, IDC_SLIDER_VOLUME, m_sliderVolume);
    DDX_Control(pDX, IDC_SLIDER_SPEED, m_sliderSpeed);
    DDX_Control(pDX, IDC_SLIDER_PITCH, m_sliderPitch);
    DDX_Control(pDX, IDC_SLIDER_ACCENT, m_sliderAccent);
    DDX_Control(pDX, IDC_EDIT_TEXT, m_editText);
    DDX_Control(pDX, IDC_EDIT_TEXT2, m_editText2);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CTTSDlg, CDialog)
	//{{AFX_MSG_MAP(CTTSDlg)
    ON_WM_DESTROY()
    ON_BN_CLICKED(IDC_BUTTON_SPEAK, OnButtonSpeak)
    ON_BN_CLICKED(IDC_BUTTON_SPEAK2, OnButtonSpeak2)
    ON_BN_CLICKED(IDC_BUTTON_SAVE, OnButtonSave)
    ON_BN_CLICKED(IDC_BUTTON_SAVE2, OnButtonSave2)
    ON_BN_CLICKED(IDC_BUTTON_AIBO_SPEAK, OnButtonAiboSpeak)
    ON_BN_CLICKED(IDC_BUTTON_AIBO_SPEAK2, OnButtonAiboSpeak2)
    ON_BN_CLICKED(IDC_BUTTON_LEXICON_SONYTTS, OnButtonLexiconSonyTTS)
    ON_BN_CLICKED(IDC_BUTTON_LEXICON_SAPI_J, OnButtonLexiconSAPI_J)
    ON_BN_CLICKED(IDC_BUTTON_LEXICON_SAPI_E, OnButtonLexiconSAPI_E)
    ON_WM_HSCROLL()
    ON_CBN_SELCHANGE(IDC_COMBO_ENGINE, OnSelchangeComboEngine)
    ON_CBN_SELCHANGE(IDC_COMBO_FORMAT, OnSelchangeComboFormat)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTTSDlg message handlers
BOOL    CTTSDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    m_sliderSpeed.SetRange( 0, VOICE_PARAM_MAX );
    m_sliderSpeed.SetPos( VOICE_PARAM_DEFAULT );
    m_sliderSpeed.SetTicFreq( 5 );                  // Interval
    m_sliderPitch.SetRange( 0, VOICE_PARAM_MAX );
    m_sliderPitch.SetPos( VOICE_PARAM_DEFAULT );
    m_sliderPitch.SetTicFreq( 5 );
    m_sliderAccent.SetRange( 0, VOICE_PARAM_MAX );
    m_sliderAccent.SetPos( VOICE_PARAM_DEFAULT );
    m_sliderAccent.SetTicFreq( 5 );
    m_sliderVolume.SetRange( 0, VOICE_PARAM_MAX );
    m_sliderVolume.SetPos( VOICE_PARAM_DEFAULT );
    m_sliderVolume.SetTicFreq( 5 );

    CString msg;
    msg.LoadString( IDS_TTS_MSG1_JAPANESE );
    m_editText.SetWindowText( msg );
    msg.LoadString( IDS_TTS_MSG2_ENGLISH  );
    m_editText2.SetWindowText( msg );

    m_pTTS = new ( CVAIBOTTS );
    if ( m_pTTS->Init() != E_VAIBOTTS_NOERROR ) {
        delete m_pTTS;
        m_pTTS = NULL;
    }

    // Get the TTS engine list
    if ( m_pTTS ) {

        // Get the number of engines
        int     nEngineNum;
        m_pTTS->GetTTSEngineNum( nEngineNum );
        for ( int i = 0; i < nEngineNum; i++ ) {
            char    strEngineName[ 256 ];
            m_pTTS->GetTTSEngineName( i, strEngineName );
            m_ComboEngine.InsertString( -1, strEngineName );
        }

        // Specify the current engine.
        m_ComboEngine.SetCurSel( 0 );
        m_pTTS->SetVoiceEngine( m_ComboEngine.GetCurSel() );
        if ( m_pTTS->GetTTSEngineKind( m_ComboEngine.GetCurSel() ) == E_VAIBOTTS_ENGINE_SAPI ) {
            m_pTTS->SetVoiceVolume( VOICE_PARAM_MAX );  // Because the volume of SAPI is low.
            m_sliderVolume.SetPos( VOICE_PARAM_MAX );
        }
        m_ComboFormat.SetCurSel( m_pTTS->GetOutputFormat() );
    }

    return TRUE;
}

void    CTTSDlg::OnDestroy()
{
    CDialog::OnDestroy();

    if ( m_pDlgLexicon != NULL ) {
        m_pDlgLexicon->DestroyWindow();
        delete m_pDlgLexicon;
        m_pDlgLexicon = NULL;
    }

    if ( m_pTTS ) {
        m_pTTS->End();
        delete m_pTTS;
    }
}


void    SplitString( CString& strSrc, CString& strDst, int nSplitStringLen )
{
    if ( strSrc.GetLength() < nSplitStringLen ) {
        strDst = strSrc;
        strSrc.Empty();
        return;
    }

    // Terminating characters of a string.
    #define     STREND_NUM  ( 6 )
    CString     strEnd[ STREND_NUM ];

    CString msg;
	msg.LoadString( IDS_TTS_STREND_1 );
    strEnd[0] = msg;
	msg.LoadString( IDS_TTS_STREND_2 );
    strEnd[1] = msg;
	msg.LoadString( IDS_TTS_STREND_3 );
    strEnd[2] = msg;
	msg.LoadString( IDS_TTS_STREND_4 );
    strEnd[3] = msg;
	msg.LoadString( IDS_TTS_STREND_5 );
    strEnd[4] = msg;
	msg.LoadString( IDS_TTS_STREND_6 );
    strEnd[5] = msg;

    int     nSplitIdx = -1;

    for ( int i = 0; i < STREND_NUM; i++ ) {

        int     nFindIdx = -1;
        int     nIdx = 0;
        while ( 1 ) {
            nIdx = strSrc.Find( strEnd[ i ], nIdx + 1 );
            // Terminating character wasn't found.
            if ( nIdx < 0 ) {
                break;
            }
            // Exceeded maximum range.
            if ( nIdx >= nSplitStringLen ) {
                break;
            }
            nFindIdx = nIdx;
        }

        // Terminating character was found.
        if ( nFindIdx >= 0 ) {
            if ( nFindIdx > nSplitIdx ) {
                nSplitIdx = nFindIdx;   // The largest one
            }
        }
    }

    // Terminating character was found.
    if ( nSplitIdx >= 0 ) {
        //  double-byte character?
        if ( IsDBCSLeadByte( strSrc.GetAt( nSplitIdx ) ) ) {
            // Include the following character.
            strDst = strSrc.Left( nSplitIdx + 2 );
            strDst += '\0';
            strSrc = strSrc.Mid( nSplitIdx + 2 );
        }
        else {
            // Do not included the following character.
            strDst = strSrc.Left( nSplitIdx + 1 );
            strDst += '\0';
            strSrc = strSrc.Mid( nSplitIdx + 1 );
        }
    }
    // Terminating character wasn't found.
    else {
        // Cut string in the middle (unavoidable).
        //  double-byte character?
        if ( IsDBCSLeadByte( strSrc.GetAt( nSplitStringLen - 1 ) ) ) {
            // Include the following character.
            strDst = strSrc.Left( nSplitStringLen + 1 );
            strDst += '\0';
            strSrc = strSrc.Mid( nSplitStringLen + 1 );
        }
        else {
            // Do not included the following character.
            strDst = strSrc.Left( nSplitStringLen );
            strDst += '\0';
            strSrc = strSrc.Mid( nSplitStringLen );
        }
    }
}

void    CTTSDlg::OnButtonSpeak()
{
    if ( !m_pTTS ) {
        return;
    }

    CString     strEdit;
    m_editText.GetWindowText( strEdit );
    if ( strEdit.IsEmpty() ) {
        return;
    }

    CString     strReadText = strEdit;
    for ( int i = 0; ; i++ ) {

        CString     strText;
        SplitString( strReadText, strText, 60 );


        char    strTempPath[ 1024 ];
        ::GetTempPath( 1024, strTempPath );

        CString     strFile;
        strFile.Format( "%s_VAIBOTTS%02d.wav", strTempPath, i );

        CFile   fileTest;
        if ( fileTest.Open( strFile, CFile::modeRead | CFile::shareDenyNone ) ) {
            fileTest.Close();
            CFile::Remove( strFile );
        }

        // Create wave file
        if ( m_pTTS->MakeWaveFile( strText, strFile ) ) {
            AfxMessageBox( "Wave file creation error\n" );
            return;
        }

        // Play
        while ( !PlaySound( strFile, NULL, SND_FILENAME | SND_ASYNC | SND_NOSTOP ) ) {
            Sleep( 100 );   // Wait for the previous sound production.
        }

        // Short wait.
        Sleep( 10 );

        // String to say is now empty
        if ( strReadText.IsEmpty() ) {
            break;
        }
    }
}

void    CTTSDlg::OnButtonSpeak2()
{
    if ( !m_pTTS ) {
        return;
    }

    CString     strEdit;
    m_editText2.GetWindowText( strEdit );
    if ( strEdit.IsEmpty() ) {
        return;
    }

    m_pTTS->Speak( NULL, strEdit );
}

void    CTTSDlg::OnButtonSave()
{
    if ( !m_pTTS ) {
        return;
    }

    CString     strEdit;
    m_editText.GetWindowText( strEdit );
    if ( strEdit.IsEmpty() ) {
        return;
    }

    CFileDialog dlg( FALSE, "wav", "TTS.wav", 0, NULL, this );
    if ( dlg.DoModal() != IDOK ) {
        return;
    }

    CString     strFile;
    strFile = dlg.GetPathName();

    // Save
    if ( m_pTTS->MakeWaveFile( strEdit, strFile ) ) {
        AfxMessageBox( "Wave file creation error\n" );
    }
}

void    CTTSDlg::OnButtonSave2()
{
    if ( !m_pTTS ) {
        return;
    }

    CString     strEdit;
    m_editText2.GetWindowText( strEdit );
    if ( strEdit.IsEmpty() ) {
        return;
    }

    CFileDialog dlg( FALSE, "wav", "TTS.wav", 0, NULL, this );
    if ( dlg.DoModal() != IDOK ) {
        return;
    }

    CString     strFile;
    strFile = dlg.GetPathName();

    // Save
    if ( m_pTTS->MakeWaveFile( strEdit, strFile ) ) {
        AfxMessageBox( "Wave file creation error\n" );
    }
}

void    CTTSDlg::AiboSpeak( CString strEdit )
{
    // TTS OK?
    if ( m_pTTS == NULL ) {
        AfxMessageBox( "TTS Engine not initialized\n" );
        return;
    }

    // VAIBO OK ?
    if ( m_vaibo == NULL ) {
        AfxMessageBox( "Not Connected to AIBO\n" );
        return;
    }
    if ( !m_vaibo->IsConnect() ) {
        AfxMessageBox( "Not Connected to AIBO\n" );
        return;
    }
    if ( ( ( CRemoteTestDlg* )AfxGetMainWnd() )->IsAiboControl() == false ) {
        AfxMessageBox( "Can't remotely control AIBO\n" );
        return;
    }


    // NetAudio Preparation
    int nState = m_vaibo->GetStateNetAudio();
    switch (nState) {
    case AUDIOTP_STATE_SERVICE:
    case AUDIOTP_STATE_PAUSE:
        break;
    case AUDIOTP_STATE_PLAY:
        AfxMessageBox( "The NetAudio Service is busy\n" );
        return;
    default:
        AfxMessageBox( "Please Start the NetAudio Service\n" );
        return;
    }


	CString     strText = strEdit;
	
	// Get TEMP directory
	char    strTempPath[ 1024 ];
	::GetTempPath( 1024, strTempPath );
	
	// TEMP filename
	CString     strFile;
	strFile.Format( "%s_VAIBOTTS.wav", strTempPath);
	
	// Confirm the existence of the file.
	CFile   fileTest;
	if ( fileTest.Open( strFile, CFile::modeRead | CFile::shareDenyNone ) ) {
		// It exists.
		fileTest.Close();
		// Delete
		CFile::Remove( strFile );
	}
	
	// Preparation of the wave file
	if ( m_pTTS->MakeWaveFile( strText, strFile ) ) {
		AfxMessageBox( "Wave file creation error\n" );
		return;
	}
	
	// Check the size of the transfer
	CFile*  pFile = new CFile( strFile, CFile::modeRead | CFile::shareDenyNone );
	if ( pFile != NULL ) {
		int     nSize;
		bool    isError = false;
		if ( ( nSize = pFile->GetLength() ) >= 1 * 1000 * 1000 * 3/*1MB*/ ) {
			isError = true;
			AfxMessageBox( "Wave file is too large\n" );
		}
		pFile->Close();
		delete pFile;
		
		if ( isError ) {
			return;
		}
	}
	else {
		AfxMessageBox( "Wave file open error\n" );
		return;
	}
	
	// AudioSendWAV
	int     nRet;
	if ( ( nRet = m_vaibo->AudioSendWAVFile( strFile ) ) != VAIBO_NOERROR ) {
		CString strDebug;
		strDebug.Format( "Wave file transfer error %d\n", nRet );
		AfxMessageBox( strDebug );
	}

}

void    CTTSDlg::OnButtonAiboSpeak()
{
    if ( !m_pTTS ) {
        return;
    }

    CString     strEdit;
    m_editText.GetWindowText( strEdit );
    if ( strEdit.IsEmpty() ) {
        return;
    }

    AiboSpeak( strEdit );
}

void    CTTSDlg::OnButtonAiboSpeak2()
{
    if ( !m_pTTS ) {
        return;
    }

    CString     strEdit;
    m_editText2.GetWindowText( strEdit );
    if ( strEdit.IsEmpty() ) {
        return;
    }

    AiboSpeak( strEdit );
}

void    CTTSDlg::DisplayLexicon( int eLexicon )
{
    if ( m_pDlgLexicon == NULL ) {
        m_pDlgLexicon = new CTTSLexiconDlg( m_pTTS );
        m_pDlgLexicon->Create( IDD_DIALOG_LEXICON );
    }
    m_pDlgLexicon->SetLexicon( eLexicon );
    m_pDlgLexicon->ShowWindow( SW_SHOW );
}

void    CTTSDlg::OnButtonLexiconSonyTTS()
{
    DisplayLexicon( E_VAIBOTTS_LEXICON_SONYTTS_J );
}

void    CTTSDlg::OnButtonLexiconSAPI_J()
{
    DisplayLexicon( E_VAIBOTTS_LEXICON_SAPI_J );
}

void    CTTSDlg::OnButtonLexiconSAPI_E()
{
    DisplayLexicon( E_VAIBOTTS_LEXICON_SAPI_E );
}


void    CTTSDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    if ( ( CSliderCtrl* )pScrollBar == &m_sliderSpeed ) {
        unsigned int    unPos = m_sliderSpeed.GetPos();
        if ( m_pTTS ) {
            m_pTTS->SetVoiceSpeed( unPos );
        }
    }
    else if ( ( CSliderCtrl* )pScrollBar == &m_sliderPitch ) {
        unsigned int    unPos = m_sliderPitch.GetPos();
        if ( m_pTTS ) {
            m_pTTS->SetVoicePitch( unPos );
        }
    }
    else if ( ( CSliderCtrl* )pScrollBar == &m_sliderAccent ) {
        unsigned int    unPos = m_sliderAccent.GetPos();
        if ( m_pTTS ) {
            m_pTTS->SetVoiceAccent( unPos );
        }
    }
    else if ( ( CSliderCtrl* )pScrollBar == &m_sliderVolume ) {
        unsigned int    unPos = m_sliderVolume.GetPos();
        if ( m_pTTS ) {
            m_pTTS->SetVoiceVolume( unPos );
        }
    }


    CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

void    CTTSDlg::OnSelchangeComboEngine()
{
    if ( m_pTTS ) {

        m_pTTS->SetVoiceEngine( m_ComboEngine.GetCurSel() );

        if ( m_pTTS->GetTTSEngineKind( m_ComboEngine.GetCurSel() ) == E_VAIBOTTS_ENGINE_SAPI ) {
            m_pTTS->SetVoiceVolume( VOICE_PARAM_MAX );  // Because the volume of SAPI is low.
            m_sliderVolume.SetPos( VOICE_PARAM_MAX );
        }
    }
}

void    CTTSDlg::OnSelchangeComboFormat()
{
    if ( m_pTTS ) {
		if ( m_ComboFormat.GetCurSel() == 0 ) {
			m_pTTS->SetOutputFormat( E_TTS_WAVE_FORMAT_16K_16BIT );
		} 
		else {
			m_pTTS->SetOutputFormat( E_TTS_WAVE_FORMAT_8K_8BIT );
		}
	}
}


// Wait for the end of the produced voice.
void    CTTSDlg::NotifyPlayWave( int status )
{
    if ( status == DONE_PLAY_WAV ) {

        m_isPlayWave = false;

        if ( m_isSendFTP ) {
            m_vaibo->SendCmd( APPCMD_PLAY_WAV, false );
            m_isPlayWave = true;
            m_isSendFTP = false;
        }

        // There is no transfer.
        if ( !m_isSendFTP ) {
            ( CButton* )( GetDlgItem( IDC_BUTTON_AIBO_SPEAK ) )->EnableWindow( true );
            ( CButton* )( GetDlgItem( IDC_BUTTON_AIBO_SPEAK2 ) )->EnableWindow( true );
        }
    }
}
