/*	XFile.h
 *
 *		This contains the various classes which are used to
 *	manipulate files and search directories
 */

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

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

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

#ifndef PandaWave_XFILE
#define PandaWave_XFILE

#include <stdio.h>
#include <XConfig.h>
#include <XStream.h>
#include <XString.h>
#include <XHandle.h>

#if OPT_XWIN
#include <dirent.h>
#endif

/************************************************************************/
/*																		*/
/*	Forwards															*/
/*																		*/
/************************************************************************/

class XGDirectory;
class XGFileSpecifier;

/************************************************************************/
/*																		*/
/*	File Specifier Abstraction											*/
/*																		*/
/************************************************************************/

/*$	XGDirectory
 *
 *		This object represents a directory on a hard disk. This is a
 *	portable mechanism for creating and changing the current directory,
 *	including updating the current working directory on platforms which
 *	support that operation.
 */

class XGDirectory {
	public:
								XGDirectory();
								XGDirectory( const XGFileSpecifier & );
		virtual					~XGDirectory();
		
		/*
		 *	Set directory to predefined locations
		 */
		
		void					SetAppLocation();
		void					SetCurLocation();
		
		/*
		 *	Change directory stuff
		 */
		
		bool					ChangeDirectory(char *);
						/*		This changes the directory in this either down one level to
						 *	the named directory, or up one level if NULL is passed for name.
						 *	This verifies that the directory exists first. */
		bool					CreateDirectory(char *);
		void					GetDirectoryName( char * );
		
		bool					operator == ( const XGDirectory &other ) const;
		
		/*
		 *	Update the current working directory
		 */
		
		void					UpdateCWD();
		
		/*
		 *	Scan the contents
		 */
		
		bool					GetFirstFile(XGFileSpecifier &, bool *dirf);
		bool					GetNextFile(XGFileSpecifier &, bool *dirf);
		
		/*
		 *	Internal stuff
		 */
		
		static void				InitDirectoryInfo();
		void					SetDirectoryInfo();

	private:
		bool					fInit;

#if OPT_MACOS
		short					fIndex;
		short					fVolRefNum;
		long					fDirID;
#endif

#if OPT_WINOS
		HANDLE					fList;
#endif

#if OPT_XWIN
		DIR						*fList;
#endif

#if OPT_WINOS || OPT_XWIN
		XGString				fPath;
#endif

	friend class XGFileSpecifier;
};

/*$	XGFileSpecifier
 *
 *		This represents a file name.
 *
 *		The problem is there are a couple of ways a file may be
 *	specified, depending on if this is on the Macintosh, Windows
 *	or Unix. Further, we want to be able to specify an "alias",
 *	a way of storing a shortcut to a file.
 *
 *		That's solved by encapsulating the name (or file specifier)
 *	of a file inside of this object. This also provides a mechanism
 *	for extracting the directory of this file, as well as extracting
 *	the file's name and extension.
 *
 *		This also provides a mechanism for creating this thing
 *	from an alias (stored in an XGHandle). Note that an alias is 
 *	only useful on one machine, and is useful for constructing file 
 *	preferences only.
 */

class XGFileSpecifier {
	public:

#if OPT_MACOS
								XGFileSpecifier(FSSpec &);
#else
								XGFileSpecifier(const char *);
#endif

								XGFileSpecifier(XGHandle &);
								XGFileSpecifier();
								XGFileSpecifier(const XGFileSpecifier&);
		virtual					~XGFileSpecifier();
								
		/*
		 *	Initializers
		 */
		
#if OPT_MACOS
		XGFileSpecifier			&operator = (const FSSpec &f);
#else
		XGFileSpecifier			&operator = (const char *f);
#endif

		XGFileSpecifier			&operator = (XGHandle &alias);
		XGFileSpecifier			&operator = (const XGFileSpecifier &);
		
		bool					operator == (const XGFileSpecifier &) const;
		bool					operator != (const XGFileSpecifier &other) const
									{
										return !(*this == other);
									}
		
		/*
		 *	Standard file access
		 */
		
		void					SetFile(XGDirectory &, char *);

		void					GetName(char *) const;
		void					GetBaseName( char *, int maxextension = 3 ) const;
								// get file name minus an extension of up to maxextension characters,
								// EXCLUDING the period.
		void					GetExtension( char *extension, int maxextension = 3 ) const;
		void					GetDirectory(XGDirectory &) const;
		void					GetAlias(XGHandle &) const;
		
		/*
		 *	File open/close by dialog
		 */

#if OPT_MACOS
		static XGFileSpecifier	*OpenDialog(short paramRes);
		static XGFileSpecifier	*SaveDialog(short paramRes, OSType, OSType, char *name);
#endif

#if OPT_WINOS
		static XGFileSpecifier	*OpenDialog(char *tlist, char *dext);
		static XGFileSpecifier	*SaveDialog(char *tlist, char *dext, char *name);
#endif

#if OPT_XWIN
		static XGFileSpecifier	*OpenDialog(char *tlist);
		static XGFileSpecifier	*SaveDialog(char *ext, char *name);
#endif
		
		/*
		 *	ANSI C File access
		 */
		
		FILE					*OpenFile(const char *access) const;
		
		/*
		 *  High-level operations, return true if successful
		 */
		 
		 static bool			ExchangeFileContents( XGFileSpecifier &file1, XGFileSpecifier &file2 );
		 //static bool			RenameFile( XGFileSpecifier &original, XGFileSpecifier &newname );
		 void					DeleteFile();
		 XGFileSpecifier		TempInSameDirectory();
	 	 static bool			RenameFile(const XGFileSpecifier &file1, const XGFileSpecifier &file2 );
		 

#if OPT_MACOS
		void					SetTypeCreator( OSType type, OSType creator );
		OSType					GetType();
		OSType					GetCreator();
#endif
			// return extension WITHOUT the period
		
		/*
		 *	Internal accessors
		 */
		
#if OPT_MACOS
		const FSSpec			&GetFileName() const
									{
										return fFileName;
									}
#endif

#if OPT_WINOS || OPT_XWIN
		const XGString			&GetFileName() const 
									{
										return fFileName;
									}
#endif

	private:

#if OPT_MACOS
		FSSpec					fFileName;
#else
		XGString				fFileName;
#endif

	friend class XGFile;
	friend class XGDirectory;
};

/************************************************************************/
/*																		*/
/*	File Stream															*/
/*																		*/
/************************************************************************/

/*$	XGFile
 *
 *		This is a file-based file object. This basically provides the
 *	abstractions for the standard file routines provided by Unix,
 *	Windows and MacOS
 */

class XGFile : public XGFileStream {
	public:
								XGFile();
		virtual					~XGFile();
		
		/*
		 *	File open/close routines
		 */
		
#if OPT_MACOS
		virtual void			Open(XGFileSpecifier *, bool rwflag);
		virtual void			Create(XGFileSpecifier *, OSType, OSType);
#endif

#if OPT_WINOS || OPT_XWIN
		virtual void			Open(XGFileSpecifier *, bool rwflag);
		virtual void			Create(XGFileSpecifier *);
#endif

		virtual void			Close();
		
		/*
		 *	File information
		 */
		
		virtual bool			IsOpen() const;
		virtual bool			IsReadWrite() const
									{
										return fRWFlag;
									}
		virtual bool			IsCreateFile() const
									{
										return fCreate;
									}
		virtual void			GetFileName(char *) const;
		virtual void			GetFileExtension(char *) const;

#if OPT_MACOS
		OSType					GetFileCreator()
									{
										return fCreator;
									}
		OSType					GetFileType()
									{
										return fType;
									}
#endif

		const XGFileSpecifier	&GetFileSpecifier()
									{
										return fFileSpec;
									}


		/*
		 *	File I/O routines
		 */
		
		virtual	long			Read(long, void *);
		virtual	long			Write(long, void *);
		virtual void			Flush(void);

		virtual long			GetFilePos();
		virtual void			SetFilePos(long);
		virtual long			GetEOF();
		virtual void			SetEOF(long);
		
	protected:
		virtual void			Initialize();
		virtual void			Terminate();
		
		bool					fCreate;
		bool					fRWFlag;
		XGFileSpecifier			fFileSpec;

	private:
		void					InternalClose();

#if OPT_MACOS
		short					fRefNum;
		OSType					fType;
		OSType					fCreator;
#endif

#if OPT_WINOS
		HANDLE					fRefNum;
#endif

#if OPT_XWIN
		int						fRefNum;
#endif
};

#endif

