// SrtReader.cpp: implementation of the CSrtReader class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "srtcut.h"
#include "SrtReader.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSrtReader::CSrtReader()
{

}

CSrtReader::~CSrtReader()
{
    for( int nTitle = 0; nTitle < m_vpTitles.size(); nTitle++ )
    {
        struct _tagTitle* pTitle = m_vpTitles[nTitle];

        delete pTitle;
    }

}

BOOL CSrtReader::ReadFromFile(LPCTSTR lpszFileName)
{
    if( lpszFileName == NULL )
        return FALSE;
    if( _tcslen(lpszFileName) == 0 )
        return FALSE;

    CStdioFile file;

    TRY
    {
        if( !file.Open(lpszFileName, CFile::modeRead | CFile::typeText) )
            return FALSE;

        _tagTitle* pTitle = NULL;
        CString strLine;
        int iLineIndex = 0;

        while( file.ReadString(strLine) )
        {
            strLine.TrimLeft();
            strLine.TrimRight();
            if( !strLine.IsEmpty() )
            {
                if( iLineIndex % 3 == 0 )
                {
                    if( pTitle != NULL )
                        delete pTitle;    // for avoid memory leak
                    pTitle = new _tagTitle;
                    if( !_TryToReadIndex(strLine, pTitle->iIndex) )
                    {
                        // TODO:
                    }
                }
                else if( iLineIndex % 3 == 1 )
                {
                    if( !_TryToReadTimestamp(strLine, pTitle->tsStart, pTitle->tsEnd) )
                    {
                        // TODO:
                    }
                }
                else
                {
                    if( !_TryToReadText(strLine, pTitle->szText) )
                    {
                        // TODO:
                    }
                    m_vpTitles.push_back(pTitle);
                    pTitle = NULL;    // for avoid memory leak
                }
                iLineIndex++;
            }
        }
        if( pTitle != NULL )
            delete pTitle;    // for avoid memory leak
    }
    CATCH(CFileException, e)
    {
    }
    END_CATCH
    return TRUE;

}

// cut once, return current separators amount
int CSrtReader::Cut(short sHour, short sMinute, short sSecond, short sMillsecond)
{
    struct _tagTimestamp tsSeparator;

    tsSeparator.sHour = sHour;
    tsSeparator.sMinute = sMinute;
    tsSeparator.sSecond = sSecond;
    tsSeparator.sMillsecond = sMillsecond;

    if( !m_vtsSeparators.empty() )
    {
        struct _tagTimestamp& tsReferenceSeparator = m_vtsSeparators[m_vtsSeparators.size() - 1];

        if( _LessThan(tsSeparator, tsReferenceSeparator) )    // the separator timestamps are in orders
            return -1;
    }

    m_vtsSeparators.push_back(tsSeparator);
    return m_vtsSeparators.size();

}

BOOL CSrtReader::SaveToFiles(LPCTSTR lpszFileNameFormat) const
{
    if( lpszFileNameFormat == NULL )
        return FALSE;
    if( _tcslen(lpszFileNameFormat) == 0 )
        return FALSE;
    if( m_vtsSeparators.empty() )
        return FALSE;

    TRY
    {
        CString strTest;

        strTest.Format(lpszFileNameFormat, 0);
    }
    CATCH(CException, e)
    {
        return FALSE;
    }
    END_CATCH

    struct _tagTimestamp tsOffset;
    CString strFileName;
    int nTitle = 0;
    int nOffset = 0;

    tsOffset.sHour = 0;
    tsOffset.sMinute = 0;
    tsOffset.sSecond = 0;
    tsOffset.sMillsecond = 0;
    for( int nSeparator = 0; nSeparator < m_vtsSeparators.size(); nSeparator++ )
    {
        const struct _tagTimestamp& tsSeparator = m_vtsSeparators[nSeparator];

        for( ; nTitle < m_vpTitles.size(); nTitle++ )
        {
            struct _tagTitle* pTitle = m_vpTitles[nTitle];

            if( _LessThan(tsSeparator, pTitle->tsStart) )
                break;
        }
        strFileName.Format(lpszFileNameFormat, nSeparator);
        _SaveToFile(nOffset, tsOffset, nTitle, strFileName);
        nOffset = nTitle;
        tsOffset.sHour = tsSeparator.sHour;
        tsOffset.sMinute = tsSeparator.sMinute;
        tsOffset.sSecond = tsSeparator.sSecond;
        tsOffset.sMillsecond = tsSeparator.sMillsecond;
    }
    strFileName.Format(lpszFileNameFormat, nSeparator);
    _SaveToFile(nOffset, tsOffset, m_vpTitles.size(), strFileName);
    return TRUE;

}

// Format: 0 to n, a number only
//  1
inline BOOL CSrtReader::_TryToReadIndex(LPCTSTR lpszLine, int &iIndex) const
{
    iIndex = _ttoi(lpszLine);
    return TRUE;

}

// Format:
//  00:00:51,984 --> 00:00:53,076
inline BOOL CSrtReader::_TryToReadTimestamp(LPCTSTR lpszLine, _tagTimestamp &tsStart, _tagTimestamp &tsEnd) const
{
    _stscanf(lpszLine, _T("%d:%d:%d,%d --> %d:%d:%d,%d"), &tsStart.sHour, &tsStart.sMinute,
        &tsStart.sSecond, &tsStart.sMillsecond, &tsEnd.sHour, &tsEnd.sMinute,
        &tsEnd.sSecond, &tsEnd.sMillsecond);
    return TRUE;

}

// Format: a string
//  == Title made: vcforge.net ==
inline BOOL CSrtReader::_TryToReadText(LPCTSTR lpszLine, LPTSTR lpszText) const
{
    _tcsncpy(lpszText, lpszLine, 1024);
    return TRUE;

}

// compare two _tagTimestamp, return TRUE if ts1 < ts2
inline BOOL CSrtReader::_LessThan(const struct _tagTimestamp &ts1, const struct _tagTimestamp &ts2) const
{
    if( ts2.sHour > ts1.sHour )
        return TRUE;
    else if( ts2.sHour == ts1.sHour )
    {
        if( ts2.sMinute > ts1.sMinute )
            return TRUE;
        else if( ts2.sMinute == ts1.sMinute )
        {
            if( ts2.sSecond > ts1.sSecond )
                return TRUE;
            else if( ts2.sSecond == ts1.sSecond )
            {
                if( ts2.sMillsecond > ts1.sMillsecond )
                    return TRUE;
            }
        }
    }
    return FALSE;

}

inline BOOL CSrtReader::_SaveToFile(int iStartTitle, const _tagTimestamp &tsOffset, int iStopTitle, LPCTSTR lpszFileName) const
{
    CStdioFile file;

    TRY
    {
        if( !file.Open(lpszFileName, CFile::modeCreate | CFile::modeWrite | CFile::typeText) )
            return FALSE;

        for( int nTitle = iStartTitle; nTitle < iStopTitle; nTitle++ )
        {
            const struct _tagTitle* pTitle = m_vpTitles[nTitle];
            struct _tagTimestamp tsStart;
            struct _tagTimestamp tsEnd;
            CString strLine;

            _WriteIndex(pTitle->iIndex - iStartTitle, strLine);
            file.WriteString(strLine);
            file.WriteString(_T("\r\n"));
            _TimeSpan(tsStart, pTitle->tsStart, tsOffset);
            _TimeSpan(tsEnd, pTitle->tsEnd, tsOffset);
            _WriteTimestamp(tsStart, tsEnd, strLine);
            file.WriteString(strLine);
            file.WriteString(_T("\r\n"));
            _WriteText(pTitle->szText, strLine);
            file.WriteString(strLine);
            file.WriteString(_T("\r\n"));
            file.WriteString(_T("\r\n"));
        }
        file.Close();
    }
    CATCH(CFileException, e)
    {
    }
    END_CATCH
    return TRUE;

}

inline void CSrtReader::_WriteIndex(int iIndex, CString &strLine) const
{
    strLine.Format(_T("%d"), iIndex);

}

inline void CSrtReader::_WriteTimestamp(const _tagTimestamp &tsStart, const _tagTimestamp &tsEnd, CString &strLine) const
{
    strLine.Format(_T("%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d"), tsStart.sHour, tsStart.sMinute,
        tsStart.sSecond, tsStart.sMillsecond, tsEnd.sHour, tsEnd.sMinute, tsEnd.sSecond, tsEnd.sMillsecond);

}

inline void CSrtReader::_WriteText(LPCTSTR lpszText, CString &strLine) const
{
    strLine = lpszText;

}

inline BOOL CSrtReader::_TimeSpan(_tagTimestamp &ts, const _tagTimestamp &ts1, const _tagTimestamp &ts2) const
{
    __int64 i641 = ts1.sHour * 60 * 60 * 1000 + ts1.sMinute * 60 * 1000 + ts1.sSecond * 1000 + ts1.sMillsecond;
    __int64 i642 = ts2.sHour * 60 * 60 * 1000 + ts2.sMinute * 60 * 1000 + ts2.sSecond * 1000 + ts2.sMillsecond;
    __int64 i64 = i641 - i642;

    ts.sHour = i64 / (60 * 60 * 1000);
    i64 -= ts.sHour * 60 * 60 * 1000;
    ts.sMinute = i64 / (60 * 1000);
    i64 -= ts.sMinute * 60 * 1000;
    ts.sSecond = i64 / 1000;
    i64 -= ts.sSecond * 1000;
    ts.sMillsecond = i64;
    return TRUE;

}