// ----------------------------------------------------------------------------
//  FILE: ifilesys.hpp
//
//  Core classes for the OpenClass File System Interface
//      IFileSystemEntity   - Base class for any physical file system object
//      IFile               - Represents physical files on the disk
//      IDirectory          - Represents physical directories
//      IVolume             - Represents physical volumes
//      IFileOperation      - Abstract base for file system operations
//      IFileSystemCopier   - Used to copy file system entities
//      IFileSystemMover    - Used to move file system entities
//
//  COPYRIGHT:
//      IBM Open Class Library
//      (C) Copyright International Business Machines Corporation 1997
//      Licensed Material - Program-Property of IBM - All Rights Reserved.
//
// Revision: 59 1.32.1.5 source/core/filesys/ifilesys.hpp, filesystem, ioc.v400, 980918 
// ----------------------------------------------------------------------------

#ifndef _IFILESYS_
#define _IFILESYS_

#include <ibase.hpp>
#include <itext.hpp>
#include <iprimtyp.hpp>

// Streaming support
#include <imstrmbl.hpp>
#include <idatstrm.hpp>

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

//      TypeDefs...
typedef const void *    IFileKind;
typedef IText            IHostPathName;
typedef IText            IFileName;

#ifdef _AIX
typedef long long        IFileSize;        // TODO: use ILongLong!
#else
typedef ILongLong        IFileSize;
#endif

// Forward declarations
class IException;
class IFile;
class IDirectory;
class IVolume;
class IPathName;
class ICompoundNameParser;
class IFSRecord;
class IFSFileRecord;
class IFSDirectoryRecord;
class IFSVolumeRecord;
class ITimeStamp;

#pragma enum(4)
#pragma pack(push,4)

class IFileSystemEntity : public IMSTREAMABLE
{
    StreamableDeclarationsMacro(IFileSystemEntity);
public:
    // A lazy evaluator for a static
    static const IFileName& uniqueName();

    enum ECreateFlags
    {
        kMustExist,
        kCreateIfNeeded,
        kCreateOnly,
        kReplaceExisting
    };

    enum EFailureAction
    {
        kContinue,
        kStop
    };

    static const ICompoundNameParser& defaultParser ();

    IFileSystemEntity(const IPathName &path);

    IFileSystemEntity(const IHostPathName& hostPath,
                        const ICompoundNameParser& = defaultParser());

    IFileSystemEntity ();
    IFileSystemEntity (const IFileSystemEntity& copy);
    virtual ~IFileSystemEntity ();

    virtual IFileSystemEntity& operator=(const IFileSystemEntity& right);

    bool operator==(const IFileSystemEntity& object) const;

    bool operator!=(const IFileSystemEntity& object) const;

    bool valid() const;

    bool connected() const;

    IFileName name()const;

    void setName (const IFileName& newName) const;

    IPathName path() const;

    IHostPathName hostPath(const ICompoundNameParser& parser = defaultParser()) const;

    ITimeStamp modificationTime () const;

    bool temporary() const;

    bool isA(const IFileKind& kind) const;

    IVolume volume() const;

    IDirectory parent() const;

    IDirectory topmostParent() const;

    void moveTo(IDirectory& destination, const IFileName& newName = "",
                EFailureAction action = kStop);

    IFileSystemEntity copyTo(IDirectory &destination, const IFileName& newName = "",
                             EFailureAction action = kStop) const;

    void deleteSelf(bool deleteChildren = false);

    virtual void writeToStream(IDataStream& towhere) const;

    virtual void readFromStream(IDataStream& fromwhere);

    IFileSystemEntity(IFSRecord* Record);
    IFSRecord* getRecord() const;

protected:
    // Subclass Interface...
    void typeSafeAssign(const IFileSystemEntity& right, const IFileKind& kind);

    void setInvalid();

private:
    // Internal functions and data...
    void assertValid() const;
    void invalidRecord() const;

    IFSRecord* fRecord;
};


class IDirectory : public IFileSystemEntity
{
    StreamableDeclarationsMacro(IDirectory);
public:
    static const IFileKind _IMPORT kKind;

    IDirectory();
    IDirectory(const IPathName &path, ECreateFlags flags = kMustExist);
    IDirectory( const IHostPathName &path,
                ECreateFlags flags = kMustExist,
                const ICompoundNameParser& = defaultParser());
    IDirectory(const IDirectory& copy);
    virtual ~IDirectory();
    IDirectory(const IFileSystemEntity& copy);

    IDirectory& operator=(const IFileSystemEntity& right);

    static IDirectory current();
    static void setCurrent(const IDirectory &);

    IFileSystemEntity lookUp(   const IHostPathName& pathOrName,
                                const ICompoundNameParser& = defaultParser()) const;

    IFileSystemEntity lookUp(const IPathName& partialPath) const;

    IDirectory createDirectory(const IFileName& pathOrName,
                               const ICompoundNameParser& = defaultParser());

    IFile createFile(const IFileName& name, IFileSize initialSize = 0,
                     const ICompoundNameParser& = defaultParser());

    void deleteAllContents ();

    static IDirectory createTemporary(const IFileName& dirName = uniqueName());

    // These two member functions are of use only to file system implementations.
    // IFSDirectoryRecord is not declared in a public header file.
    IDirectory(IFSDirectoryRecord* Record);
    IFSDirectoryRecord* getRecord() const;
};


class IVolume : public IDirectory
{
    StreamableDeclarationsMacro(IVolume);
public:
    static const IFileKind _IMPORT kKind;
    IVolume();
    IVolume(const IHostPathName &path, const ICompoundNameParser& = defaultParser());
    IVolume(const IVolume& copy);
    virtual ~IVolume();
    IVolume(const IFileSystemEntity& copy);
    IVolume& operator=(const IFileSystemEntity& right);

    IFileSize freeSpace() const;
    IFileSize totalSpace() const;

    enum EState
    {
        kFalse = 0,
        kUnknown,
        kTrue
    };

    EState online() const;
    EState remote() const;
    EState removable() const;

    // These two member functions are of use only to file system implementations.
    // IFSVolumeRecord is not declared in a public header file.
    IVolume(IFSVolumeRecord* Record);
    IFSVolumeRecord* getRecord() const;
};


class IFile : public IFileSystemEntity
{
    StreamableDeclarationsMacro(IFile);
public:
    static const IFileKind _IMPORT kKind;
    IFile();
    IFile(const IPathName &path, ECreateFlags flags = kMustExist);
    IFile(  const IHostPathName &path,
            ECreateFlags flags = kMustExist,
            const ICompoundNameParser& = defaultParser());
    IFile(const IFile& copy);
    virtual ~IFile();
    IFile(const IFileSystemEntity& copy);

    IFile& operator=(const IFileSystemEntity& right);

    IFileSize size() const;
    void setSize(IFileSize newSize);

    void setModificationTime(const ITimeStamp& modificationTime) const;

    static IFile createTemporary(const IFileName& name = uniqueName(),
                                 const IFileSize initialSize = 0u);


    //
    // We have to use our own seek_dir enum here, because OpenClass libraries
    // are not allowed to depend on the C++ streams library
    //
    enum EOpenMode
    {
        in = 1,
        out = 2,
        ate = 4,
        app = 010,
        trunc = 020
    };

    IDataStream* createStream(  int modeForMe = in + out,
                                int modeForOthers = 0,
                                IDataStream::EStreamEncoding encoding
                                            = IDataStream::kInteroperableBinary);

    // These two member functions are of use only to file system implementations.
    // IFSFileRecord is not declared in a public header file.
    IFile(IFSFileRecord* Record);
    IFSFileRecord* getRecord() const;
};


class IFileOperation
{
public:
    enum EFailureAction
    {
        kContinue,
        kStop
    };

    virtual ~IFileOperation ();

    void setFailureAction(EFailureAction actionOnFailure);

    EFailureAction failureAction() const;

    unsigned int reportFrequency() const;

    virtual bool reportProgress(double fractionDone,
                                const IFileSystemEntity& currentEntity);

    virtual bool renameNeeded(  IFileName& modifyThisName,
                                const IFileSystemEntity& currentEntity);

    virtual bool handleFailure( const IException& reason,
                                const IFileSystemEntity& current);

protected:
    IFileOperation();
    IFileOperation(EFailureAction action, unsigned int tellMeTimes);

    IFileSystemEntity execute(  const IFileSystemEntity& entity,
                                IDirectory &target,
                                const IFileName& newName);

    virtual IFileSystemEntity doOneEntity(  const IFileSystemEntity &entity,
                                            IDirectory &target,
                                            const IFileName &newName) = 0;

    virtual IDirectory doOneDirectory(  const IDirectory &dir,
                                        IDirectory &dest,
                                        const IFileName &newName);

    virtual void postProcess(IFileSystemEntity &source, IFileSystemEntity &result);

private:
    // Disallowed functions...
    IFileOperation(const IFileOperation& copy);
    IFileOperation& operator = (const IFileOperation& right);

    // Internal utilities
    IFileSystemEntity goRecursive(IFileSystemEntity entity,
                                  IDirectory &destination,
                                  const IFileName& newName);

    static IFileSize getTotalSize(const IFileSystemEntity& entity);

    // Private data...
    enum
    {
        kOverhead = 100
    };

    EFailureAction  fFailureAction;
    unsigned int    fTellMeTimes;

    IFileSize       fTotalSize;
    IFileSize       fSizeSoFar;
    IFileSize       fSizeIncrement;
    IFileSize       fNextSize;
};

class IFileSystemCopier : public IFileOperation
{
public:
    IFileSystemCopier(EFailureAction action = kStop, unsigned int tellMeTimes = 0);
    virtual ~IFileSystemCopier ();

    IFileSystemEntity copy( const IFileSystemEntity& source,
                            IDirectory& destination,
                            const IFileName& newName = "");

protected:
    virtual IFileSystemEntity doOneEntity(  const IFileSystemEntity &entity,
                                            IDirectory &destination,
                                            const IFileName &newName);
private:
    // Disallowed functions...
    IFileSystemCopier(const IFileSystemCopier&);
    IFileSystemCopier& operator=(const IFileSystemCopier&);
};

class IFileSystemMover : public IFileOperation
{
public:
    IFileSystemMover(EFailureAction action = kStop, unsigned int tellMeTimes = 0);
    virtual ~IFileSystemMover ();

    IFileSystemEntity move( IFileSystemEntity& source,
                            IDirectory& destination,
                            const IFileName& newName = "");

protected:
    virtual IFileSystemEntity doOneEntity(  const IFileSystemEntity &entity,
                                            IDirectory &destination,
                                            const IFileName &newName);

    virtual void postProcess(IFileSystemEntity &source, IFileSystemEntity &result);

private:
    // Disallowed functions...
    IFileSystemMover(const IFileSystemMover& copy);
    IFileSystemMover& operator=(const IFileSystemMover& right);
};

#pragma pack(pop)
#pragma enum(pop)

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#include <ifilesys.inl>

#endif
