

#ifndef _bytstore_h_
#define _bytstore_h_


/*
 *
 *          Copyright (C) 1995, M. A. Sridhar
 *  
 *
 *     This software is Copyright M. A. Sridhar, 1995. You are free
 *     to copy, modify or distribute this software  as you see fit,
 *     and to use  it  for  any  purpose, provided   this copyright
 *     notice and the following   disclaimer are included  with all
 *     copies.
 *
 *                        DISCLAIMER
 *
 *     The author makes no warranties, either expressed or implied,
 *     with respect  to  this  software, its  quality, performance,
 *     merchantability, or fitness for any particular purpose. This
 *     software is distributed  AS IS.  The  user of this  software
 *     assumes all risks  as to its quality  and performance. In no
 *     event shall the author be liable for any direct, indirect or
 *     consequential damages, even if the  author has been  advised
 *     as to the possibility of such damages.
 *
 */



// ByteStringStore is a   class that  encapsulates a  facility  for
// storing byte strings  of arbitrary sizes into a Binaryfile, via a handle,
// and retrieving them for subsequent use. A user  of this class  can add a new
// byte string to the store, thus obtaining an associated handle (using the
// {\tt Add} method), and later retrieve the byte string by specifying  that
// handle (using the {\tt Retrieve} method). Byte strings currently stored
// in the store may be modified via the {\tt Modify} method; this
// modification can change either the data or the length (or both) of the
// byte string.
//
// The {\tt Add} and {\tt Modify} methods can be given a
// ByteArray as parameter. But the {\tt Retrieve} method must be given a
// ByteString as parameter because {\tt Retrieve} might need to change the
// length of the parameter ByteString.
// 
// Byte strings may be removed from  the store via  the {\tt Remove} method;
// this renders the associated handle invalid.
// 
// This class  also provides two methods,  {\tt ReadHeader}  and {\tt
// WriteHeader}, for manipulating a ``user-defined'' header. A  client of
// this object may store client-specific header information in this header.
// This header is itself a ByteString and therefore need not be of fixed
// length.
//
// It is possible to iterate over all the byte strings in a ByteStringStore
// using the ByteStoreIterator class.



#if defined(__GNUC__)
#pragma interface
#endif


#include "io/iodefs.h"  // Include this first!!!

#include "base/bytstrng.h"
#include "io/slotfile.h"

class YACL_IO CL_ByteStringStore: public CL_Object {


public:

    // ----------------------- Constructors/destructors -----------------

    CL_ByteStringStore (const char* pathName, bool create = FALSE, bool
                       report_errors = TRUE);
    // Construct a ByteStringStore on the file with name {\tt pathName}. For
    // example: \par
    //      {\tt CL_ByteStringStore myData ("/home/yacl/myfile.dat");}
    // \par\noindent
    // If {\tt create} is TRUE, create a new file with the given name,
    // overwriting any 
    // existing one. If {\tt report_errors} is TRUE, then issue error
    // messages through {\tt CL_Error} when I/O errors occur.

    ~CL_ByteStringStore();
    // Destructor: close the ByteStringStore.

    // ------------------------ Storage and retrieval -------------------

    virtual CL_SlottedFileHandle Allocate ();
    // Allocate a handle at which a new ByteString can be stored, and
    // return it.
    
    virtual CL_SlottedFileHandle Add (const CL_ByteArray& data);
    // Add the given byte string {\tt data} into the store after allocating
    // a new handle for it and return the allocated handle. Return 0 on failure
    // (e.g., due to I/O error).

    virtual bool Remove (CL_SlottedFileHandle h);
    // Remove the byte string associated with the handle {\tt h}. Return
    // TRUE on success, FALSE if either the handle was invalid or an I/O
    // error occurred.

    virtual bool Retrieve  (CL_SlottedFileHandle h,
                            CL_ByteString& value) const;
    // Retrieve the byte string associated with the handle {\tt h}
    // and return it {\tt value}. Return TRUE as the
    // function value if successful, FALSE on I/O error or invalid handle.

    virtual bool Modify (CL_SlottedFileHandle h, const CL_ByteArray& b);
    // Modify the byte string associated with handle {\tt h}
    // to be equal {\tt b}.  The length of the second parameter need not
    // bear any relationship to 
    // the length of the byte string currently associated with the given
    // handle.
    // Return TRUE as the function value if successful, FALSE on I/O
    // error or invalid handle.


    // ------------------- Manipulating user headers ------------------

    virtual bool ReadHeader (CL_ByteString& header) const;
    // Read and return the user-defined header in the file. Returns
    // TRUE on success, FALSE on I/O error.

    virtual bool WriteHeader (const CL_ByteString& header);
    // Write the parameter into the user-defined header. The size or
    // contents of the new header need not bear any relationship to the size
    // or contents of the current header. The method returns
    // TRUE on success, FALSE on I/O error. 


    // ---------------------- Basic methods ----------------------------

    const char* ClassName () const { return "CL_ByteStringStore";};

    // ---------------------- End public protocol -------------------

protected:
    CL_SlottedFileHandle _Add    (uchar* data, long data_size);
    
    bool                 _Remove (CL_SlottedFileHandle);
    
    bool                 _Retrieve  (CL_SlottedFileHandle h,
                                     CL_ByteString& value,
                                     CL_SlottedFileHandle& itr_next) const;
    

    class CL_SlottedFile* _file;
    friend class CL_ByteStoreIterator;
    
};



// ByteStoreIterator is meant for iteration over all the ByteStrings in a
// ByteStringStore. Its protocol is similar to other YACL iterators, except
// that it does not include a {\tt More} method, only {\tt Reset} and {\tt
// Next}. The iteration terminates when {\tt Next} returns a zero handle.
// The reason for this design is that the {\tt More} method would require an
// extra I/O operation, so we gain a little efficiency by embedding it in
// the {\tt Next} method instead.

class YACL_IO CL_ByteStoreIterator {

public:
    CL_ByteStoreIterator (const CL_ByteStringStore&);
    // Constructor.

    CL_ByteStoreIterator (const CL_ByteStoreIterator&);
    // Copy constructor.

    // -------------------- Iteration methods -------------------------

    virtual void Reset ();
    // Begin the iteration.
    
    virtual CL_SlottedFileHandle Next (CL_ByteString& value);
    // Return the next ByteString in sequence, in the parameter, and
    // return its handle as the function value. Return 0 when there are no
    // more ByteStrings. The ByteStrings are not returned in any particular
    // order.


protected:
    CL_SlottedFileHandle      _next;
    const CL_ByteStringStore& _store;
    
};


#endif
