#include "stdafx.h"
#include "MAC.h"
#include "APEInfoFormatDlg.h"
#include "APETag.h"
#include "WAVInputSource.h"
#include "MACDlg.h"
#include "APEInfo.h"

using namespace APE;

IMPLEMENT_DYNAMIC(CAPEInfoFormatDlg, CDialog)
CAPEInfoFormatDlg::CAPEInfoFormatDlg(CMACDlg * pMACDlg, CWnd * pParent)
    : CDialog(CAPEInfoFormatDlg::IDD, pParent)
{
    m_pMACDlg = pMACDlg;
}

CAPEInfoFormatDlg::~CAPEInfoFormatDlg()
{
}

void CAPEInfoFormatDlg::DoDataExchange(CDataExchange * pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_FORMAT, m_ctrlFormat);
}

BOOL CAPEInfoFormatDlg::OnInitDialog()
{
    // set the font to all the controls
    SetFont(theApp.GetFont());
    SendMessageToDescendants(WM_SETFONT, reinterpret_cast<WPARAM>(theApp.GetFont()->GetSafeHandle()), MAKELPARAM(false, 0), true);

    // parent
    return CDialog::OnInitDialog();
}

BEGIN_MESSAGE_MAP(CAPEInfoFormatDlg, CDialog)
END_MESSAGE_MAP()

void CAPEInfoFormatDlg::Layout()
{
    CRect rectWindow;
    GetClientRect(&rectWindow);
    const int nBorder = 0;
    m_ctrlFormat.SetWindowPos(APE_NULL, theApp.GetSize(nBorder), theApp.GetSize(nBorder), rectWindow.Width() - theApp.GetSize(nBorder * 2), rectWindow.Height() - theApp.GetSize(nBorder * 2), SWP_NOZORDER);
}

bool CAPEInfoFormatDlg::SetFiles(CStringArray & aryFiles)
{
    m_aryFiles.Copy(aryFiles);

    CString strSummary;

    if (m_aryFiles.GetSize() <= 100)
    {
        for (int z = 0; z < m_aryFiles.GetSize(); z++)
        {
            strSummary += m_aryFiles[z] + _T("\r\n");
            strSummary += GetSummary(m_aryFiles[z]) + _T("\r\n\r\n");
        }
    }
    else
    {
        strSummary = _T("Too many files selected. Please select less tracks.");
    }
    strSummary.TrimRight();

    m_ctrlFormat.SetWindowText(strSummary);

    return true;
}

CString CAPEInfoFormatDlg::GetSummary(const CString & strFilename)
{
    CString strSummary;

    CSmartPtr<IAPEDecompress> spAPEDecompress; int nFunctionRetVal = ERROR_UNDEFINED;
    spAPEDecompress.Assign(CreateIAPEDecompress(strFilename, &nFunctionRetVal, true, true, false));
    if ((spAPEDecompress != APE_NULL) && (nFunctionRetVal == ERROR_SUCCESS))
    {
        CString strLine;

        str_utfn cCompressionName[16]; APE_CLEAR(cCompressionName);
        GetAPECompressionLevelName(static_cast<int>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_COMPRESSION_LEVEL)), cCompressionName, 16, false);

        strLine.Format(_T("Monkey's Audio %.2f (%s)"),
            static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_FILE_VERSION)) / static_cast<double>(1000),
            static_cast<LPCTSTR>(cCompressionName));
        strSummary += strLine + _T("\r\n");

        // format
        strLine.Format(_T("Format: %.1f khz, %d bit, %d ch"),
            static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_SAMPLE_RATE)) / static_cast<double>(1000),
            static_cast<int>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_BITS_PER_SAMPLE)),
            static_cast<int>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_CHANNELS)));
        if (spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_FORMAT_FLAGS) & APE_FORMAT_FLAG_AIFF)
            strLine += _T(", AIFF");
        strSummary += strLine + _T("\r\n");

        // length
        strLine.Format(_T("Length: %s (%I64d blocks)"),
            FormatDuration(static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_DECOMPRESS_LENGTH_MS)) / 1000.0, false).GetString(),
            static_cast<int64>(spAPEDecompress->GetInfo(IAPEDecompress::APE_DECOMPRESS_TOTAL_BLOCKS)));
        strSummary += strLine + _T("\r\n");

        // the file size
        strLine.Format(_T("APE: %.2f MB"), static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_APE_TOTAL_BYTES)) / static_cast<double>(1048576));
        strSummary += strLine + _T("\r\n");

        strLine.Format(_T("WAV: %.2f MB"), static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_WAV_TOTAL_BYTES)) / static_cast<double>(1048576));
        strSummary += strLine + _T("\r\n");

        // the compression ratio
        strLine.Format(_T("Compression: %.2f%%"), static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_AVERAGE_BITRATE) * 100) / static_cast<double>(spAPEDecompress->GetInfo(IAPEDecompress::APE_INFO_DECOMPRESSED_BITRATE)));
        strSummary += strLine + _T("\r\n");

        IAPETag * pTag = GET_TAG(spAPEDecompress);
        OutputAPETag(pTag, strSummary);
    }
    else
    {
        APE::WAVEFORMATEX wfeInput; int64 nTotalBlocks = 0; int64 nHeaderBytes = 0; int64 nTerminatingBytes = 0; int32 nFlags = 0; int nErrorCode = 0;
        CSmartPtr<CInputSource> spInputSource(CInputSource::CreateInputSource(strFilename, &wfeInput, &nTotalBlocks, &nHeaderBytes, &nTerminatingBytes, &nFlags, APE_NULL, false, &nErrorCode));

        CString strFormat;
        if (nErrorCode == ERROR_SUCCESS)
        {
            // output details from the input source
            strFormat.Format(_T("%d samples per second\r\n%d channels\r\n%d bits per sample\r\n%I64d header bytes\r\n%I64d terminating bytes\r\n%I64d total blocks"), static_cast<int>(wfeInput.nSamplesPerSec), static_cast<int>(wfeInput.nChannels), static_cast<int>(wfeInput.wBitsPerSample), nHeaderBytes, nTerminatingBytes, nTotalBlocks);
            if (nFlags & APE_FORMAT_FLAG_BIG_ENDIAN)
                strFormat += _T("\r\nBig endian");
            if (nFlags & APE_FORMAT_FLAG_SIGNED_8_BIT)
                strFormat += _T("\r\nSigned 8-bit");
            if (spInputSource->GetFloat())
                strFormat += _T("\r\nFloating point");
        }
        else
        {
            // see if the file has an APE tag (WavPack files do)
            CSmartPtr<CAPETag> spAPETag(new CAPETag(strFilename, true));
            if (spAPETag->GetHasAPETag())
            {
                OutputAPETag(spAPETag, strSummary);
            }
            else
            {
                strFormat = _T("Format information not available for this file (unsupported by Monkey's Audio)");
            }
        }

        strSummary += strFormat;
    }

    // output metrics about processing like input size, output size, and processing time
    MAC_FILE * pFile = APE_NULL;
    int nFileIndex = m_pMACDlg->GetFileArray().GetFileIndex(strFilename);
    if (nFileIndex >= 0)
        pFile = m_pMACDlg->GetFileArray().ElementAt(nFileIndex);
    if (pFile != APE_NULL)
    {
        int64 nElapsedMS = 0;
        if (pFile->m_bStarted && pFile->m_bDone)
            nElapsedMS = static_cast<int64>(pFile->m_dwEndTickCount - pFile->m_dwStartTickCount);

        CString strNew;
        if (pFile->m_dInputFileBytes > 0)
        {
            strNew.Format(_T("\r\nInput file size (MB): %.2f"), static_cast<double>(pFile->m_dInputFileBytes) / (static_cast<double>(1024) * static_cast<double>(1024)));
            strSummary += strNew;
        }
        if (pFile->m_dOutputFileBytes > 0)
        {
            strNew.Format(_T("\r\nOutput file size (MB): %.2f"), static_cast<double>(pFile->m_dOutputFileBytes) / (static_cast<double>(1024) * static_cast<double>(1024)));
            strSummary += strNew;
        }
        if (nElapsedMS > 0)
        {
            strNew.Format(_T("\r\nProcessing time (seconds): %.2f"), static_cast<double>(nElapsedMS) / static_cast<double>(1000));
            strSummary += strNew;
        }
    }

    strSummary.TrimRight();
    return strSummary;
}

void CAPEInfoFormatDlg::OutputAPETag(APE::IAPETag * pTag, CString & strSummary)
{
    if (pTag != APE_NULL)
    {
        CString strTag = _T("None");
        if (pTag->GetHasAPETag())
        {
            strTag.Format(_T("APE Tag v%.2f"), static_cast<double>(pTag->GetAPETagVersion()) / static_cast<double>(1000));
            if (pTag->GetHasID3Tag())
                strTag += _T(", ID3v1.1");
        }
        else if (pTag->GetHasID3Tag())
        {
            strTag = _T("ID3v1.1");
        }
        CString strLine;
        strLine.Format(_T("Tag: %s (%d bytes)"),
            strTag.GetString(), pTag->GetTagBytes());
        strSummary += strLine + _T("\r\n");

        int nTagIndex = 0; CAPETagField * pTagField = APE_NULL;
        while ((pTagField = pTag->GetTagField(nTagIndex++)) != APE_NULL)
        {
            if (pTagField->GetFieldFlags() & TAG_FIELD_FLAG_DATA_TYPE_BINARY)
            {
                strLine.Format(_T("    %s: binary value (%d bytes)"),
                    pTagField->GetFieldName(),
                    pTagField->GetFieldValueSize());
                strSummary += strLine + _T("\r\n");
            }
            else
            {
                const int nMaximumSize = 1024;
                WCHAR cValue[nMaximumSize];
                APE_CLEAR(cValue);
                int nValueBytes = nMaximumSize - 1;
                pTag->GetFieldString(pTagField->GetFieldName(), &cValue[0], &nValueBytes);

                CString strValue;
                if (nValueBytes >= nMaximumSize)
                    strValue.Format(_T("<too large to display> (%d bytes)"), nValueBytes);
                else
                    strValue = cValue;

                strLine.Format(_T("    %s: %s"),
                    pTagField->GetFieldName(),
                    strValue.GetString());
                strSummary += strLine + _T("\r\n");
            }
        }

        strSummary.TrimRight(_T("\r\n"));
    }
}
