//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd 2013  (all rights reserved)
//               MELBOURNE, VICTORIA, AUSTRALIA, 3130
//
//  Provided no fee is charged (either by the distributer or user)
//  permission to use, copy, modify, and distribute this software and
//  its documentation for any purpose and without fee is hereby granted,
//  provided that the above copyright notice appear in all copies and
//  that both that copyright notice and this permission notice appear
//  in supporting documentation.
//
//  No waranty or suitablity for purpose is implied.
//
//
//  IMAPIFolder interface wrapper class implementation
//  NOTES: Manages all subordinate IMAPIFolder resources
//      

#include "stdafx.h"
#include "P2Pevent.h"
#include "MAPIEx.h"
#include "MAPISession.h"
#include "MAPI_Ext.h"

enum { PROP_MESSAGE_FLAGS
     , PROP_ENTRYID
     , MESSAGE_COLS };

/////////////////////////////////////////////////////////////
// CMAPIFolder

CMAPIFolder::CMAPIFolder()
{
    //m_pIMAPIFolder = nullptr;
	  RenderThisSafe ( );
}

CMAPIFolder::CMAPIFolder ( CMAPISession *pCMAPISession, LPMAPIFOLDER pFolder, LPCTSTR lpszName)
{
    RenderThisSafe ( );

    Attach ( pCMAPISession, pFolder, lpszName );
}

CMAPIFolder::~CMAPIFolder()
{
	Close();
}

void
CMAPIFolder::RenderThisSafe ( )
{
    m_pCMAPISession = nullptr;
    m_pHierarchy    = nullptr;
    m_pContents     = nullptr;
    m_nMaxRowsSize  = DEFAULT_FOLDER_BUFFER_SIZE;
    m_pSRowSet      = NULL;
    ClearRowSet ( );
}

///////////////////////////////////////////////////////////
//  Internal Operations

BOOL CMAPIFolder::QueryRows()
{
    ClearRowSet();
    if(m_pContents)
    {
      if(m_pContents->QueryRows(m_nMaxRowsSize, 0, &m_pSRowSet)==S_OK)
      {
			  return TRUE;
		  }
		  m_pSRowSet=NULL;
	  }
	  return FALSE;
}

SRow*
CMAPIFolder::GetNextRow ( )
{
	if ( m_pSRowSet==NULL ||
       m_nRowsIndex>=m_pSRowSet->cRows)
	{
		if ( !QueryRows() ) return NULL;
	}
	if(m_pSRowSet->cRows==0)
	{
		ClearRowSet();
		return NULL;
	}
	return &m_pSRowSet->aRow[m_nRowsIndex++];
}

///////////////////////////////////////////////////////////
//  External operations

void
CMAPIFolder::Close()
{
    ClearRowSet();
    m_pCMAPISession = nullptr;
    RELEASE(m_pHierarchy);
    RELEASE(m_pContents);
    CMAPIProp::Close();
}

void
CMAPIFolder::SetBufferSize ( int nSize )
{
    ASSERT(nSize>0);
    m_nMaxRowsSize = max ( 1, nSize );
}

void
CMAPIFolder::ClearRowSet()
{
    if ( m_pSRowSet )
    {
      FreeProws ( m_pSRowSet );
      MAPIFreeBuffer ( m_pSRowSet );
      m_pSRowSet=NULL;
    }
    m_nRowsIndex = 0;
}

void
CMAPIFolder::Attach ( CMAPISession *pCMAPISession, IMAPIFolder *pIMAPIFolder, LPCTSTR lpszName)
{
    Close();
    m_pCMAPISession = pCMAPISession;
    m_pIMAPIProp    = pIMAPIFolder;
    m_pIMAPIProp->AddRef ();
    m_strName       = lpszName;
    LPSPropValue pProp;
    if ( GetProperty(PR_ENTRYID,pProp) == S_OK) 
    {
      SetSBinEntryID(&pProp->Value.bin);
      MAPIFreeBuffer(pProp);
    } 
    else 
    {
      ASSERT(0);
      SetSBinEntryID ( nullptr );
    }
}

///////////////////////////////////////////////////////////
//  Folder and Message management

//
//  Queries this folder for next sub-folder in sequence
//
//  Returns:     CMAPIFolder*
//               NOTES: Client responsible for life cycle
//                 0.. End of list
//                 ?.. Next CMAPIFolder pointer
CMAPIFolder*
CMAPIFolder::Query4SubFolder ( LPCTSTR lpszSubFolder )
{
    if ( !GetHierarchy() )
      EVERR_MAPI(0,"Null hierarchy" )->Throw();

    CString      strFolder;
    CMAPIFolder *pSubFolder=nullptr;
    while (  pSubFolder == nullptr )
    {
      pSubFolder = Query4NextSubFolder();
      if ( pSubFolder == nullptr )
        break; 
      if ( strFolder.CompareNoCase(lpszSubFolder) ) 
        pSubFolder = pSubFolder -> Query4SubFolder(lpszSubFolder);
    }
    return pSubFolder;
} 

CMAPIFolder*
CMAPIFolder::Query4NextSubFolder ( )
{
    ASSERT(m_pHierarchy);
    HRESULT    hr;

	  DWORD      dwObjType;
	  LPSRowSet   pRows = nullptr;

    LPMAPIFOLDER pISubFolder = nullptr;
	  hr = m_pHierarchy -> QueryRows ( 1, 0, &pRows );
    if ( hr != S_OK )
      THROW_MAPI ( hr, "IMAPITable::QueryRows() failed" );
    P2PsafeMAPIbuffer SRowSetSB = pRows;       // Lock in resource recovery
		if ( pRows->cRows <= 0 )
      return nullptr;
		CString strSubFolder = MAPI_GetValidString ( pRows->aRow[0].lpProps[0] );
    hr = GetIMAPIFolder() -> OpenEntry ( pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin.cb
                                       , (LPENTRYID)pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin.lpb
                                       , NULL, MAPI_MODIFY, &dwObjType
                                       , (LPUNKNOWN*)&pISubFolder );
    if ( hr != S_OK )
      THROW_MAPI ( hr, "IMAPITable::OpenEntry() failed" );
    return new CMAPIFolder ( m_pCMAPISession, pISubFolder, strSubFolder );
}

CMAPImessage*
CMAPIFolder::CreateMessage ( int nPriority, BOOL bSaveToSentFolder )
{
    CMAPImessageSP spMAPImessage = new CMAPImessage();
    if ( !spMAPImessage -> Create ( m_pCMAPISession, bSaveToSentFolder, this ) )
      spMAPImessage = 0;
    if ( !spMAPImessage.IsEmpty() )
      spMAPImessage -> SetImportance ( nPriority );
    return spMAPImessage.Dereference();
} 

///////////////////////////////////////////////////////////////////////////////
//  Property exposure

IMAPIFolder*
CMAPIFolder::GetIMAPIFolder ( )
{
    return (IMAPIFolder *)m_pIMAPIProp;
}

IMAPITable*
CMAPIFolder::GetHierarchy()
{
    RELEASE(m_pHierarchy);
	  HRESULT hr = GetIMAPIFolder() -> GetHierarchyTable ( 0, &m_pHierarchy );
    if ( hr != S_OK )
      EVERR_MAPI(hr,"IMAPIFolder::GetHierarchyTable() failed" )->Throw();

    const int nProperties=2;
    SizedSPropTagArray(nProperties, Columns)={nProperties,{PR_DISPLAY_NAME, PR_ENTRYID}};
    hr = m_pHierarchy -> SetColumns ( (LPSPropTagArray)&Columns, 0 ); 
    if ( hr != S_OK )
    {
      RELEASE(m_pHierarchy);
      EVERR_MAPI(hr,"IMAPITable::SetColumns() failed" )->Throw();
    }
    return m_pHierarchy;
}

LPCTSTR
CMAPIFolder::GetName()
{
    return m_strName;
}

int
CMAPIFolder::GetRowCount()
{
    ULONG ulCount = 0;
    if ( m_pContents == nullptr )
    {
      ASSERT(0);
      EVERR_MAPI ( 0, "Null contents pointer" );
      return -1;
    }

    HRESULT hr = m_pContents -> GetRowCount ( 0, &ulCount );
    if ( hr != S_OK )
      THROW_MAPI ( hr, "IMAPITable::GetRowCount() failed" );
    return ulCount;
}

IMAPITable*
CMAPIFolder::GetContents ( )
{
    HRESULT hr;
    RELEASE(m_pContents);
    hr = GetIMAPIFolder() -> GetContentsTable ( T_MAPI_UNICODE, &m_pContents);
    if ( hr != S_OK )
    {
      MAPI_HRESULT ( hr, "IMAPIFolder::GetContentsTable() failed" );
      return nullptr;
    }

    const int nProperties = MESSAGE_COLS;
    SizedSPropTagArray ( nProperties, Columns)  ={nProperties,{PR_MESSAGE_FLAGS, PR_ENTRYID }};
    hr = m_pContents -> SetColumns ( (LPSPropTagArray)&Columns, 0 );
    if ( hr != S_OK )
    {
	    RELEASE(m_pContents);
      MAPI_HRESULT ( hr, "IMAPITable::SetColumns() failed" );
	    return nullptr;
    }
    return m_pContents;
}
