// File: ichnldat.h
//

#ifndef _ICHNLDAT_H_
#define _ICHNLDAT_H_

typedef enum _scState {               /* State of data channel */
	SCS_UNINITIALIZED = 0,           // Nothing is valid
	SCS_CREATESAP,                   // Creating m_gcc_pIAppSap
	SCS_ATTACH,                      // Attaching
	SCS_ENROLL,                      // Enrolling in a conference
	SCS_JOIN_PRIVATE,                // Join the private channel
	SCS_REGRETRIEVE,                 // Checking the registry
	SCS_REGRETRIEVE_NEW,             // new channel must be created
	SCS_REGRETRIEVE_EXISTS,          // channel already exists
	SCS_JOIN_NEW,                    // Creating a new MCS channel
	SCS_REGCHANNEL,                  // Registering the MCS channel
	SCS_JOIN_OLD,                    // Joining an existing channel
	SCS_REGPRIVATE,                  // Register the private channel
	SCS_CONNECTED,                   // m_mcs_channel_id is valid
	SCS_TERMINATING,                 // shutting down
	SCS_JOIN_STATIC_CHANNEL          // Join a static channel
} SCSTATE;


// An application key consists of an MS Object ID + guid identifier + guid + node id
#define cbKeyApp (4 + 1 + sizeof(GUID) + sizeof(DWORD))
#define MAX_CHECKID_COUNT 80  // Maximum number of times to ask for channel Id

typedef struct _tagUcid {
	DWORD     dwUserId;           // Node ID
	ChannelID channelId;          // Private channel ID
	UserID    sender_id_public;
	UserID    sender_id_private;
} UCID;

// CNmMemberId
class CNmMemberId
{
private:
	UINT      m_cCheckId;          // non-zero means checking the ID

	ChannelID m_channelId;         // Private channel ID
	UserID    m_sender_id_public;
	UserID    m_sender_id_private;

	CNmMember *m_pMember;

public:
	CNmMemberId(CNmMember *pMember, UCID *pucid);

	ChannelID GetChannelId(void)  {return m_channelId;}
	ChannelID SenderId(void)      {return m_sender_id_public;}

	VOID  UpdateRosterInfo(UCID * pucid);
	BOOL  FSenderId(UserID id)    {return ((id == m_sender_id_public) || (id == m_sender_id_private));}

	UINT  GetCheckIdCount(void)   {return m_cCheckId;}
	VOID  SetCheckIdCount(UINT c) {m_cCheckId = c;}

	CNmMember *GetMember(void)    {return m_pMember;}
};




// INmChannelData
//
class CNmChannelData :  public INmChannelData,
                        public RefCount,
                    	public CConnectionPointContainer
{
private:
	GUID	m_guid;                  // SetGuid/GetGuid
	BOOL    m_fClosed;               // TRUE when CloseConnection is called
	BOOL    m_fActive;               // TRUE when data channel is active
	DWORD   m_dwUserIdLocal;         // Data channel needs to know local user id
	CConfObject * m_pConference;	 //	Helpful to get member list

	ULONG       m_cMember;           // Number of members in this channel
	COBLIST   * m_pListMemberId;	 // Member id list
	COBLIST	  * m_pListMember;       // Member list
	PGCCEnrollRequest	m_pGCCER;     // Enroll request from enrolling app

public:
	CNmChannelData(CConfObject * pConference, REFGUID rguid);
	~CNmChannelData();


	// Internal functions
	GUID * PGuid(void)      {return &m_guid;}
	VOID UpdatePeer(CNmMember * pMember, UCID *pucid, BOOL fAdd);
	VOID UpdateRoster(UCID * rgPeer, int cPeer, BOOL fAdd, BOOL fRemove);
	VOID UpdateMemberChannelId(DWORD dwUserId, ChannelID channelId);
	HRESULT OpenConnection(void);
	HRESULT CloseConnection(void);

	ULONG IsEmpty()               {return 0 == m_cMember;}
	COBLIST * GetMemberList()     {return m_pListMember;}
	VOID AddMember(CNmMember * pMember);
	VOID RemoveMember(CNmMember * pMember);

	CNmMemberId *GetMemberId(CNmMember *pMember);
	CNmMemberId *GetMemberId(DWORD dwUserId);
	VOID  UpdateRosterInfo(CNmMember *pMember, UCID * pucid);
	ChannelID GetChannelId(CNmMember *pMember);
	CNmMember *PMemberFromSenderId(UserID id);
	CConfObject * PConference() {return m_pConference;}
	DWORD GetLocalId()          {return m_dwUserIdLocal;}

	// INmChannelData methods
	STDMETHODIMP IsActive(void);
	STDMETHODIMP SetActive(BOOL fActive);
	STDMETHODIMP GetConference(INmConference **ppConference);
	STDMETHODIMP EnumMember(IEnumNmMember **ppEnum);
	STDMETHODIMP GetMemberCount(ULONG * puCount);	STDMETHODIMP GetGuid(GUID *pguid);
	STDMETHODIMP SendData(INmMember *pMember, ULONG uSize, LPBYTE pb, ULONG uOptions);
	STDMETHODIMP RegistryAllocateHandle(ULONG numberOfHandlesRequested);
	

	// IUnknown methods
	ULONG STDMETHODCALLTYPE AddRef(void);
	ULONG STDMETHODCALLTYPE Release(void);
	STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppvObj);

/////////////////////////////////////////////////////////////


// class CT120Channel

private:
	DWORD DoJoin(SCSTATE scs);

	DWORD DoJoinStatic(ChannelID staticChannel);
	DWORD DoCreateSap(void);
	DWORD DoEnroll(void);
	DWORD DoJoinPrivate(void);
	DWORD DoAttach(void);
	DWORD DoRegRetrieve(void);
	DWORD DoRegChannel(void);
	DWORD DoJoinNew(void);
	DWORD DoJoinOld(void);
	DWORD DoRegPrivate(void);

	VOID  OnEntryConfirmRemote(GCCAppSapMsg * pMsg);
	VOID  OnEntryConfirmLocal(GCCAppSapMsg * pMsg);

public:
	// Methods:
	VOID InitCT120Channel(DWORD dwUserId);

	GUID * m_pGuid;
	CNmChannelData * m_pChannel;

	DWORD   m_dwUserId;
	BYTE    m_keyApp[cbKeyApp];
	BYTE    m_keyChannel[cbKeyApp];

	SCSTATE m_scs;         // Current state

	GCCConferenceID m_gcc_conference_id;
	IGCCAppSap      *m_gcc_pIAppSap;
	GCCSessionKey   m_gcc_session_key;
	GCCRegistryKey  m_gcc_registry_key;
	GCCRegistryItem m_gcc_registry_item;

	GCCRegistryKey  m_registry_key_Private;
	GCCRegistryItem m_registry_item_Private;
	
	ChannelID       m_mcs_channel_id;  // public channel ID
	PIMCSSap	    m_pmcs_sap;

	UserID          m_gcc_node_id;

	// m_mcs_sender_id is the result of MCS_ATTACH_USER_CONFIRM.
	// It is also the "sender_id" in MCS_SEND_DATA_INDICATION
	UserID          m_mcs_sender_id;

	// Properties:
	BOOL    FConnected(void)       {return (SCS_CONNECTED == m_scs);}
	ChannelID GetMcsChannelId()    {return m_mcs_channel_id;}
	ChannelID SenderChannelId()    {return m_mcs_sender_id;}

	VOID    CloseChannel(VOID);
	HRESULT HrSendData(ChannelID channelId, DWORD dwUserId, LPVOID lpv, DWORD cb, ULONG opt);
	VOID    UpdateScState(SCSTATE scs, DWORD dwErr);
	VOID    ProcessEntryConfirm(GCCAppSapMsg * pMsg);
	BOOL    UpdateRoster(GCCAppSapMsg * pMsg);
	VOID    RemovePeer(UINT iPeer);
	VOID    RequestChannelId(DWORD dwUserId);
	VOID    NotifyChannelConnected(void);
	VOID    ProcessHandleConfirm(GCCAppSapMsg * pMsg);

};
DECLARE_STANDARD_TYPES(CNmChannelData);

void CALLBACK NmGccMsgHandler(GCCAppSapMsg * pMsg);
void CALLBACK NmMcsMsgHandler(unsigned int uMsg, LPARAM lParam, PVOID pv);

// list management
POSITION AddNode(PVOID pv, COBLIST **ppList);
PVOID RemoveNodePos(POSITION * pPos, COBLIST *pList);
VOID  RemoveNode(PVOID pv, COBLIST * pList);

// Data Notification Structure
typedef struct {
	INmMember * pMember;
	LPBYTE   pb;
	ULONG    cb;
	ULONG    dwFlags;
} NMN_DATA_XFER;


// Global Routines
VOID FreeMemberIdList(COBLIST ** ppList);
HRESULT	OnNmDataSent(IUnknown *pConferenceNotify, void *pv, REFIID riid);
HRESULT OnNmDataReceived(IUnknown *pConferenceNotify, void *pv, REFIID riid);
HRESULT	OnAllocateHandleConfirm(IUnknown *pConferenceNotify, void *pv, REFIID riid);



#endif // _ICHNLDAT_H_
