/****************************************************************************************

		IChangeManagement.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		IChangeListener definition
		IChangeChannel definition
		IChangeManager definition

		Author:	Greg
		Date:	4/6/98
		
		The ChangeManager allows objects to notify others of changes.  These changes
		are communicated via ChangeChannels.  ChangeChannels can be created via the 
		ChangeManager, and objects that wish to be notified of a change register 
		themselves on the channel.  When a change is posted by an object, each listener 
		on the channel is notified via IChangeListener::DataChanged().
		
		Multiple changes can be grouped via calls to BeginChange() and EndChange().
		When a BeginChange() is encountered, all changes (on all channels) are queued
		until a matching EndChange() is found.  Since BeginChange()/EndChange() pairs
		can nest, only after the outermost EndChange() is found are the changes processed.
		 
		For example:
		
			BeginChange();
			...
			changeManager->PostChange(kMyChannel, 'add ', theData);
			...
			changeManager->PostChange(kMyChannel, 'edit', theData);
			...
			changeManager->PostChange(kMyChannel, 'del ', theData);
			...
			EndChange();			

		When EndChange() is called, all of the changes are processed, in order of 
		posting.  Note that each listener receives a given change before any
		listener receives the next change in the list (so that in the above example,
		all of the listeners would receive the 'add' change, then every listener would
		receive the 'edit' change, and so on).
		
		Using BeginChange() and EndChange() makes it possible to discard all changes on
		a particular channel or all channels.  DiscardChangesOnChannel() and 
		DiscardAllChanges() removes all queued changes on a channel or all channels (in
		other words, all changes since the outermost BeginChange() was called). It is
		meaningless to call DiscardChangesOnChannel() or DiscardChangesOnAllChannels()
		when not inside a BeginChange()/EndChange() pair.
		
		Since it is impossible for a listener to know when more related changes are coming,
		generally, it is a good idea for DataChanged() to simply invalidate data instead
		of doing any drawing or changes directly.  For example, if a window is listening
		to the selection channel, and changes the name in an edit text in DataChanged(),
		then if some object posts two successive changes on the selection channel to
		deselect the old object and reselect the new one, then the window will update the
		edit text twice, and will most likely flicker.  Instead, the window should simply
		note that they should grab the selection at the next available opportunity and
		update the edit text then (asyncronously).  

		Revision History

		when		who			what & why
		==========	==========	======================================================
		12/11/98	Joshua		New change management API

*****************************************************************************************/

#ifndef __ICHANGEMANAGEMENT__
#define __ICHANGEMANAGEMENT__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCOSConfig.h"
#include "MCCompObj.h"

struct IChangeListener;

//*********************** Globally Unique Ids ********************************

MCDEFINE_GUID_H(IID_IChangeChannel);
MCDEFINE_GUID_H(IID_IChangeListener);
MCDEFINE_GUID_H(IID_IChangeManager);

//****************************************************************************



/******************************************************************************\
*                                                                              *
*      IChangeChannel                                                          *
*                                                                              *
\******************************************************************************/

/// \addtogroup ShellInterface
///
/// \{

/// This is the generic interface to access a change channel. A change channel
/// stores a list of listener that are notified when a change occurs.
///
/// There are several change channels in the application. They are identified by
/// a four characters Identifier.
///
struct IChangeChannel : public IMCUnknown
{
	// ****************************************************************************
	//								RegisterListener
	// 
	/// Registers a listener.
	/// 
	virtual void 	MCCOMAPI RegisterListener	(IChangeListener* 	listener) = 0;
	
	// ****************************************************************************
	//								UnregisterListener
	// 
	/// Unregister a listener.
	/// 
	virtual void 	MCCOMAPI UnregisterListener	(IChangeListener* 	listener) = 0;
	
	// ****************************************************************************
	//								GetChannelID
	// 
	/// Returns the Identifier of the channel.
	/// 
	virtual int32	MCCOMAPI GetChannelID		() = 0;
};

/// \}



/// \addtogroup ShellInterface
/// \{

/******************************************************************************\
*                                                                              *
*      IChangeListener                                                         *
*                                                                              *
\******************************************************************************/

/// The generic interface for a listener in a change channel (see IChangeChannel).
///
/// If you want to be notified from changes, you can derive your class from this
/// interface and register it in a change channel.
///
struct IChangeListener : public IMCUnknown
{
	// ****************************************************************************
	//								DataChanged
	// 
	/// This function is called when a change has been posted on a channel
	/// on which this IChangeListener registered itself.
	/// 
	/// \param channel      The channel that is notifying of the change.
	/// \param changeKind   The kind of change.
	/// \param changedData  Data associated with the type of change.
	/// 
	virtual void 	MCCOMAPI DataChanged		(IChangeChannel* channel, IDType changeKind, IMCUnknown* changedData) = 0;
};

/// \}


/// \addtogroup ShellInterface
/// \{

/******************************************************************************\
*                                                                              *
*       IChangeManager                                                         *
*                                                                              *
\******************************************************************************/

enum { kAnonymousChannel = -1 };

/// The change manager manages the list of the change channels (see IChangeChannel).
///
struct IChangeManager : public IMCUnknown
{
	// ****************************************************************************
	//								CreateChannel
	// 
	/// Creates a new channel with the ID channelID.  If a channel already exists
	/// with the same ID, the function returns that channel and a new channel 
	/// is not created (exception: any number of anonymous channels can be created
	/// and CreateChannel(kAnonymousChannel) will return a new channel every time).
	/// 
	/// \param outChannel         The new channel
	/// \param channelID		  The identifier of the channel.
	/// 
	virtual void	MCCOMAPI 	CreateChannel				(IChangeChannel** outChannel, int32 channelID = kAnonymousChannel) = 0;
	
	// ****************************************************************************
	//								GetChannelByID
	// 
	/// Finds the channel with the ID channelID.  Anonymous channels can not be
	/// found in this way.
	/// 
	/// \param outChannel  A pointer to the channel.
	/// \param channelID   The ID of the channel
	/// 
	virtual void	MCCOMAPI 	GetChannelByID				(IChangeChannel** outChannel, int32	channelID) = 0;
		
	// ****************************************************************************
	//								BeginChange
	// 
	/// Called at the beginning of a change. The changes are queued at a different
	/// level until EndChange is posted.
	/// 
	virtual void	MCCOMAPI	BeginChange					() = 0;
	
	// ****************************************************************************
	//								EndChange
	// 
	/// Called at the end of a change. (see BeginChange())
	/// 
	virtual void	MCCOMAPI	EndChange					() = 0;

	// ****************************************************************************
	//								PostChange
	// 
	/// Post a change
	/// 
	/// \param channelID    The ID of the change channel
	/// \param changeKind   The type of change.
	/// \param changedData  The data associated with this change.
	/// 
	virtual void	MCCOMAPI	PostChange					(int32				channelID,
															 IDType				changeKind,
															 IMCUnknown*		changedData) = 0;

	// ****************************************************************************
	//								PostChange
	// 
	/// Post a change
	/// 
	/// \param channel      A pointer to the change channel
	/// \param changeKind   The type of change.
	/// \param changedData  The data associated with this change.
	/// 
	virtual void	MCCOMAPI	PostChange					(IChangeChannel*	channel,
															 IDType				changeKind,
															 IMCUnknown* 		changedData) = 0;
														 		
	// ****************************************************************************
	//								DiscardChangesOnChannel
	// 
	/// Discard all the changes posted on a channel.
	/// 
	/// \param channel  The change channel.
	/// 
	virtual void	MCCOMAPI	DiscardChangesOnChannel		(IChangeChannel* channel) = 0;
	
	// ****************************************************************************
	//								DiscardChangesOnAllChannels
	// 
	/// Discard all the changed posted on a channel.
	/// 
	virtual void	MCCOMAPI	DiscardChangesOnAllChannels	() = 0;

	// ****************************************************************************
	//								ProcessQueuedChanges
	// 
	/// Process all the changes that were queued.
	/// 
	virtual void	MCCOMAPI	ProcessQueuedChanges		() = 0;
	
	// ****************************************************************************
	//								EndAndDiscardChange
	// 
	/// Called at the end of a change like EndChange() (see BeginChange()). But it
	/// will also discard any changes that has been posted during the Beginchange /
	/// EndChange block.
	/// 
	virtual void	MCCOMAPI	EndAndDiscardChange			() = 0;
};


/// \}

//******************************************************************

#endif