/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Data-Model Framework (DM)
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/08
// RCS-ID:      $Id: dmcmn.h,v 1.7 2001/04/04 12:42:36 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifndef __DMCMN_G__
#define __DMCMN_G__

#include "wx/object.h"
#include "wx/list.h"
#include "wx/dynarray.h"

// class hierarchy of Data-Model Framework (DM)

class wxObject;
	class wxDMAttrInfo;
	class wxDMAttrGroupInfo;

	class wxDMNode;
		class wxDMCompositeNode;

	class wxDMCommandProcessor;
	class wxDMClipboard;
	class wxDMListener;

WX_DEFINE_ARRAY( wxDMAttrInfo*, DMAttrInfoListT );
WX_DEFINE_ARRAY( wxDMAttrGroupInfo*, DMAttrGroupInfoListT );
WX_DEFINE_ARRAY( wxDMNode*, DMNodeListT );
WX_DEFINE_ARRAY( wxDMListener*, DMListenerListT );

#define NOTIFY_NO_ARG( method ) \
	{  DMListenerListT& _lst = GetListeners(); \
	   for(size_t ii = 0; ii != _lst.Count(); ++ii )\
		_lst[ii]->##method(); }

#define NOTIFY_ONE_ARG( method, arg1 ) \
	{  DMListenerListT& _lst = GetListeners(); \
	   for(size_t ii = 0; ii != _lst.Count(); ++ii )\
		_lst[ii]->##method( arg1 ); }

#define NOTIFY_TWO_ARG( method, arg1, arg2 ) \
	{  DMListenerListT& _lst = GetListeners(); \
	   for(size_t ii = 0; ii != _lst.Count(); ++ii )\
		_lst[ii]->##method( arg1, arg2 ); }

#define NOTIFY_THREE_ARG( listeners, method, arg1, arg2, arg3 ) \
	{  DMListenerListT& _lst = GetListeners(); \
	   for(size_t ii = 0; ii != _lst.Count(); ++ii )\
		_lst[ii]->##method( arg1, arg2, arg3 ); }

class wxDMListener
{
public:
	virtual void OnNodeRemoved( wxDMNode& node );
	virtual void OnNodeAdded( wxDMNode& node );
	virtual void OnNodeChanged( wxDMNode& node );
	virtual void OnNodeOrderChanged( wxDMNode& node );
	virtual void OnPointerChanged( wxDMNode* pFromPtr, wxDMNode* pToPtr );
	virtual void OnNodeReplaced( wxDMNode& node, wxDMNode& withNode );
	
	virtual void OnFocusChanged( wxDMNode& node );
	virtual void OnFocusRemoved();

	virtual void OnSelectionSet( DMNodeListT& nodes );
	virtual void OnNodeAddedToSelection( wxDMNode& node );
	virtual void OnNodeDeselected( wxDMNode& node );

	virtual void OnUpdateFinished();
};

class wxDMNode : public wxObject
{
public:
	wxDMNode();
	~wxDMNode();

	// overridables
	virtual bool Contains( wxDMNode* pNode );
	virtual bool IsLinked();

	virtual wxDMNode* Clone( bool uniqueCopy, bool cloneChildren = FALSE );
	virtual void AssignData( wxDMNode* pCopy, bool uniqueCopy, bool cloneChildren );

	// operations 

	virtual size_t GetGroupCount();
	virtual wxDMAttrGroupInfo* GetAttrGroupInfo( size_t index );
	virtual void* GetAttrGroupData( size_t index );
	virtual void* GetAttrGroupData( wxDMAttrGroupInfo* pForGroup );
	virtual wxString GetDisplayName();

	virtual size_t GetOrderNo();
	virtual void SetOrderNo( size_t orderNo );

	virtual void AddChild( wxDMNode* pChild, int zOrder = -1 );
	virtual void Remove();
	virtual void RemoveChild( wxDMNode* pChild );
	virtual void RemoveChild( size_t childIndex );

	virtual void OnStartEdit();
	virtual void OnFinishEdit();

	virtual bool CanHaveChildren();
	virtual bool HasChildren();
	virtual size_t GetChildCount();
	virtual wxDMNode* GetChild( size_t index );
	virtual void Replace( wxDMNode* pWithNode );
	virtual DMNodeListT& GetChildren();

	virtual bool HasParent();
	virtual void SetParent( wxDMNode* pParent );
	virtual wxDMNode* GetParent();

	/*** support for undo-able operations ***/

	// notifications should be invoked to let the notify
	// the command-manager when the object's shape or location changes

	virtual void NotifyWillChange( wxDMNode* pObj );
	virtual void NotifyWillRemove( wxDMNode* pObj );
	virtual void NotifyAdded( wxDMNode* pObj );

	// overridable notifications for parent-nodes 

	virtual void OnChildInserted( wxDMNode* pNode );
	virtual void OnChildChanged( wxDMNode* pNode );
	virtual void OnChildRemoved( wxDMNode* pNode );

	virtual bool HasCommandProcessor();
	virtual void SetCommandProcessor( wxDMCommandProcessor* pProcessor );
	virtual wxDMCommandProcessor* GetCommandProcessor();
	virtual wxDMCommandProcessor* FindCmdProcessor();

	virtual DMListenerListT& GetListeners();

	virtual void SetSelected( bool isSelected );
	virtual bool IsSelected();
	virtual void SetFocused( bool isFocused );
	virtual bool IsFocused();

	virtual wxDMNode* FindFocus();

	// helpers

	wxDMNode& GetRootNode();

	virtual void GetSelection( DMNodeListT& toLst );
	virtual void SetSelection( DMNodeListT& lst );
	virtual wxDMNode* GetFocus();

	DECLARE_DYNAMIC_CLASS( wxDMNode )

	enum EXTENRAL_STATE_FLAGS
	{
		NODE_SELECTED = 0x1,
		NODE_FOCUSED  = 0x2
	};

protected:
	void DoSetSelection( wxHashTable& nodeHash );
	wxDMNode* FindFocusRecursive( wxDMNode* pNode );

protected:
	wxDMNode*   mpParent;
	int			mFlags;
};

class wxDMCompositeNode : public wxDMNode
{
public:
	wxDMCompositeNode();
	~wxDMCompositeNode();

	// overrriden methods of wxDMNode

	virtual void AssignData( wxDMNode* pCopy, bool uniqueCopy, bool cloneChildren );

	virtual void AddChild( wxDMNode* pChild, int zOrder = -1 );
	virtual void RemoveChild( wxDMNode* pChild );
	virtual void RemoveChild( size_t childIndex );

	virtual bool HasChildren();
	virtual size_t GetChildCount();
	virtual wxDMNode* GetChild( size_t index );
	virtual DMNodeListT& GetChildren();

	virtual void SetCommandProcessor( wxDMCommandProcessor* pProcessor );
	virtual bool HasCommandProcessor();
	virtual wxDMCommandProcessor* GetCommandProcessor();

	DECLARE_DYNAMIC_CLASS( wxDMCompositeNode )

protected:
	DMNodeListT	  mChildren;
	wxDMCommandProcessor* mpCmdProcessor;
};

class wxDMAttrInfo : public wxObject
{
public:
	wxDMAttrInfo();
	~wxDMAttrInfo();

	// string-based methods dedicated for editing this 
	// property within propert-sheet control

	virtual wxString GetStringValue( void* pGroupData );
	virtual void SetStringValue( const wxString& value, void* pGroupData );
	virtual bool ValidateStringValue( const wxString& value, const wxString* pErrMsg = NULL );

	virtual bool HasRestrictedValues( void* pGroupData );
	virtual bool SetRestrictedValues( wxStringList& list );
	virtual void GetRestrictedValues( wxStringList& toLst, void* pGroupData );

	virtual bool HasMultipleValues( void* pGroupData );
	virtual void SetMultipleValues( wxStringList& fromList, void *pGroupData );
	virtual void GetMultipleValues( wxStringList& toList, void* pGroupData );

	virtual void InitValue( void* pGroupData );
	virtual void DestroyValue( void* pGroupData );
	virtual void CopyValue( void* pDestData, void* pSrcData );

	virtual void SetUserData( void* pUserData );
	virtual void* GetUserData();

	virtual bool ShownAsBooleanField();

	// meta-info
	virtual void SetVisible( bool visible );
	virtual bool IsVisible();

	virtual void SetName( const wxString& name );
	virtual wxString GetName();
	virtual void SetDisplayName( const wxString& name );
	virtual wxString GetDisplayName();
	virtual void SetDefaultValue( const wxString& value );
	virtual const wxString& GetDefaultValue();

	virtual bool NeedsCustomEditor();
	virtual wxWindow* CreateCustomEditor();
	virtual bool ApplayEditorChanges( wxWindow* pCustEditor, void* pGroupData );

	virtual bool HasValueSelectionDialog();
	virtual bool ShowValueSelectonDialog( void* pGroupData );

	virtual bool IsDefaultValue( void* pGroupData );

	DECLARE_DYNAMIC_CLASS( wxDMAttrInfo )

protected:
	wxString mName;
	wxString mDisplayName;
	wxString mDefaultValue;
	bool	 mVisible;
	void*    mpUserData;
};

class wxDMAttrGroupInfo : public wxObject
{
public:
	wxDMAttrGroupInfo();
	~wxDMAttrGroupInfo();

	virtual void SetName( const wxString& name );
	virtual const wxString& GetName();

	virtual size_t Count();
	virtual wxDMAttrInfo* GetAttr( size_t index );

	virtual wxString GetAttrValueByName( const wxString& name, void* pGroupData );
	virtual void SetAttrValueByName( const wxString& name, const wxString& value, 
									 void* pGroupData );

	virtual void Add( wxDMAttrInfo* pInfo );
	virtual void RemoveAll();

	virtual void InitValues( void* pGroupData );
	virtual void DestroyValues( void* pGroupData );
	virtual void CopyValues( void* pDestGroupData, void* pSrcGroupData );

	// returns (size_t)(-1) if not present
	virtual size_t GetAttrIndex( const wxString& attrName );

	wxDMAttrInfo* GetAttrByName( const wxString& attrName );

	DECLARE_DYNAMIC_CLASS( wxDMAttrGroupInfo )

protected:
	wxString		mName;
	DMAttrInfoListT mAttribs;
};

enum wxDM_COMMAND_TYPES
{
	wxDM_CMD_CHANGE,
	wxDM_CMD_ADD,
	wxDM_CMD_REMOVE
};

///////////////////////////////////////
/// support for undoable operations ///
///////////////////////////////////////

enum DM_COMMAND_TYPE
{
	DM_CMD_CHANGE,
	DM_CMD_ADD,
	DM_CMD_REMOVE,

	DM_CMD_LATEST_STATE
};

class wxDMCommandInfo : public wxObject
{
public:
	wxDMCommandInfo( int type, wxDMNode* pRealObj, size_t batchLevel );
	~wxDMCommandInfo();

	int GetType();
	bool FinishesBatch();
	wxDMCommandInfo* GetLatestState();

	void CaptureLatestState();

public: /* protected really */
	int          mType;
	wxDMNode*    mpObjCopy;
	wxDMNode*    mpRealObj;
	bool         mRealObjIsDelted;
	wxDMNode*	 mpParent;
	bool		 mParentIsDeleted;

	size_t       mZOrder;
	bool         mFinishesBatch;

	wxDMCommandInfo* mpLatestState;
};

WX_DEFINE_ARRAY( wxDMCommandInfo*, DMCommandInfoListT );

class wxDMCommandProcessor : public wxObject
{
public:

	wxDMCommandProcessor();
	wxDMCommandProcessor( wxDMNode* pRootNode, size_t maxCommands = 1000000 );
	~wxDMCommandProcessor();

	virtual void SetRoot( wxDMNode* pObj );

	virtual void ClearCommandBuffer();

	virtual void SetChangeSender( wxObject* pObject );
	virtual wxObject* GetChangeSender();

	virtual void NotifyWillChange( wxDMNode* pObj );
	virtual void NotifyWillRemove( wxDMNode* pObj );
	virtual void NotifyAdded( wxDMNode* pObj );

	virtual void StartBatch();
	virtual void FinishBatch();

	// user-level commands

	virtual bool CanUndo();
	virtual bool CanRedo();
	virtual bool CanPaste();
	virtual bool CanDelete();

	virtual void Undo();
	virtual void Redo();

	virtual void Delete();
	virtual void SelectAll();
	virtual void Copy();
	virtual void Paste();

	virtual void AddListener( wxDMListener* pListener );
	virtual void RemoveListener( wxDMListener* pListener );
	virtual DMListenerListT& GetListeners();

	// given clipboard object is not owned (released) by command processor

	virtual wxDMClipboard* GetClipboard();
	virtual void SetClipboard( wxDMClipboard* pBoard );

	DECLARE_DYNAMIC_CLASS( wxDMCommandProcessor )

protected:

	void RelinkReferencesTo( wxDMNode* pNewObj, wxDMCommandInfo& cmd );

	void RemoveObject( wxDMCommandInfo& cmd );
	void RestoreObject( wxDMCommandInfo& cmd );
	void AddObject( wxDMCommandInfo& cmd );
	bool HasModsAhead( size_t cmdNo );

	void CleanUp();
	void SetRootNode( wxDMNode* pNode );

	void CheckBuffer();
	void InsertCommand( wxDMCommandInfo* pCmd );

	void EncodeDeletedObject( wxDMNode* pDeleted );

	void DoDeleteRecursive( wxDMNode* pNode );

protected:

	wxDMNode*		mpRootNode;
	static wxDMClipboard*  mpClipboard;
	wxObject*		mpChangeSender; // object which has recently
									// initiated node change 
	DMListenerListT mListeners;

	DMCommandInfoListT	mCommands;
	size_t				mBatchLevel;
	size_t				mMaxCommands;
	size_t				mNextCmd;

	bool		mQueueLocked;

	static size_t mIdGenerator;
};

class wxDMPasteHandler
{
public:
	virtual void HandleNodePasting( wxDMNode* pNode, wxDMNode* pToNode, int depth ) = 0;
};

class wxDMClipboard : public wxObject
{
public:
	wxDMClipboard();
	~wxDMClipboard();

	virtual bool CanCopy();
	virtual bool CanPaste();

	virtual void Copy();
	virtual void Paste();

	virtual void SetRootNode( wxDMNode* pNode );

	virtual void Destroy();

	virtual void SetPasteHandler( wxDMPasteHandler* pHandler );
	virtual wxDMPasteHandler* GetPasteHandler();

protected:
	virtual wxDMNode* DoPasteRecursive( wxDMNode* pNode, wxDMNode* pTarget, int depth );

protected:
	wxDMNode*   mpRoot;
	wxDMPasteHandler* mpHandler;
	DMNodeListT mContent;
};

#endif // __DMCMN_G__