#ifndef _NSRAEDWT_ //-*-c++-*-
#define _NSRAEDWT_

//----------------------------------------------------------------------
//  aedWritr.h
//   AEDWriter - writes LogExtentLists to AEDs.
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//
//  CLASSES:
//   AEDWriter
//  
//----------------------------------------------------------------------
// $Source: /projects/HMS/nsr/udfCore/ss/nsrAEDWt.h,v $
// $Revision: 1.4 $     $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/06/21 23:37:49 $

//----------------------------------------------------------------------
//  CLASS:  AEDWriter                           --CSB
//    Writes LogExtentLists to AEDs.
//
//  DATA MEMBERS:
//
//  PUBLIC METHODS:
//
//  NOTES:  (E.g., special cases, heads-up, and algo discussion) 
//
//----------------------------------------------------------------------

class AEDWriter {
    // We have pointers to these lists, because we reference these
    //   lists during the read operations.
    // NOTE: We do NOT manage the memory for these lists, and they
    //   are not ours!  We merely reference the lists past in
    //   for to/fromDisk operations!
    LogExtentList*   metaDataEL_;   
    LogExtentList*   dataEL_;
    LELSpaceResource*   reserveLELSR_;
    ADType           adType_;
    //UINT32           dataLength_;

private:
    // Populate our extent lists (dataEL_, reserveLELSR_, metaDataEL_)
    Error populateELs_(LogExtent& logExtent,
                       ADTable& adTable,
                       UINT32 lenFirstList);
    // Populate the one extent list passed in, appending to metaDataEL_.
    Error populateEL_(LogExtent& logExtent,
                      LogExtentList& list,
                      const UINT64& infoLen, 
                      ADTable& beginADTable,
                      UINT32& currentIndex,
                      AllocExtentDesc& lefotverAED);
    // Although we pass the list into this function, it cannot be static becuase
    //   we are still populating the metaDataEL_ with it.
    Error recursivelyAppendADsToEL_(LogExtent& logExtent, 
                                    LogExtentList& list, 
                                    const UINT64& infoLen,
                                    const ADTable& beginADTable,
                                    UINT32& currentIndex, 
                                    AllocExtentDesc& lefotverAED);

    UINT32 writeOverflowAEDs_(UINT32 adsInFileEntry,
                              UINT32 fileEntryBlock, 
                              SpaceResource& space,
                              Error& err);

    // Populate the entire ADTable (from ADTable index 0 to however many
    //   it is already sized to hold) beginning at the "joinedIndex" specified.
    Error populateADTable_(ADTable& adTable,
                           UINT32 joinedIndex);

    // Set the AD reference passed in to a reference to an overflow
    //   AED.
    void setContinuationAD_(SpaceResource& space,
                            ADTable& adTable, 
                            UINT32 adTableIndex,
                            UINT32 metaDataELIndex,
                            Error& err);

    // Free all the meta-data blocks at this index and after.
    void freeUnusedMetaDataExtents_(SpaceResource& space,
                                    UINT32 numAEDsWritten,
                                    Error& err);
    
    // The following functions are neccessary so we can iterate through our
    //   dataEL_ and reserveLELSR_ as if they were one big EL.  They cannot
    //   be in the same ExtentList, however, because the last extent in the
    //   dataEL_ may not end on a block boundary, and that cannot be internal
    //   to an ExtentList.
    // These iterators are used to write ADs toDisk() (with overflow AEDs).
    // Return the number of ADs in both the dataEL_ and reserveLELSR_.
    UINT32 numDataAndReserveExtents_(void) const;
    // Return the next available sector on the surface that we can use
    //   for metadata.  NOTE:  If we don't have the sector left over from
    //   the read, then we must allocate the sector from the space resource,
    //   assign it to our list, and return that.
    // NOTE:  If the space resource won't give us another extent, then
    //   return NULL.
    LogExtent* getMetaDataBlock_(SpaceResource& space,
                                 UINT32 metaDataELIndex,
                                 Error& err);

    // !!! Nobody calls this anymore.
    //LogExtent* getDataOrReserveLogExtent_(UINT32 joinedIndex, Error& err);


public:
    AEDWriter() {
        metaDataEL_   = NULL;
        dataEL_       = NULL;
        reserveLELSR_    = NULL;
    }
    virtual ~AEDWriter() {}

    // Write the lists to the surface.
    // NOTE: We ASSUME the ADTable adType is set!
    void toDisk( LogExtent& logExtent, 
                 ADTable& adTable,
                 LogExtentList& bodyEL,
                 LELSpaceResource& tailEL,
                 LogExtentList& metaDataEL,
                 SpaceResource & space, 
                 Error & err);

    // NOTE: We ASSUME the ADTable adType is set!
    void fromDisk( LogExtent& logExtent,
                   ADTable& adTable,
                   LogExtentList& bodyEL,
                   UINT64 firstListLen,
                   LELSpaceResource& tailEL,
                   LogExtentList& metaDataEL,
                   Error & err );

    // Confirm none of our members are in an error state.
    Error error(void) const {
        // Make sure none of our data members are in error state.
        Error err;
        if(!(err = metaDataEL_->error()))
            // If we don't have an error.
            if(!(err = dataEL_->error()))
                // If we don't have an error.
                err = reserveLELSR_->error();
        return err;
    }

    String getState(void) {
        String str;
        char buf[80];
        sprintf(buf, "AEDWriter: %x %x %x\n", dataEL_, reserveLELSR_, metaDataEL_);
        str += buf;
        return str;
    }

    void clear(void);
    void print(UINT32 indent, const String & header = "") ;
    void printVerbose(UINT32 indent, const String & header = "") ;
};  // class AEDWriter

#endif
