//
// editssn.cpp
//
// CEditSession2
//
#include "private.h"
#include "korimx.h"
#include "editssn.h"
#include "helpers.h"

#define SafeAddRef(x)        { if ((x)) { (x)->AddRef(); } }


/*   C  E D I T  S E S S I O N 2   */
/*------------------------------------------------------------------------------

    Constructor

------------------------------------------------------------------------------*/
CEditSession2::CEditSession2(ITfContext *pic, CKorIMX *ptip, ESSTRUCT *pess, PFNESCALLBACK pfnCallback)
{
    Assert(pic  != NULL);
    Assert(ptip != NULL);
    Assert(pess != NULL);

    m_cRef        = 1;
    m_pic         = pic;
    m_ptip        = ptip;
    m_ess         = *pess;
    m_pfnCallback = pfnCallback;

    // add reference count in the struct
    SafeAddRef(m_pic);
    SafeAddRef(m_ptip);
    SafeAddRef(m_ess.ptim);
    SafeAddRef(m_ess.pRange);
    SafeAddRef(m_ess.pEnumRange);
    SafeAddRef(m_ess.pCandList);
    SafeAddRef(m_ess.pCandStr);
}


/*   ~  C  E D I T  S E S S I O N 2   */
/*------------------------------------------------------------------------------

    Destructor

------------------------------------------------------------------------------*/
CEditSession2::~CEditSession2( void )
{
    SafeRelease(m_pic);
    SafeRelease(m_ptip);
    SafeRelease(m_ess.ptim);
    SafeRelease(m_ess.pRange);
    SafeRelease(m_ess.pEnumRange);
    SafeRelease(m_ess.pCandList);
    SafeRelease(m_ess.pCandStr);
}


/*   Q U E R Y  I N T E R F A C E   */
/*------------------------------------------------------------------------------

    Query interface of object
    (IUnknown method)

------------------------------------------------------------------------------*/
STDAPI CEditSession2::QueryInterface(REFIID riid, void **ppvObj)
{
    *ppvObj = NULL;

    if (IsEqualIID( riid, IID_IUnknown ) || IsEqualIID(riid, IID_ITfEditSession)) 
        *ppvObj = SAFECAST(this, ITfEditSession*);

    if (*ppvObj)
        {
        AddRef();
        return S_OK;
        }

    return E_NOINTERFACE;
}


/*   A D D  R E F   */
/*------------------------------------------------------------------------------

    Add reference count
    (IUnknown method)

------------------------------------------------------------------------------*/
STDAPI_(ULONG) CEditSession2::AddRef()
{
    return ++m_cRef;
}


/*   R E L E A S E   */
/*------------------------------------------------------------------------------

    Release object
    (IUnknown method)

------------------------------------------------------------------------------*/
STDAPI_(ULONG) CEditSession2::Release()
{
    long cr;

    cr = --m_cRef;
    Assert(cr >= 0);

    if (cr == 0)
        delete this;

    return cr;
}


/*   E D I T  S E S S I O N   */
/*------------------------------------------------------------------------------

    Callback function of edit session
    (ITfEditSession method)

------------------------------------------------------------------------------*/
STDAPI CEditSession2::DoEditSession(TfEditCookie ec)
{
    return m_pfnCallback(ec, this);
}


/*   I N V O K E   */
/*------------------------------------------------------------------------------



------------------------------------------------------------------------------*/
HRESULT CEditSession2::Invoke(DWORD dwFlag, HRESULT *phrSession)
{
    HRESULT hr;
    DWORD dwFlagES = 0;

    if ((m_pic == NULL) || (m_ptip == NULL))
        return E_FAIL;

    // read/readwrite flag

    switch (dwFlag & ES2_READWRITEMASK)
        {
    default:
    case ES2_READONLY: 
        dwFlagES |= TF_ES_READ;
        break;

    case ES2_READWRITE:
        dwFlagES |= TF_ES_READWRITE;
        break;
        }

    // sync/async flag

    switch (dwFlag & ES2_SYNCMASK)
        {
    default:
        Assert(fFalse);
    // fall through

    case ES2_ASYNC:
        dwFlagES |= TF_ES_ASYNC;
        break;

    case ES2_SYNC:
        dwFlagES |= TF_ES_SYNC;
        break;

    case ES2_SYNCASYNC:
        dwFlagES |= TF_ES_ASYNCDONTCARE;
        break;
        }

    // invoke

    m_fProcessed = FALSE;
    hr = m_pic->RequestEditSession(m_ptip->GetTID(), this, dwFlagES, phrSession);

    // try ASYNC session when SYNC session failed

    // NOTE: KOJIW:
    // How can we know if the edit session has been processed synchronously?

    // Satori#2409 - do not invoke callback twice
    //    if (!m_fProcessed && ((dwFlag & ES2_SYNCMASK) == ES2_SYNCASYNC)) { 
    //        hr = m_pic->EditSession( m_ptip->GetTID(), this, (dwFlagES & ~TF_ES_SYNC), phrSession );
    //    }

return hr;
}