/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __MODEL__H__
#define __MODEL__H__

#include "ustr.h"
#include <vector>

// forward references 
class EntnodeData;

#if qMacPP
#define CObject LPane
#endif

#ifdef qUnix
#define CObject void
#endif

// use this to cast to proper notification handler
typedef void (*FNOBSERVER)(CObject*);


// notification handler
//template <class TObserver>
class NotificationManager
{
// used types
public:

private:
	// node describing observer registration
	struct Node
	{
		CObject* observer;  
		// observer

		FNOBSERVER handler; 
		// its notification handler

		// default constructor just zeroes everything
		Node()
		: observer(NULL), handler(NULL)
		{}

		// full-blown construction
		Node(CObject* o, FNOBSERVER h)
		: observer(o), handler(h)
		{}

		Node(const Node & n)
		{
			observer = n.observer;
			handler = n.handler;
		}

		Node & operator=(const Node & n)
		{
			observer = n.observer;
			handler = n.handler;
			return *this;
		}

	};

// Attributes
private:
	std::vector<Node> m_nodes;
	
// Construction
public:
	NotificationManager()	{}

// Operations
public:
	// register an observer
	void CheckIn(CObject* observer, FNOBSERVER handler)
	{
		m_nodes.push_back(Node(observer, handler));
	}

	// unregister an observer
	void CheckOut(CObject* observer)
	{
		for (std::vector<Node>::iterator i = m_nodes.begin(); i != m_nodes.end(); i++)
		{
			if ((*i).observer == observer)
			{
				m_nodes.erase(i);
				break;
			}
		}
	}

	// fire up a notification once done with changes in observable
	void NotifyAll()
	{
		for (std::vector<Node>::iterator i = m_nodes.begin(); i != m_nodes.end(); i++)
		{
			// make a local copy so that observers can freely unregister during the process
			Node & node = *i;
			node.handler(node.observer);
		}
	}

};

// interface to filtering entries
class KiFilterModel
{
// Interfaces
public:
	// checks to see if an item satisfies current filtering criteria
	virtual bool IsMatch(EntnodeData* data) = 0;

	// retrieves notification manager for observing changes in the 
	virtual NotificationManager* GetNotificationManager() = 0;
};

// interface to recursive display of entries
class KiRecursionModel
{
// Interfaces
public:
	// returns true if displaying files recursively
	virtual bool IsShowRecursive() = 0;

	// retrieves notification manager for observing changes in the 
	virtual NotificationManager* GetNotificationManager() = 0;
};

// interface to recursive display of entries
class KiIgnoreModel
{
// Interfaces
public:
	// returns true if displaying ignored files
	virtual bool IsShowIgnored() = 0;

	// retrieves notification manager for observing changes in the 
	virtual NotificationManager* GetNotificationManager() = 0;
};

// interface to filtering entries
class KoFilterModel : public KiFilterModel
{
// Attributes
protected:
	NotificationManager m_manager; // manager for filter change notifications
	UStr m_mask;			 // current file mask
	std::vector<UStr> m_match;  // itemized array of file masks to display as found
	bool m_isChanged;		// flag to tell if only changed files are to be displayed
	bool m_isAdded;			// flag to tell if only added files are to be displayed
	bool m_isRemoved;		// flag to tell if only removed files are to be displayed
	bool m_isConflicts;		// flag to tell if conflicting files shall be displayed

	bool m_isUnknown;		// flag to tell if unknown files have to be shown
	bool m_isMissing;		// flag to tell if missing files have to be shown
	bool m_isHideUnknown;	// flag to tell if unknown files have to be hidden, mutually 
							// exclusive with above

// Construction
public:
	KoFilterModel();
	virtual ~KoFilterModel();


// Interfaces
public:
	// checks to see if an item satisfies current filtering criteria
	virtual bool IsMatch(EntnodeData* data);

	// retrieves notification manager for observing changes in the 
	virtual NotificationManager* GetNotificationManager();

// Operations
public:
	// tells if the filter is in default mode - fo show flags are set
	bool IsDefaultMode() const;

	// toggles modified flag
	void ToggleModified();

	//accessor for modified flag
	bool IsModified() const;

	// sets new file mask, returns true if changed
	bool SetMask(const char *mask);

	// toggles show conflict flag
	void ToggleConflict()
	{
		m_isConflicts = !m_isConflicts;
	}

	//accessor for show conflict flag
	bool IsConflict() const
	{
		return m_isConflicts;
	}

	// toggles show conflict flag
	void ToggleUnknown();

	//accessor for show unknown flag
	bool IsUnknown() const
	{
		return m_isUnknown;
	}

	// toggles hide unknown flag
	void ToggleHideUnknown();

	//accessor for hide unknown flag
	bool IsHideUnknown() const
	{
		return m_isHideUnknown;
	}


	// toggles show missing flag
	void ToggleMissing()
	{
		m_isMissing = !m_isMissing;
	}

	//accessor for show missing flag
	bool IsMissing() const
	{
		return m_isMissing;
	}

	void ToggleChanged()
	{
		m_isChanged = !m_isChanged;
	}

	bool IsChanged() const
	{
		return m_isChanged;
	}

	void ToggleAdded()
	{
		m_isAdded = !m_isAdded;
	}

	bool IsAdded() const
	{
		return m_isAdded;
	}

	void ToggleRemoved()
	{
		m_isRemoved = !m_isRemoved;
	}

	bool IsRemoved() const
	{
		return m_isRemoved;
	}
};

// interface to recursive display of entries
class KoRecursionModel : public KiRecursionModel
{
	NotificationManager m_manager; 
	// manager for change notifications

	bool m_isRecursive;		
	// flag to tell if files in subfolders shall be iterated
// Construction
public:
	KoRecursionModel();
	virtual ~KoRecursionModel();

// Interfaces
public:
	// returns true if displaying files recursively
	virtual bool IsShowRecursive();

	// retrieves notification manager for observing changes in the 
	virtual NotificationManager* GetNotificationManager();

	// toggle recursion switch
	void ToggleRecursion();

};

// interface to recursive display of entries
class KoIgnoreModel : public KiIgnoreModel
{
	NotificationManager m_manager; 
	// manager for change notifications

	bool m_isIgnore;
	// flag to tell if ignored files are displayed

// Construction
public:
	KoIgnoreModel();
	virtual ~KoIgnoreModel();

// Interfaces
public:
	// returns true if displaying ignored files
	virtual bool IsShowIgnored();

	// retrieves notification manager for observing changes in the 
	virtual NotificationManager* GetNotificationManager();

	// toggle recursion switch
	void ToggleIgnore();
};
#endif 
// __MODEL__H__
