/*
** 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.
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- April 1998
 * Modified: Jerzy Kaczorowski <kaczoroj@hotmail.com> - 27 Jan 2001 - fix warning C4800 (Add "0 != " for all the int variables forced to bool value)
 */

/*
 * CvsEntries.h --- adaptation from cvs/src/entries.c
 */

#ifndef CVSENTRIES_H
#define CVSENTRIES_H

#include "SortList.h"
#include "CvsIgnore.h"
#include "TextBinary.h"

/// Entry type enum
typedef enum
{
	ENT_FILE,	/*!< File entry */
	ENT_SUBDIR	/*!< Directory entry */
} ent_type;

/*!
	Class to support reference counted full path description
	\note Reference-counted, we don't use delete on it
*/
class EntnodePath
{
public:
	// Construction
	EntnodePath(const char* path);
protected:
	virtual ~EntnodePath();

public:
	// Interface
	EntnodePath* Ref();
	EntnodePath* UnRef();
	const char* GetFullPathName(UStr& resPath, const char* name) const;
	const char* GetFolderPath() const;

protected:
	// Data members
	const char* fullpathname;	/*!< Fully qualified pathname of the folder containing the item */
	int ref;					/*!< Reference count */
};

/*!
	Abstract class to hold the node data
	\note Reference-counted, we don't use delete on it
*/
class EntnodeData
{
protected:
	// Construction
	EntnodeData(const char* name, EntnodePath* path);
	virtual ~EntnodeData();

public:
	/// Enum node types
	enum
	{
		kName = 0,
		kStatus = 3,
		kPath = 7
	};

	// Interface
	
	/// Get the entry type
	virtual ent_type GetType() const = 0;

	EntnodeData* Ref();
	EntnodeData* UnRef();
	static int Compare(const EntnodeData& node1, const EntnodeData& node2);
	virtual const char* operator[](int index) const;

	void SetMissing(bool state);
	bool IsMissing() const;
	void SetVisited(bool state);
	bool IsVisited() const;
	void SetUnknown(bool state);
	bool IsUnknown() const;
	void SetIgnored(bool state);
	bool IsIgnored() const;
	void SetLocked(bool state);
	bool IsLocked() const;
	void SetRemoved(bool state);
	bool IsRemoved() const;
	void SetDesc(const char* newdesc);
	const char* GetDesc() const;

	const char* GetName() const;
	const char* GetFullPathName(UStr& resPath) const;

	const char* GetFolderPath() const;
	virtual const char* GetConflict() const;

	void SetUnmodified(bool state);
	bool IsUnmodified() const;

#ifdef TARGET_OS_MAC
	UFSSpec& MacSpec();
	const UFSSpec& GetMacSpec() const;
#endif /* TARGET_OS_MAC */

protected:
	// Data members
	int ref;	/*!< Reference counter */

	int missing : 1;	/*!< Missing flag */
	int visited : 1;	/*!< Visited flag */
	int unknown : 1;	/*!< Unknown flag */
	int unmodified : 1;	/*!< Unmodified flag */
	int ignored : 1;	/*!< Ignored flag */
	int locked : 1;		/*!< Locked flag */
	int removed : 1;	/*!< Removed flag */

#ifdef TARGET_OS_MAC
	UFSSpec macspec;	/*!< Macspec */
#endif /* TARGET_OS_MAC */

private:
	const char* user;			/*!< Name of this item */
	const char* desc;			/*!< Item's description */
	EntnodePath* fullpathname;	/*!< Fully qualified pathname of the folder containing the item */
	
	static UStr sbuffer;	/*!< Static buffer */
};

/*!
	Abstract class to hold the file node data
	\note Reference-counted, we don't use delete on it
*/
class EntnodeFile : public EntnodeData
{
public:
	// Construction
	EntnodeFile(const char* name, EntnodePath* path, const char* newvn = 0L,
		const char* newts = 0L, const char* newoptions = 0L,
		const char* newtag = 0L, const char* newdate = 0L,
		const char* newts_conflict = 0L);
protected:
	virtual ~EntnodeFile();

public:
	/// Enum file node types
	enum
	{
		kVN = 1,
		kTS = 5,
		kOption = 2,
		kTag = 4,
		kConflict = 6
	};

	// Interface
	virtual const char* operator[](int index) const;
	virtual ent_type GetType() const;
	virtual const char* GetConflict() const;

protected:
	// Data members
	const char* vn;				/*!< Revision */
	const char* ts;				/*!< Timestamp */
	const char* option;			/*!< Option */
	const char* tag;			/*!< Tag, can be NULL */
	const char* date;			/*!< Date, can be NULL */
	const char* ts_conflict;	/*!< Conflict, can be NULL */
};

/*!
	Abstract class to hold the folder node data
	\note Reference-counted, we don't use delete on it
*/
class EntnodeFolder : public EntnodeData
{
public:
// Construction
	EntnodeFolder(const char* name, EntnodePath* path, const char* newvn = 0L,
		const char* newts = 0L, const char* newoptions = 0L, const char* newtag = 0L,
		const char* newdate = 0L, const char* newts_conflict = 0L);
protected:
	virtual ~EntnodeFolder();

public:
	// Interface
	virtual const char* operator[](int index) const;
	virtual ent_type GetType() const;
};

/// Allow reference of a file or a folder node
class ENTNODE
{
public:
	// Construction
	ENTNODE();
	ENTNODE(EntnodeData* data);
	ENTNODE(EntnodeData& data);
	ENTNODE(const ENTNODE& anode);
	virtual ~ENTNODE();

	// Interface
	static int Compare(const ENTNODE& node1, const ENTNODE& node2);
	ENTNODE& operator=(const ENTNODE& anode);
	EntnodeData* Data() const;
	operator EntnodeData*() const;

protected:
	// Data members
	EntnodeData* shareData; /*!< Data */
};

bool Entries_Open(CSortList<ENTNODE>& entries, const char* fullpath);

EntnodeData* Entries_SetVisited(const char* path, CSortList<ENTNODE>& entries, const char* name,
	const struct stat& finfo, bool isFolder, const std::vector<CStr>* ignlist = 0L);

void Entries_SetMissing(CSortList<ENTNODE>& entries);
bool Tag_Open(CStr& tag, const char* fullpath);

//////////////////////////////////////////////////////////////////////////
// EntnodePath

/// Increase reference count
inline EntnodePath* EntnodePath::Ref()
{
	++ref; 
	return this;
}

/// Decrease reference count, delete self if reference count reached zero
inline EntnodePath* EntnodePath::UnRef()
{
	if( --ref == 0 )
	{
		delete this;
		return 0L;
	}
	
	return this;
}

/*!
	Get the folder path
	\return Folder path
*/
inline const char* EntnodePath::GetFolderPath() const
{
	return fullpathname;
}

//////////////////////////////////////////////////////////////////////////
// EntnodeData

/// Increase reference count
inline EntnodeData* EntnodeData::Ref()
{
	++ref;
	return this;
}

/// Decrease reference count, delete self if reference count reached zero
inline EntnodeData* EntnodeData::UnRef()
{
	if( --ref == 0 )
	{
		delete this;
		return 0L;
	}
	
	return this;
}

/*!
	Compare two nodes data
	\param node1 First node
	\param node2 Second node
	\return Less than zero if node1 is less than node2, zero if nodes are equal, more than zero if node2 is less than node1
	\note For windows comparison is not case sensitive
*/
inline int EntnodeData::Compare(const EntnodeData& node1, const EntnodeData& node2)
{
#ifdef WIN32
	return stricmp(node1.user, node2.user);
#else /* !WIN32 */
	return strcmp(node1.user, node2.user);
#endif /* !WIN32 */
}

/// Set the missing flag
inline void EntnodeData::SetMissing(bool state)
{
	missing = state;
}

/// Get the missing flag
inline bool EntnodeData::IsMissing() const
{
	return 0 != missing;
}

/// Set the visited flag
inline void EntnodeData::SetVisited(bool state)
{
	visited = state;
}

/// Get the visited flag
inline bool EntnodeData::IsVisited() const
{
	return 0 != visited;
}

/// Set the unknown flag
inline void EntnodeData::SetUnknown(bool state)
{
	unknown = state;
}

/// Get the unknown flag
inline bool EntnodeData::IsUnknown() const
{
	return 0 != unknown;
}

/// Set the ignored flag
inline void EntnodeData::SetIgnored(bool state)
{
	ignored = state;
}

/// Get the ignored flag
inline bool EntnodeData::IsIgnored() const
{
	return 0 != ignored;
}

/// Set the locked flag
inline void EntnodeData::SetLocked(bool state)
{
	locked = state;
}

/// Get the locked flag
inline bool EntnodeData::IsLocked() const
{
	return 0 != locked;
}

/// Set the removed flag
inline void EntnodeData::SetRemoved(bool state)
{
	removed = state;
}

/// Get the removed flag
inline bool EntnodeData::IsRemoved() const
{
	return 0 != removed;
}

/// Set the description
inline void EntnodeData::SetDesc(const char* newdesc)
{
	desc = newdesc;
}

/// Get the description
inline const char* EntnodeData::GetDesc() const
{
	return desc;
}

/// Get the item name
inline const char* EntnodeData::GetName() const 
{
	return user;
}

/// Get the fully qualified item name
inline const char* EntnodeData::GetFullPathName(UStr& resPath) const 
{
	return fullpathname->GetFullPathName(resPath, user);
}

/// Get the fully qualified folder name of the item
inline const char* EntnodeData::GetFolderPath() const
{
	return fullpathname->GetFolderPath();
}

/// Get the conflict marker
inline const char* EntnodeData::GetConflict() const
{
	return 0L;
}

/// Set the unmodified flag
inline void EntnodeData::SetUnmodified(bool state)
{
	unmodified = state;
}

/// Get the unmodified flag
inline bool EntnodeData::IsUnmodified() const
{
	return 0 != unmodified;
}

#ifdef TARGET_OS_MAC
/// Access macspec
inline UFSSpec& EntnodeData::MacSpec()
{
	return macspec;
}

/// Get macspec
inline const UFSSpec& EntnodeData::GetMacSpec() const
{
	return macspec;
}
#endif /* TARGET_OS_MAC */

//////////////////////////////////////////////////////////////////////////
// ENTNODE

inline ENTNODE::ENTNODE() : shareData(0L) 
{
}

inline ENTNODE::ENTNODE(EntnodeData* data) : shareData(data->Ref())
{
}

inline ENTNODE::ENTNODE(EntnodeData& data) : shareData(data.Ref())
{
}

inline ENTNODE::ENTNODE(const ENTNODE& anode) : shareData(0L)
{
	*this = anode;
}

inline ENTNODE::~ENTNODE()
{
	if( shareData != 0L )
		shareData->UnRef();
}

/*!
	Compare two ENTNODE items
	\param node1 First item
	\param node2 Second item
	\return Less than zero if node1 is less than node2, zero if nodes are equal, more than zero if node2 is less than node1
*/
inline int ENTNODE::Compare(const ENTNODE& node1, const ENTNODE& node2)
{
	return EntnodeData::Compare(*node1.shareData, *node2.shareData);
}

/// Access data
inline EntnodeData* ENTNODE::Data() const
{
	return shareData;
}

/// Operator EntnodeData*
inline ENTNODE::operator EntnodeData*() const
{
	return shareData;
}

#endif /* CVSENTRIES_H */
