//		COPYRIGHT 2002, B2C2, Inc.
//
//		TimeShiftRecFile.cpp
//		File for Time Shift buffer or digital video recorder
//
/*
	History:
		07/2002 - ALF - Created
*/


#include <windows.h>
#include <streams.h>

#include "RecFile.h"

///////////////////////////////////////////////////////////////////////////////
//
// CTimeShiftRecFile Constructor/Destructor
//

/*-----------------------------------------------------------------------------------------------*/

CTimeShiftRecFile::CTimeShiftRecFile()
{
    m_hFile = INVALID_HANDLE_VALUE;

	m_pFileName = NULL;

	m_eFileType = TSRF_UNKNOWN;
	m_dwFileAccess = 0;
	m_dwFileOpenFlags = 0;
	m_dwShareMode = 0;
}

/*-----------------------------------------------------------------------------------------------*/

// virtual 
CTimeShiftRecFile::~CTimeShiftRecFile()
{
	CloseFile();

	if (m_pFileName)
	{
		delete [] m_pFileName;
		m_pFileName = NULL;
	}
}

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::SetFileName(LPCOLESTR pszFileName)
{
    // Is this a valid filename supplied
    CheckPointer(pszFileName, E_POINTER);

    if(wcslen(pszFileName) > MAX_PATH)
	{
        return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
	}

	// Delete previous file name
	if (m_pFileName)
	{
		delete [] m_pFileName;
		m_pFileName = NULL;
	}

    // Take a copy of the filename
    m_pFileName = new WCHAR[1+lstrlenW(pszFileName)];
    if (m_pFileName == NULL)
	{
        return E_OUTOFMEMORY;
	}

    lstrcpynW(m_pFileName,pszFileName,lstrlenW(pszFileName)+1);

	// Create the file then close it

    HRESULT hr = OpenFile();
    CloseFile();

    return hr;
}

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::SetFileType(E_TSR_FILE_TYPE eType)
{
    // Only changable if file is not open
	if (m_hFile != INVALID_HANDLE_VALUE)
	{
		return E_UNEXPECTED;
	}

	switch (eType)
	{
	case TSRF_RECORD : // Record file
		m_dwFileAccess = GENERIC_WRITE;
		m_dwFileOpenFlags = CREATE_ALWAYS;                // overwrite existing
		m_dwShareMode = NULL;
		break;
	case TSRF_PLAY : // Play file
		m_dwFileAccess = GENERIC_READ;
		m_dwFileOpenFlags = OPEN_EXISTING;				// existing file only 
		m_dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
		break;
	case TSRF_TIME_SHIFT : // Time shift file
		m_dwFileAccess = GENERIC_READ | GENERIC_WRITE;
		m_dwFileOpenFlags = CREATE_ALWAYS;                // overwrite existing
		m_dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
		break;
	default : 
		return E_INVALIDARG;
	};

	m_eFileType = eType;

    return S_OK;
}

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::OpenFile()
{
//	CAutoLock l(&m_Lock);

	TCHAR *pFileName = NULL;

    // Is the file already opened
    if (m_hFile != INVALID_HANDLE_VALUE) 
	{
        return S_OK;
    }

    // Has a filename been set yet
    if (m_pFileName == NULL) 
	{
        return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
    }

    // Convert the UNICODE filename if necessary
#if defined(WIN32) && !defined(UNICODE)
    char convert[MAX_PATH];

    if (!WideCharToMultiByte(CP_ACP,0,m_pFileName,-1,convert,MAX_PATH,0,0))
	{
        return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
	}
    pFileName = convert;
#else
    pFileName = m_pFileName;
#endif


    // Try to open the file
	m_hFile = CreateFile((LPCTSTR) pFileName,   // The filename
                         m_dwFileAccess,        // File access
                         (DWORD) m_dwShareMode, // Share access
                         NULL,                  // Security
                         m_dwFileOpenFlags,		// Open flags
                         (DWORD) 0,             // More flags
                         NULL);                 // Template

    if (m_hFile == INVALID_HANDLE_VALUE) 
	{
        DWORD dwErr = GetLastError();
        return HRESULT_FROM_WIN32(dwErr);
    }

    return S_OK;
} 

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::CloseFile()
{
//	CAutoLock l(&m_Lock);

    if (m_hFile == INVALID_HANDLE_VALUE) 
	{
        return S_OK;
    }

    CloseHandle(m_hFile);

    m_hFile = INVALID_HANDLE_VALUE;
    return S_OK;
} 

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::Write(PVOID pData, DWORD dwLength)
{
//	CAutoLock l(&m_Lock);

	if (m_hFile == INVALID_HANDLE_VALUE)
	{
		return E_FAIL;
	}

    DWORD dwWritten;

    if (!WriteFile(m_hFile, (PVOID)pData, dwLength, &dwWritten, NULL)) 
	{
        DWORD dwErr = GetLastError();
        return HRESULT_FROM_WIN32(dwErr);
    }

    return S_OK;
}

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::Read(PVOID pData, DWORD dwLength, DWORD* pdwRead)
{
//	CAutoLock l(&m_Lock);

	if (m_hFile == INVALID_HANDLE_VALUE)
	{
		return E_FAIL;
	}

    if (!ReadFile(m_hFile, (PVOID)pData, dwLength, pdwRead, NULL)) 
	{
        DWORD dwErr = GetLastError();
        return HRESULT_FROM_WIN32(dwErr);
    }

    return S_OK;
} 

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::Delete( void )
{
//	CAutoLock l(&m_Lock);

	TCHAR *pFileName = NULL;

	// Convert the UNICODE filename if necessary
#if defined(WIN32) && !defined(UNICODE)
    char convert[MAX_PATH];

    if (!WideCharToMultiByte(CP_ACP,0,m_pFileName,-1,convert,MAX_PATH,0,0))
	{
        return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
	}
    pFileName = convert;
#else
    pFileName = m_pFileName;
#endif

    if (!DeleteFile(pFileName))
	{
        DWORD dwErr = GetLastError();
        return HRESULT_FROM_WIN32(dwErr);
    }

    return S_OK;
}

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::GetFileSize( __int64* pi64FileSize )
{
	if (m_hFile == INVALID_HANDLE_VALUE)
	{
		return E_FAIL;
	}

	DWORD dwFileSizeLow;
	DWORD dwFileSizeHigh;

	dwFileSizeLow = ::GetFileSize(m_hFile, &dwFileSizeHigh);

	if (dwFileSizeLow == INVALID_FILE_SIZE)
	{
		return E_FAIL;
	}

	*pi64FileSize = dwFileSizeLow + ((__int64)dwFileSizeHigh << 32);
		
    return S_OK;
}

/*-----------------------------------------------------------------------------------------------*/

HRESULT CTimeShiftRecFile::Reposition(__int64 i64DistanceToMove, DWORD dwMoveMethod, __int64* pi64FilePosition)
{
//	CAutoLock l(&m_Lock);

	if (m_hFile == INVALID_HANDLE_VALUE)
	{
		return E_FAIL;
	}

	LONG lDistanceToMove = (long) (i64DistanceToMove & 0xFFFFFFFF);
	LONG lDistanceToMoveHigh = (long) (i64DistanceToMove >> 32);

	DWORD dwFilePosition;

	dwFilePosition = SetFilePointer (m_hFile, lDistanceToMove, &lDistanceToMoveHigh, dwMoveMethod) ;

	if (pi64FilePosition)
	{
		*pi64FilePosition = dwFilePosition + ((__int64)lDistanceToMoveHigh << 32);
	}

    return S_OK;
} 

/*-----------------------------------------------------------------------------------------------*/
