//
// CvsCoworker.cpp : Implementation of CvsCoworker
//
//  This module is mostly boilerplate: dispatching from a single instance
//  handle-based interface to method calls on object based context.
//  In other words, you are unlikely to want to change this file.
//

#include "stdafx.h"
#include "CVS_Coworker_i.h"
#include "CvsTrace.h"
#include "CvsCoworkerErrors.h"
#include "CvsCoworker.h"
#include "CvsProject.h"
#include "CvsFilenames.h"

//
//  Common bit of code,
//

#ifdef NDEBUG
#define CATCH_EXCEPTIONS(FN) \
catch (...) {} return S_FALSE;
#else
#define CATCH_EXCEPTIONS(FN) \
catch (const char* e) { qTRACE(("*EXCEPTION from " #FN "() : %s",e)); } \
catch (...) { qTRACE(("*EXCEPTION from " #FN "()")); } return S_FALSE;
#endif

//
//  Copy a string into a fixed length buffer.
//

static inline void CopyString(char* s1,const char* s2,int n)
{
    ASSERT(s1);
    ASSERT(s2);
    ASSERT(0<n);
    strncpy(s1,s2,n);
    s1[n-1] = 0;
}

static inline void CopyString(unsigned char* s1,const char* s2,int n)
{
    CopyString((char*)s1,s2,n);
}

/////////////////////////////////////////////////////////////////////////////
// CvsCoworker

STDMETHODIMP CvsCoworker::InterfaceSupportsErrorInfo(REFIID riid)
{
    qTRACE_FN(CvsCoworker::InterfaceSupportsErrorInfo);
    static const IID* arr[] = {
        &IID_ICvsCoworker,
        0
    };
    for (int i=0; arr[i]; ++i) {
        if (::ATL::InlineIsEqualGUID(*arr[i],riid)) {	//Jerzy[6/13/2001] - fix according to Q243298 at MSDN 
            return S_OK;
        }
    }
    return S_FALSE;
}

STDMETHODIMP CvsCoworker::GetLastError(
    int handle,
    int* piError
    )
{
    ASSERT(piError);
    *piError = 0;
    CvsProject* pProject = CvsProject::FindProject(handle);
    if (!pProject) {
        return CVS_E_FAILED_PROJECT_INVALID;
    }
    *piError = pProject->getLastError();
    return S_OK;
}

STDMETHODIMP CvsCoworker::GetErrorMessage(
    int handle,
    int iError,
    int cbErrorBuffer,
    unsigned char *sErrorBuffer
    )
{
    LOG_API_FN(GetErrorMessage);
    LOG_API_N(iError);
    ASSERT(sErrorBuffer);
    ASSERT(0 < cbErrorBuffer);
    if (sErrorBuffer) {
        *sErrorBuffer = 0;
    }
    CvsProject* pProject = CvsProject::FindProject(handle);
    if (!pProject) {
        return CVS_E_FAILED_PROJECT_INVALID;
    }
    CvsString sError;
    if (!pProject->getErrorMessage(iError,sError)) {
        return S_FALSE;
    }
    CopyString(sErrorBuffer,sError,cbErrorBuffer);
    LOG_API_S(sErrorBuffer);
    return S_OK;
}

STDMETHODIMP CvsCoworker::GetProject(
    int *pHandle,
    const unsigned char *sUsername,
    int cbProjectNameBuffer,
    unsigned char *sProjectNameBuffer,
    int cbProjectHomeBuffer,
    unsigned char *sProjectHomeBuffer,
    BOOL bAllowPathChange,
    BOOL bAllowNewProject,
    BOOL *pbNewProject
    )
{
    LOG_API_FN(GetProject);
    LOG_API_S(sUsername);
    LOG_API_S(sProjectNameBuffer);
    LOG_API_S(sProjectHomeBuffer);
    LOG_API_N(bAllowPathChange);
    LOG_API_N(bAllowNewProject);
    ASSERT(pHandle);
    ASSERT(sUsername);
    ASSERT(0 < cbProjectNameBuffer);
    ASSERT(sProjectNameBuffer);
    ASSERT(0 < cbProjectHomeBuffer);
    ASSERT(sProjectHomeBuffer);
    ASSERT(pbNewProject);
    try {
        *pHandle = 0;
        *pbNewProject = false;
        CvsProject* pProject = new CvsProject;
        *pHandle = pProject->getProjectHandle();
        bool bOK = pProject->getProject(
            (char*)sUsername,
            (char*)sProjectNameBuffer,
            (char*)sProjectHomeBuffer,
            bAllowPathChange,
            bAllowNewProject,
            *pbNewProject
            );
        CopyString(sProjectNameBuffer,pProject->getProjectName(),cbProjectNameBuffer);
        CopyString(sProjectHomeBuffer,pProject->getProjectHome(),cbProjectHomeBuffer);
        LOG_API_N(bOK);
        LOG_API_S(sProjectNameBuffer);
        LOG_API_S(sProjectHomeBuffer);
        if (!bOK) {
            return CVS_E_FAILED_OPEN_PROJECT;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(GetProject);
}

STDMETHODIMP CvsCoworker::OpenProject(
    int* pHandle,
    const unsigned char *sUsername,
    const unsigned char *sProjectName,
    const unsigned char *sProjectHome
    )
{
    LOG_API_FN(OpenProject);
    LOG_API_S(sUsername);
    LOG_API_S(sProjectName);
    LOG_API_S(sProjectHome);
    ASSERT(pHandle);
    ASSERT(sUsername);
    ASSERT(sProjectName);
    ASSERT(sProjectHome);
    try {
        *pHandle = 0;
        CvsProject* pProject = new CvsProject;
        *pHandle = pProject->getProjectHandle();
        bool bOK = pProject->openProject(
            (const char*)sUsername,
            (const char*)sProjectName,
            (const char*)sProjectHome
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED_OPEN_PROJECT;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(OpenProject);
}

// Standard preamble for mapping a handle to an class instance.
#define PREAMBLE(H) \
CvsProject* pProject = CvsProject::FindProject(handle); \
ASSERT(pProject); \
if (!pProject) { return CVS_E_FAILED_PROJECT_INVALID; }

STDMETHODIMP CvsCoworker::CloseProject(
    int handle
    )
{
    LOG_API_FN(CloseProject);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->closeProject();
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED_CLOSE_PROJECT;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(CloseProject);
}

STDMETHODIMP CvsCoworker::UpdateFiles(
    int handle,
    const unsigned char *sFilenames,
    BOOL bDirectories,
    BOOL bRecurse
    )
{
    LOG_API_FN(UpdateFiles);
    LOG_API_S(sFilenames);
    LOG_API_N(bDirectories);
    LOG_API_N(bRecurse);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->updateFiles(
            CvsFilenames(sFilenames),
            bDirectories,
            bRecurse
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(UpdateFiles);
}

STDMETHODIMP CvsCoworker::CheckoutFiles(
    int handle,
    const unsigned char *sFilenames
    )
{
    LOG_API_FN(CheckoutFiles);
    LOG_API_S(sFilenames);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->checkoutFiles(
            CvsFilenames(sFilenames)
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(CheckoutFiles);
}

STDMETHODIMP CvsCoworker::CheckinFiles(
    int handle,
    const unsigned char *sFilenames,
    BOOL bKeepCheckedOut
    )
{
    LOG_API_FN(CheckinFiles);
    LOG_API_S(sFilenames);
    LOG_API_N(bKeepCheckedOut);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->checkinFiles(
            CvsFilenames(sFilenames),
            bKeepCheckedOut
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(CheckinFiles);
}

STDMETHODIMP CvsCoworker::UncheckoutFiles(
    int handle,
    const unsigned char *sFilenames
    )
{
    LOG_API_FN(UncheckoutFiles);
    LOG_API_S(sFilenames);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->uncheckoutFiles(
            CvsFilenames(sFilenames)
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(UncheckoutFiles);
}

STDMETHODIMP CvsCoworker::AddFiles(
    int handle,
    const unsigned char* sOptionsAndFilenames,
    const unsigned char* sComment
    )
{
    LOG_API_FN(AddFiles);
    LOG_API_S(sOptionsAndFilenames);
    LOG_API_S(sComment);
    ASSERT(sOptionsAndFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->addFiles(
            CvsFilenames(sOptionsAndFilenames),
            (const char*)sComment
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(AddFiles);
}

STDMETHODIMP CvsCoworker::RemoveFiles(
    int handle,
    const unsigned char *sFilenames
    )
{
    LOG_API_FN(RemoveFiles);
    LOG_API_S(sFilenames);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->removeFiles(
            CvsFilenames(sFilenames)
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(RemoveFiles);
}

STDMETHODIMP CvsCoworker::RenameFile(
    int handle,
    const unsigned char *sOldFilename,
    const unsigned char *sNewFilename
    )
{
    LOG_API_FN(RenameFiles);
    LOG_API_S(sOldFilename);
    LOG_API_S(sNewFilename);
    ASSERT(sOldFilename);
    ASSERT(sNewFilename);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->renameFile(
            (const char*)sOldFilename,
            (const char*)sNewFilename
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(RenameFile);
}

STDMETHODIMP CvsCoworker::DiffFile(
    int handle,
    const unsigned char *sFilename,
    BOOL bIgnoreCase,
    BOOL bIgnoreWhitespace
    )
{
    LOG_API_FN(DiffFiles);
    LOG_API_S(sFilename);
    LOG_API_N(bIgnoreCase);
    LOG_API_N(bIgnoreWhitespace);
    ASSERT(sFilename);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->diffFile(
            (const char*)sFilename,
            bIgnoreCase,
            bIgnoreWhitespace
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(DiffFile);
}

STDMETHODIMP CvsCoworker::ShowFileHistory(
    int handle,
    const unsigned char *sFilenames
    )
{
    LOG_API_FN(ShowFileHistory);
    LOG_API_S(sFilenames);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->showFileHistory(
            CvsFilenames(sFilenames)
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(ShowFileHistory);
}

STDMETHODIMP CvsCoworker::ShowFileProperties(
    int handle,
    const unsigned char *sFilename
    )
{
    LOG_API_FN(ShowFileProperties);
    LOG_API_S(sFilename);
    ASSERT(sFilename);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->showFileProperties(
            (const char*)sFilename
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(ShowFileProperties);
}

STDMETHODIMP CvsCoworker::ShowUserInterface(
    int handle,
    const unsigned char *sFilenames
    )
{
    LOG_API_FN(ShowUserInterface);
    LOG_API_S(sFilenames);
    ASSERT(sFilenames);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->showUserInterface(
            CvsFilenames(sFilenames)
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(ShowUserInterface);
}

STDMETHODIMP CvsCoworker::HasAdvancedOptionsForCommand(
    int handle,
    CvsCommand command,
    BOOL *pbAdvancedOptions
    )
{
    LOG_API_FN(HasAdvancedOptionsForCommand);
    LOG_API_N(command);
    ASSERT(pbAdvancedOptions);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->hasAdvancedOptionsForCommand(
            command,
            *pbAdvancedOptions
            );
        LOG_API_N(bOK);
        LOG_API_N(*pbAdvancedOptions);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(HasAdvancedOptionsForCommand);
}

STDMETHODIMP CvsCoworker::ShowAdvancedOptionsForCommand(
    int handle,
    CvsCommand command
    )
{
    LOG_API_FN(ShowAdvancedOptionsForCommand);
    LOG_API_N(command);
    PREAMBLE(handle);
    try {
        bool bOK = pProject->showAdvancedOptionsForCommand(
            command
            );
        LOG_API_N(bOK);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(ShowAdvancedOptionsForCommand);
}

STDMETHODIMP CvsCoworker::GetFileChanges(
    int handle,
    int cbFilenameBuffer,
    unsigned char *sFilenameBuffer
    )
{
    LOG_API_FN(GetFileChanges);
    ASSERT(0<cbFilenameBuffer);
    ASSERT(sFilenameBuffer);
    PREAMBLE(handle);
    CvsString sFilename;
    try {
        bool bOK = pProject->getFileChanges(
            sFilename
            );
        CopyString(sFilenameBuffer,sFilename,cbFilenameBuffer);
        LOG_API_N(bOK);
        LOG_API_S(sFilenameBuffer);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(GetFileChanges);
}

STDMETHODIMP CvsCoworker::GetFilesToAdd(
    int handle,
    int cbFilenamesBuffer,
    unsigned char *sFilenamesBuffer
    )
{
    LOG_API_FN(GetFilesToAdd);
    ASSERT(0<cbFilenamesBuffer);
    ASSERT(sFilenamesBuffer);
    PREAMBLE(handle);
    CvsString sFilenames;
    try {
        bool bOK = pProject->getFilesToAdd(
            sFilenames
            );
        CopyString(sFilenamesBuffer,sFilenames,cbFilenamesBuffer);
        LOG_API_N(bOK);
        LOG_API_S(sFilenamesBuffer);
        if (!bOK) {
            return CVS_E_FAILED;
        }
        return S_OK;
    }
    CATCH_EXCEPTIONS(GetFilesToAdd);
}
