//-*-c++-*--------------------------------------------------------------
//  nsrAEDWt.cpp
// This class contains all member functions for the AEDWriter class.
//
//      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.cpp,v $
// $Revision: 1.6 $     $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/06/21 23:37:11 $
//

#include "nsrLib.h"

//----------------------------------------------------------------------
// METHOD: AEDWriter::print()                                   --CSB
//
//  Prints out the state of the AEDWriter.
//
// ARGS:
//  indent                  IN      Number of spaces to indent
//  header                  IN      String to print as a header title
//
// RETURNS:
//  void
// 
// PRE-CONDITIONS:
//  0 <= indent < 160
// 
// POST-CONDITIONS:
//  none
// 
// ERRORS:
// 
// NOTES:
//
//  User should use getState(), and this function should be removed
//  in the future.
//
//----------------------------------------------------------------------
void 
NSR::AEDWriter::print(UINT32 indent, const String & header) {

    // Indent.
    for(UINT32 i=0; i<indent; i++)
        printf(" ");

    printf("%s: %s\n", (const CHAR_PTR) header, (const CHAR_PTR) getState());

} // AEDWriter::print()


//----------------------------------------------------------------------
// METHOD: AEDWriter::printVerbose()                            --CSB
//
//  Prints out the state of the AEDWriter.
//
// ARGS:
//  indent                  IN      Number of spaces to indent
//  header                  IN      String to print as a header title
//
// RETURNS:
//  void
// 
// PRE-CONDITIONS:
//  0 <= indent < 160
// 
// POST-CONDITIONS:
//  none
// 
// ERRORS:
// 
// NOTES:
//  User should use getState(), and this function should be removed
//  in the future.
//----------------------------------------------------------------------
void 
NSR::AEDWriter::printVerbose(UINT32 indent,
                             const String & header) {

    CHAR_PTR ind = (CHAR_PTR) NSR::space(indent);               // cast to CHAR_PTR

    // Indent.
    for(UINT32 i=0; i<indent; i++)
        printf(" ");

    printf("%s: %s\n", (const CHAR_PTR) header, (const CHAR_PTR) getState());

} // AEDWriter::printVerbose()

//----------------------------------------------------------------------
// METHOD: AEDWriter::populateADsFromFileEntry()                   --CSB
//    
//  This is a protected member function that reads in the chain of ADs
//    from the FileEntry passed in.  (This function is for internal use only, a
//    necessary support function for the fromDisk() operation).
//
//  If the FileEntry passed in contains ADs that are overflowed to AEDs, then
//    we continue reading in those overflowed AEDs until we have read in all
//    parts of this Node.  
//
//  We begin with the FileEntry passed in, and iterate through additional
//    AED ADTables until we have finished reading in all overflowed ADs.
//
//  ARGS:
//  logExtent   IN  The one-block extent on the surface where this FileEntry
//                  is located (but we use this to know the blockSize(), and
//                  to know where the fileEntry is located--we don't read
//                  from the surface.
//  fileEntry   IN  The FileEntry we read state from.
//
//  RETURNS:
//  error_None on success, specific error on failure.
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
//  This function re-sets all the ExtentLists for the file body and file tail
//    for the AEDWriter.  We populate ourselves specifically with the AD chain
//    that begins in this FileEntry.
// 
// ERRORS:
//   error_None on success
//   error_NODE_InfoLen_mismatch  (the infoLen field in the FileEntry
//     does not match the infoLen read in).
//   error_NODE_LogBlocksRecorded_mismatch  (the logicalBlocksRecorded
//     field in the FileEntry does not match the number of logical
//     blocks read in.)  NOTE:  This error is set if the infoLen
//     matches, but the number of logical blocks recorded does not
//     match the descriptor.  If we came up short on infoLen (even though
//     the number of logical blocks recorded is also incorrect), that
//     error is returned instead of this one.
// 
// NOTES:
//  This function continues to read overflow AEDs from the surface until
//  we have read all of the overflowed ADs!  (Of course, it stops on
//  a terminating AD or when there are no more references to additional
//  AEDs).
//----------------------------------------------------------------------
NSR::Error 
NSR::AEDWriter::populateELs_( LogExtent& logExtent,
                              ADTable& adTable,
                              UINT32 lenFirstList)
{
    Error err = error_None;  // By default, no error.

    // Confirm we have a valid ADTable with ADs.
    if(adTable.error()) {
        err = error_Bad_Parameter_ADTable;  
    } else {
        // Work with the adTable.

        // Confirm we have ADs (not embedded data).
        if((adTable.adType() == ad_Embedded) ||
           (adTable.adType() == ad_Unknown)) {
            // We have embedded data or unknown ADs.
            err = error_Bad_Parameter_File_Entry;
        } else {

            // We don't have embedded data or unknown types of ADs (we should
            //   have short, long, or extended ADs).
            if (Trace::logAlgorithms()) {
                printf("We do have ADs.\n");
            }

            // First, populate the file body (the dataEL_).
            // NOTE: We want to start on the first AD (index zero) and 
            //   continue until lenFirstList.
            AllocExtentDesc leftoverAED(0, adTable.adType());
            UINT32 currentIndex = 0;

            // Clear the logical extents that we reserve as available for a later
            //   write.
            metaDataEL_->clear();

            if(adTable.numADs() == 0) {
                // If we have no ADs to populate.
                // Clear the data and reserve extent lists, because our old ADs
                //   no longer apply. (We are populating these lists from an
                //   empty table).
                dataEL_->clear();
                reserveLELSR_->clear();
            } else {
                // We have ADs to populate.

                // NOTE:  We only need to populate our lists if there are ADs
                //   in the adTable.
                err = populateEL_(logExtent, *dataEL_, 
                                  (const UINT64) lenFirstList,
                                  adTable, 
                                  currentIndex, 
                                  leftoverAED);

                if (Trace::logAlgorithms()) {
                    printf("We have populated the dataEL_: it has %d logExtents, infoLen is %d.\n", dataEL_->numLogExtents(), dataEL_->infoLen());
                }

                if(!err) {
                    // If we could populate the dataEL_ we should now populate the tail 
                    //   (the reserveLELSR_).

                    if(dataEL_->numExtents() < adTable.numADs()) {
                        // If we populated all our dataEL_ entries from the adTable,
                        // and there are still more entries in the adTable, then
                        // pass that entry in.
                        if (Trace::logAlgorithms()) {
                            printf("Trying to populate reserve from the adTable.\n");
                        }
                        // Populate a reserveEL, and then put that in the reserveLELSR_.
                        LogExtentList reserveEL(*logExtent.logVolumep());
                        err = populateEL_(logExtent, reserveEL,  MAX_UINT64, 
                                          adTable, currentIndex, leftoverAED);
                        // ISSUE: Bug: Needs to check err between calls
                        reserveLELSR_->putLogExtentList(reserveEL, err);
                    } else if( currentIndex < leftoverAED.adTable().numADs()) {
                        // We extracted all the ADs from the adTable, and are continuing 
                        // with the ADs in the leftover AED only IF there are additional
                        //   ADs in the return table.
                        if (Trace::logAlgorithms()) {
                            printf("Trying to populate reserve from the leftoverAED.adTable().\n");
                        }
                        // Populate a reserveEL, and then put that in the reserveLELSR_.
                        LogExtentList reserveEL(*logExtent.logVolumep());
                        err = populateEL_(logExtent, reserveEL,  MAX_UINT64, 
                                          leftoverAED.adTable(), currentIndex, leftoverAED); 
                        // ISSUE: Bug: Needs to check err between calls
                        reserveLELSR_->putLogExtentList(reserveEL,err);
                    } else {
                        if (Trace::logAlgorithms()) {
                            printf("We have no tail.\n");
                        }
                        // Just zero out our tail, because we don't have one.
                        reserveLELSR_->clear();
                    }
  
                    // NOTE:  Because we asked for infinity on the reserveLELSR_, an 
                    //  error of "length mismatch" doesn't mean anything.  Ignore it.
                    if(err == error_NODE_InfoLen_mismatch) {
                        // Not a problem.
                        err = error_None;
                    }

                    if (Trace::logAlgorithms()) {
                        printf("We have populated the reserveLELSR_: it has %d logExtents, infoLen is %d.\n",
                               reserveLELSR_->numLogExtents(),
                               reserveLELSR_->availBytes()); 

                        printf("currentIndex: %d, leftover num: %d\n", currentIndex,
                               leftoverAED.numADTEnts());
                    }
                }
            }
        }
    }
    return err;
}

//----------------------------------------------------------------------
// METHOD: AEDWriter::populateEL_()                             --CSB
//
// Erase the list passed in and populate it with all new ADs (extents)
//   beginning with this table and the AD offset passed in.
// Modify the offset to be the last AD we read from the table.
// If we read "infoLen" worth of bytes, we should stop.  If we don't
//   exactly stop on an AD boundary, then we have an error 
//   (error_NODE_InfoLen_mismatch).
//
// ARGS:
//  LogExtent& logExtent          IN     The extent from which the FileEntry
//                                       descriptor was read.  (Used for blockSize())
//  LogExtentList& list           IN/OUT The list to be populated (if all parameters
//                                       are not in an error state, this list is
//                                       first erased with clear().
//  const UINT64& infoLen         IN     Specifies the break condition for the
//                                       desired amount of information.  This is
//                                       NOT merely the maximum:  an error is
//                                       returned unless this number is hit exactly.
//  ADTable& beginADTable         IN/OUT The table from which we start populating
//                                       the extent list.
//  UINT32& currentIndex          IN/OUT Passed in as the index into the beginADTable
//                                       that we start from (indices less than this
//                                       value are not added to the list), and returned
//                                       as the index to the next AD value to be
//                                       read (the next un-read AD).  The return
//                                       value could refer to the beginADTable, or
//                                       may reference an AD in the leftoverAED.
//                                       The caller can determine which table to
//                                       inspect, because the list returned will
//                                       have numLogExtents() greater or less than
//                                       the number of ADs in the beginADTable.  (If
//                                       the list has more than the initial value
//                                       of the currentIndex to the end of the 
//                                       beginADTable, then it must reference the
//                                       leftoverAED.)
//  AllocExtentDesc& leftoverAED  OUT    This is a reference to an AED that is
//                                       ignored if we reach infoLen or if no AED
//                                       reference exists among the accessed ADs 
//                                       in the ADTable passed in.  Should we
//                                       continue reading on an overflow AED, this
//                                       AED is populated with the information from
//                                       the surface repeatedly across an arbitrary
//                                       number of succeeding AEDs.  Upon return from
//                                       this call, this parameter has the state of
//                                       the last AED read from the surface, and the
//                                       next un-read AD is identified by the return
//                                       value of the currentIndex parameter.
//
// RETURNS:
//  error_None on success.
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
// 
// NOTES:
//  This function continues reading AEDs from the surface into the 
//  leftoverAED paraemter, until there are no more.
//
//----------------------------------------------------------------------
NSR::Error 
NSR::AEDWriter::populateEL_(LogExtent& logExtent,
                            LogExtentList& list,
                            const UINT64& infoLen,
                            ADTable& beginADTable, 
                            UINT32& currentIndex,
                            AllocExtentDesc& leftoverAED)
{
    Error err;
    // We need to iterate across additional ADTables in AEDs, if we
    //   encounter a reference to an overflow AED.
    // First, erase our current dataEL_->
    list.clear();

    if (Trace::logAlgorithms()) {
        printf("Enter populateEL_, beginADTable has %d, currentIndex is %d, infoLen is %u.\n",
               beginADTable.numADs(), currentIndex, infoLen);
    }

    // Now, begin at the offset specified and read in ADs.  Add each AD
    //   to the list.  Stop at the end of the list, the end of the field,
    //   or at an AD with a length of zero:
    err = recursivelyAppendADsToEL_(logExtent, list, infoLen, beginADTable,
                                    currentIndex, leftoverAED);

    // At this point, we appended everything to the list.  If we failed, that
    //   is set as an error.  we are done.
    return err;
}

//----------------------------------------------------------------------
// METHOD: AEDWriter::recursivelyAppendADsToEL_()               --CSB
//
// This function appends ADs to the LogExtentList passed in, starting at the
//   ADTable entry "currentIndex", and continuing to the end of the ADTable.
// The append process STOPS UNDER THE FOLLOWING CONDITIONS:
//   1.  The LogExtentList exactly reaches "infoLen" in length.  We set the 
//       currentIndex to be the next AD AFTER the last AD we appended to the 
//       list.
//         (error = error_None)
//   2.  The LogExtentList exceeds "infoLen" in length after an AD is appended.
//       Because the AD list should have EXACTLY matched infoLen, we set
//       this as an error.
//         (error = "error_NODE_InfoLen_mismatch").
//   3.  There are no more ADs to append.  (We either read all of the ADTable
//       and there are no more, or we read an AD whose ExtentLength is zero,
//       terminating the AD chain.)  In this case, since the ExtentList.infoLen()
//       does not equal infoLen, we set an error.
//         (error = "error_NODE_LogBlocksRecorded_mismatch")
// Until we reach cases (1-3) defined above, we continue reading AD entries from
//   the ADTable and append them to the LogExtentList.  If the last AD entry
//   is an indirect reference to another AED (with its own ADTable of additional
//   (overflowed) ADs, then we create an AED and call ourselves recursively with
//   that table.
// NOTE:  In this recursive calling process, we must instantiate the AED.  Further,
//   we must track the space set aside for this AED meta-data in the AEDWriters class,
//   because this is available space on the surface for when we later write this
//   AEDWriter back out to the surface.
// !!! MS ISSUE!
//   For Multiple Surfaces, we should confirm that this previously allocated AED
//   space that we intend to re-use for a later AEDWriter write is actually available
//   on the surface we later write to.  For example, if the user reads off one
//   disk, we will track available sectors for AED info on a later write.  However,
//   if the user want us to write to a different disk (a different surface), then
//   we should recognize the "available AED space" we tracked from the read does
//   NOT apply to this other disk.  (This is not an issue for Single Surface where
//   there is only one disk, but only for multiple surfaces where the user may
//   switch disks).
//
// ARGS:
//  LogExtent& logExtent          IN     The extent from which the FileEntry
//                                       descriptor was read.  (Used for blockSize())
//  LogExtentList& list           IN/OUT The list to be populated (if all parameters
//                                       are not in an error state, this list is
//                                       first erased with clear().
//  const UINT64& infoLen         IN     Specifies the break condition for the
//                                       desired amount of information.  This is
//                                       NOT merely the maximum:  an error is
//                                       returned unless this number is hit exactly.
//  ADTable& beginADTable         IN/OUT The table from which we start populating
//                                       the extent list.
//  UINT32& currentIndex          IN/OUT Passed in as the index into the beginADTable
//                                       that we start from (indices less than this
//                                       value are not added to the list), and returned
//                                       as the index to the next AD value to be
//                                       read (the next un-read AD).  The return
//                                       value could refer to the beginADTable, or
//                                       may reference an AD in the leftoverAED.
//                                       The caller can determine which table to
//                                       inspect, because the list returned will
//                                       have numLogExtents() greater or less than
//                                       the number of ADs in the beginADTable.  (If
//                                       the list has more than the initial value
//                                       of the currentIndex to the end of the 
//                                       beginADTable, then it must reference the
//                                       leftoverAED.)
//  AllocExtentDesc& leftoverAED  OUT    This is a reference to an AED that is
//                                       ignored if we reach infoLen or if no AED
//                                       reference exists among the accessed ADs 
//                                       in the ADTable passed in.  Should we
//                                       continue reading on an overflow AED, this
//                                       AED is populated with the information from
//                                       the surface repeatedly across an arbitrary
//                                       number of succeeding AEDs.  Upon return from
//                                       this call, this parameter has the state of
//                                       the last AED read from the surface, and the
//                                       next un-read AD is identified by the return
//                                       value of the currentIndex parameter.
//
//
// RETURNS:
//  error_None on success
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
// 
// NOTES:
//
//----------------------------------------------------------------------
NSR::Error 
NSR::AEDWriter::recursivelyAppendADsToEL_(LogExtent& logExtent,
                                          LogExtentList& list, 
                                          const UINT64& infoLen, 
                                          const ADTable& beginADTable,
                                          UINT32& currentIndex,
                                          AllocExtentDesc& leftoverAED)
{
    Error err = error_None;  // By default, all is ok.

    if (Trace::logAlgorithms()) {
        printf("Enter AEDWriter::recursivelyAppendADsToEL_().\n");
        printf("  List has %d items, infoLen %d; We want infoLen %d;\n",
               list.numLogExtents(), list.infoLen(), infoLen);
        printf("  Current index in ADTable is %d; ADTable has %d ADs.\n",
               currentIndex, beginADTable.numADs());
    }

    if(list.error()) {
        // If the list parameter is in error, we can't do anything,
        err = error_Bad_Parameter_Extent_List;
    } else if(beginADTable.error()) {
        // If the ADTable is in an error state.
        err = error_Bad_Parameter_ADTable;
    }
    if(!(currentIndex < (beginADTable.numADs() ))) {
        // If we are not starting inside this beginADTable.  What are we supposed
        //   to do?  We don't have a handle (reference) to an AED, so
        //   we are stuck.
        if (Trace::logAlgorithms()) {
            printf("We are not inside the ADTable!!\n");
        }
        err = error_NODE_InfoLen_mismatch;
    } else {
        // We are starting inside this beginADTable.
        if (Trace::logAlgorithms()) {
            printf("Before starting, the list has infoLen %d, and we need infoLen %u.\n",
                   list.infoLen(), infoLen);
        }
        // Append to the list passed in from the ADTable passed in.
        ADTableStopCondition stopCondition;
        stopCondition = 
            beginADTable.appendToLogExtentList(logExtent.partitionp(), 
                                               list, infoLen, currentIndex, err);
        if(! err) {
            // If we were able to read from the beginADTable without error, see
            //   if we are done.
            if (Trace::logAlgorithms()) {
                printf("After populating, the list has infoLen %d, and we needed infoLen %u.\n",
                       list.infoLen(), infoLen);
            }
            if(list.infoLen() < infoLen) {
                // If we still need to read more, then the next AD must refer to
                // an AED.

                // RECALL: The "currentIndex" is modified when we
                // appended to the list from the ADTable, and now
                // refers to the next AD to read!

                if(currentIndex == beginADTable.numADs()) {
                    // If there are no more ADs.
                    // This is an error because we want more data but
                    // there are no more ADs.
                    err = error_NODE_InfoLen_mismatch;
                    if (Trace::logAlgorithms()) {
                        printf("We read all the ADs, but it wasn't enough!!\n");
                    }
                } else { 
                    // There are more ADs.  The next AD in the
                    // beginADTable is either a continuation reference
                    // or a termination AD.  Because we still need
                    // more ADs in our LogExtentList to reach infoLen,
                    // it should not be a termination AD. 

                    if(stopCondition == NSR::ad_Continuation) {
                        // If this AD is a reference to an AED.
                        // Read in the next AED, and call ourselves recursively to
                        // append more ADs to our list.
                        if (Trace::logAlgorithms()) {
                            printf("This last AD is a reference to an AED!\n");
                        }
                        // Make a one-sector sized array to handle the AED read from 
                        // the surface.
                        // The length in bytes.
                        ByteArray buffer(logExtent.blockSize());

                        // Make a 1-sector sized LogExtent for the AED on the surface.
                        LogExtent aedExtent;

                        beginADTable.getContinuationLogExtent(logExtent.partitionp(),
                                                              aedExtent,
                                                              currentIndex,
                                                              err); 
                        if(err) { 
                            // We could not populate the LogExtent.
                            if (Trace::logAlgorithms()) {
                                printf("HEY!!!!! COULD NOT POPULATE THE LOGEXTENT!\n");
                            }

                        } else {
                            // Read the AED from the surface.
                            if (Trace::logAlgorithms()) {
                                aedExtent.print(2, "+++++++++++++++++Before aedExtent.read()");
                            }
                            INT32   bytesRead;
                            bytesRead = aedExtent.read( buffer, err );
                        }

                        if(err){
                            // We could not read the AED extent.
                            if (Trace::logAlgorithms()) {
                                aedExtent.print(2, "After unsuccessful aedExtent.read()");
                                printf("Could not read the AED from the surface!! [%d], %s\n", 
                                       (UINT32)err, err.message());
                            }
                            //err = error_NODE_AED_Read_Failure;
                        } else{
                            // We had no problem reading the AED from the surface.
              
                            // NOTE:  We must track this sector that
                            //   we read an AED in from, because this
                            //   sector has been allocated for file
                            //   meta-data,and we should re-use that
                            //   sector on a later AEDWriter::toDisk()
                            //   if it is needed (or freed later
                            //   also).
                            // NOTE:  We ONLY append AED sectors to
                            //   this list!  These are the AEDs that
                            //   we create here, locally!  We do not
                            //   track the fileEntry descriptor
                            //   because that was not created and read
                            //   in locallin from this function!
                            //   (This is the way we want it, because
                            //   the fileEntry logicalExtent is 
                            //   allocated and managed by the user.
                            if (Trace::logAlgorithms()) {
                                aedExtent.print(2, "After successful aedExtent.read()");
                                printf("Read the AED from the surface at block %d, appending metaData block (available on write).\n",
                                       aedExtent.startBlock());
                                printf("*******  WE ARE APPENDING BLOCK %d TO OUR META DATA LIST!  **********\n", 
                                       aedExtent.startBlock());
                            }
                            metaDataEL_->append(aedExtent, err);

                            if(!err) {
                                // If we had no problems appending the
                                // metadata space to the list. Create
                                // a new AED to populate from the
                                // surface.

                                // Re-size the (empty) AED passed in
                                // by reading it from the buffer.
                                // !!! THIS IS ALREADY THE CORRECT
                                // TYPE, RIGHT!?
                                // Args:
                                //  Our buffer
                                //  We start at the beginning of the sector
                                //  The sector we came from (validation)
                                leftoverAED.fromISO(buffer, 0,
                                                    aedExtent.startBlock());

                                err =  leftoverAED.error();
                                if (Trace::logAlgorithms()) {
                                    printf("We did leftoverAED.fromISO()\n:");
                                    printf(" startblock was %d, buffer was %d, error is [%d] %s.\n", 
                                           aedExtent.startBlock(),
                                           buffer.length(),
                                           (UINT32)err,
                                           err.message()); 
                                    leftoverAED.dump("after AED::fromISO()");
                                }
                                if(!err) {
                                    // If we did not have a problem
                                    // reading from the buffer. 
  
                                    // If we read correctly, then we
                                    // can assume that this AED holds
                                    // ADs of the same ADType as we
                                    // are reading in (because that's
                                    // what it read, we specified the
                                    // ADTypein the AED constructor).
                                    // !!! HOW DO WE KNOW IF WE ARE ON
                                    // THE SAME PARTITION OR NOT?
                                    // EACH EXTENT KNOWS ITS
                                    // PARTITION, BUT WE HAVE AN AED
                                    // WITH A BUNCH OF ADs, AND NO
                                    // EXTENT REFERENCE! 
                                    // (This is an issue for
                                    // multi-surface.)
    
                                    // Call ourselves with the new table.

                                    // NOTE:  We pass down the ADTable
                                    //   inside the leftoverAED, because
                                    //   this table has ADs that we
                                    //   append to the list.  However,
                                    //   we also pass down the
                                    //   leftoverAED to be modified by
                                    //   a recursivecall, because we
                                    //   have NO NEED to track an AED
                                    //   once it has been emptied of
                                    //   its ADs (so we overwrite the
                                    //   leftoverAED with each
                                    //   recursive call).

                                    // NOTE: Because we are starting
                                    // to populate from a new ADTable,
                                    // we must reset the currentIndex
                                    // to zero (start at the beginning
                                    // of the table.)
                                    currentIndex = 0;
                                    if (Trace::logAlgorithms()) {
                                        printf("Making the recursive call:  infoLen is %d, currentIndex is %d.\n", 
                                               infoLen, currentIndex);
                                        leftoverAED.adTable().dump("New AED table");
                                    }

                                    // Because we don't want to store
                                    // all those buffers on the stack,
                                    // clear our the buffer before the
                                    // recursive call.  (Optimization
                                    // only). 
                                    buffer.clear();

                                    err =
                                        recursivelyAppendADsToEL_(logExtent,
                                                                  list, 
                                                                  infoLen,
                                                                  leftoverAED.adTable(), 
                                                                  currentIndex,
                                                                  leftoverAED);
                                }
                            }
                        }
                    } else if(stopCondition == NSR::ad_Terminating) {
                        // If this descriptor is a terminating descriptor.  
                        // Since we cannot get all the information to 
                        // reach infoLen in our LogExtentList, then
                        // we have a logical error.
                        err = error_NODE_InfoLen_mismatch;
                    } else {
                        // This descriptor is not continued, and is
                        // not terminated. We have reached a logical
                        // problem (the
                        // LogExtentList::appendFromADTable() should
                        // have read it!
                        // !!! LOGICAL ERROR!
                        if (Trace::logAlgorithms()) {
                            printf("LOGICAL ERROR! in recursivelyAppendADsToEL()! \n");
                        }
                        err = error_NODE_InfoLen_mismatch;
                    }
                }       
            }
        }
    }
    return err;  // Return our status.
}

//----------------------------------------------------------------------
// METHOD: AEDWriter::writeOverflowAEDs_()                              --CSB
//
//  This function writes all "overflow" ADs to disk in AED blocks,
//    less any ADs that fit in the FileEntry (that number passed in).  
//    Additional blocks on the surface are allocated from the SpaceResource 
//    as needed, and are appended to our internal list metaDataEL_->
//
// ARGS:
//
//  UINT32 adsInFileEntry   IN      The number of ADs in the fileEntry (so
//                                  we don't have to write them out).
//  UINT32 fileEntryBlock   IN      The sector address on the surface where
//                                  the FileEntry is located (the first AED
//                                  must reference back to the FileEntry.)
//  SpaceResource& space    IN/OUT  The resource we take/put sectors sectors
//                                  to for metaData.
//  Error err               IN/OUT  The error to set.
//
// RETURNS:
//
//    UINT32, the number of AED blocks written out.
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
// 
// NOTES:
//
//----------------------------------------------------------------------
NSR::UINT32
NSR::AEDWriter::writeOverflowAEDs_(UINT32 adsInFileEntry,
                                   UINT32 fileEntryBlock, 
                                   SpaceResource& space,
                                   Error& err)
{
    UINT32 numAEDsWritten = 0;
    // Track the address of the last block (the block referencing the
    // next AED to be written).  This is so we can recover AED information
    // if we find a rogue AED block (we will know who should have referred
    // to it.)
    UINT32 previousBlock = fileEntryBlock; 

    err = error_None;

    // Verify our parameters are ok.
    if(space.error()) {
        // If our space resource is in an error state.
        err = error_Bad_Parameter_Space_Resource;
    } else {
        // Ok parameter states.
        UINT32 numADsWritten = adsInFileEntry;
        UINT32 numDataAndReserveADs = numDataAndReserveExtents_();
        UINT32 numADsThisAED;
        UINT16 referenceAD=0;

        // Create an AED.
        AllocExtentDesc aed(1, adType_);

        // How many ADs can fit in one AED?
        UINT32 maxADsPerTable = aed.maxADTEnts(space.blockSize(), adType_);

        // Do we have any additional ADs to write out?
        while((numADsWritten < numDataAndReserveADs) && (!err)) {
            // While we have more ADs than we have written and we didn't incur 
            //  an error on the last AED write.

            if((numADsWritten + maxADsPerTable) < numDataAndReserveADs) {
                // If we are not going to write all the ADs this time.
                numADsThisAED = maxADsPerTable;
                referenceAD = 1;  // We reserve the last AD for AED reference.
            } else {
                // We can finish the ADs with this AED.
                numADsThisAED = numDataAndReserveADs - numADsWritten;
                referenceAD = 0;
            }

            // Grow the ADTable to the correct size.
            // DON'T DO THIS:
            // aed.adTable().fitEnts(numADsThisAED, adType_);
            // INSTEAD, DO THIS:
            if (Trace::logAlgorithms()) {
                printf("Resizing AED to fitEnts(%d) (wrote %d of %d).\n",
                       numADsThisAED,
                       numADsWritten,
                       numDataAndReserveADs);
            }
            aed.numADTEnts(space.blockSize(), numADsThisAED, adType_);

            // Now, record the location for the previous block (the FileEntry
            // or AED that references this AED as the next in the chain.)
            aed.prevAllocExtentLoc = previousBlock;

            // Write this batch of ADs to this table.
            if(err = populateADTable_(aed.adTable(), numADsWritten)) {
                // Error.
                if (Trace::logAlgorithms()) {
                    printf("Error from populating the ADTable: %d, %s.\n",
                           (UINT32)err, err.message());
                }
            } else {
                // We successfully populated the ADTable.
      
                // If the last AD is reserved as a reference, set it.
                if(referenceAD) {
                    setContinuationAD_(space, 
                                       aed.adTable(),
                                       numADsThisAED-1, // The last AD in the table.
                                       numAEDsWritten +1, // Meta data extent.
                                       err);  // Refer to the next AED.

                    if (Trace::logAlgorithms()) {
                        printf("We set the AED reference to the next AED in the chain (next AED at %d).\n",
                               numAEDsWritten+1);
                    }
                }

                if(!err) {
                    // If we could set this reference.
                    // Write this aed to disk.
                    // NOTE:  We are writing AEDs!  We are responsible for
                    // allocating the block for this AED!
                    ByteArray buffer(space.blockSize()); 
                    if (Trace::logAlgorithms()) {
                        printf("About to set up the metaDataBlock for the overflow AED.\n");
                    }
                    // Get the logExtent where we write out this AED.
                    LogExtent *aedExtent = getMetaDataBlock_(space, numAEDsWritten, err);
                    if(aedExtent && (!err)) {
                        // If we have our extent and don't have an error.
                        if (Trace::logAlgorithms()) {
                            printf("...............AED to be written at block %d.\n",
                                   aedExtent->startBlock());
                            aed.dump("before AED::toISO()");
                        }

                        aed.toISO( buffer, aedExtent->startBlock());
                        if (Trace::logAlgorithms()) {
                            printf("Wrote AED at block %d\n",
                                   aedExtent->startBlock());
                            aed.adTable().dump("After AED::toISO()");
                        }
                        if(! (err = aed.error())) {
                            // If we could write to the block.
                            aedExtent->write( buffer , err);
    
                            // The AED is written.  If there was an error, err is set.
                            numAEDsWritten++;  // We wrote one more.
                            // NOTE:  We don't count the reference AD as an AD to be
                            //   written, if we wrote one.
                            numADsWritten += numADsThisAED - referenceAD;
                            // Track the previously written block for the next AED.
                            previousBlock = aedExtent->startBlock();
                        }
                    }
                }
            }
        }
    }
    if (Trace::logAlgorithms()) {
        printf("We wrote %d overflow AEDs.\n",
               numAEDsWritten);
    }
    return numAEDsWritten;
}

//----------------------------------------------------------------------
// METHOD: AEDWriter::populateADTable()                                 --CSB
//
//  Populate the entire ADTable, always starting at ADTable index 0
//  and for all of the ADTable, beginning at our joined index specified.
//  We stop populating only after all ADTable entries are set or if
//  we run out of LogExtents between our dataEL_ and reserveLELSR_->
//
//  NOTE:  The joinedIndex refers to the absolute joinedIndex across 
//  a conceptually concatenated dataEL_ and reserveLELSR_ list!  The 
//  joinedIndex has nothing to do with the ADTable being populated!  
//  The ADTable always starts being populated at index 0, and up to 
//  as many ADs as the ADTable is able to hold (unless we run out of
//  LogExtents).
//
//  In the case that we want the last AD to be a reference to an overflow
//  AED, we will have to manually overwrite the last one.  (Of course,
//  that's done by the caller after we are completed.  The caller over-
//  writes the last one we insert).
//
//  NOTE:  In the event that ALL the ADs fit into the table, but
//    we STILL have ADTable entries available, we append a terminating
//    AD to the end!  (An AD of length zero).  If the caller doesn't
//    like that, the caller can overwrite that too.  Otherwise, the
//    caller doesn't have to worry about shrinking an ADTable smaller
//    just because there aren't enough ADs to fill the table.  (The
//    terminating AD just ensures we have a good logical terminator
//    in the table).
//
// ARGS:
//  ADTable& adTabel   IN/OUT  The table to be populated (must already
//                             be resized).
//  UINT32 joinedIndex IN      The index to the first LogExtent we use
//                             to populate the ADTable.  This index is
//                             the absolute index across the virtual
//                             joined LogExtentList dataEL_ and
//                             reserveLELSR_-> 
//
// RETURNS:
//  error_None on success.
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
// 
// NOTES:
//
//----------------------------------------------------------------------
NSR::Error 
NSR::AEDWriter::populateADTable_(ADTable& adTable,
                                 UINT32 joinedIndex)
{
    Error err = error_None;
    UINT32 origJoinedIndex = joinedIndex;

    if (Trace::logAlgorithms()) {
        printf("Populating ADTable starting at joinedIndex %d.\n",
               joinedIndex);
    }

    if(adTable.error()) {
        err = error_Bad_Parameter_ADTable;
    }
    else {
        // Populate the ADTable from the body, if any of these are in the
        //   body.
        if(joinedIndex < dataEL_->numLogExtents()) { 
            // If we must populate some from the dataEL_->
    
            adTable.fromLogExtentList(*dataEL_, 
                                      joinedIndex, 
                                      0,    // Always fill the whole ADTable.
                                      err);
    
            if(err) {
                // If we could not populate the ADTable from the dataEL_->
                if (Trace::logAlgorithms()) {
                    printf("Could not populate ADTable dataEL_: %d, %s.\n", 
                           (UINT32) err, err.message());
                }
            }
        }
    
        UINT32 totalNumWritten = joinedIndex - origJoinedIndex;

        // We wrote out the body.  See if we must also write out the reserveLELSR_.
        if(!err && (totalNumWritten < adTable.numADs())) {
            // If we did not have errors on writing the dataEL_ and the
            // ADTable can hold more ADs.
            // We make this local variable to suppress a compiler warning,
            //   because fromLogExtentList() takes it as a reference.
            // Make the joined index relative to the reserveLELSR_ (after the 
            //   dataEL_).
            UINT32 currentListIndex = joinedIndex - dataEL_->numLogExtents();
    
            // Write out from the tail.
            adTable.fromLogExtentList(*reserveLELSR_, 
                                      currentListIndex,
                                      totalNumWritten,
                                      err);
            if(err) {
                // If we could not populate the ADTable from the dataEL_->
                if (Trace::logAlgorithms()) {
                    printf("Could not populate ADTable dataEL_: %d, %s.\n", 
                           (UINT32) err, err.message());
                }
            }
        }

        // Calculate how many we wrote to this ADTable from both lists.
        totalNumWritten = numDataAndReserveExtents_() - origJoinedIndex;

        // At this point, we filled the adTable from the body and the
        //   tail, as much as we could.  Check to see if there is still
        //   room in the adTable (If so, we should write out a terminating
        //   AD.)

        if(totalNumWritten < adTable.numADs()) { 
            // If we have at least ONE more entry in this ADTable that
            //   is available, write out a terminating AD.
            adTable.setTerminator(totalNumWritten, err);
            // Done. We set our terminator.
        }
    }
    if (Trace::logAlgorithms()) {
        printf("Leaving populateEL_(): err %d, %s\n",
               (UINT32)err, err.message()); 
    }
    return err;
}

// Return the total number of extents in the data and reserve extent lists.
NSR::UINT32
NSR::AEDWriter::numDataAndReserveExtents_(void) const
{
    return dataEL_->numExtents() + reserveLELSR_->numLogExtents();
}

//----------------------------------------------------------------------
// METHOD: AEDWriter::getMetaDataBlock_()                               --CSB
//
// 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.
// NOTE:  This will grow the list by ONE extent only to reach the
//   metaDataELIndex, or returns NULL if the request was too far
//   out of bounds.
// NOTE:  The metaDataELIndex would start on zero for the first block
//   (like an index).
//
// ARGS:
//  SpaceResource& space   IN/OUT  The space resource we get blocks
//                                 from and free blocks to.
//  UINT32 metaDataELIndex IN      The index to the meteDataEL_ that
//                                 identifies the meta data block in
//                                 question.
//  Error& err             OUT     The return status of this function.
//
//
// RETURNS:
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
//  error_None on success.
// 
// NOTES:
//
//----------------------------------------------------------------------
NSR::LogExtent* 
NSR::AEDWriter::getMetaDataBlock_(SpaceResource& space, UINT32 metaDataELIndex,
                                  Error& err)
{
    // See if we already have this block allocated.
    UINT32 numExtents = metaDataEL_->numExtents();;
    LogExtent* extent = NULL;
    err = error_None;

if (Trace::logAlgorithms()) {
    printf("********  Request for meta data block %d, and we already have %d extents.\n", 
           metaDataELIndex, numExtents);
}

    if(numExtents > metaDataELIndex) {
        // If we already have the block in our extent list.
if (Trace::logAlgorithms()) {
        printf("We already have this block.\n");
}
        extent = metaDataEL_->at(metaDataELIndex, err);
    } else {
        // We don't have this block in our extent list.  We must grow
        // the extent list.
    
        // NOTE:  Because of the recursive nature in which we write AEDs
        //   to disk, we may get this call for block 4 (referring to the fifth
        //   overflow AED), even though there may be NO blocks in our list
        //   yet (we write the AEDs in reverse order).  Thus, we can allocate
        //   all the AED blocks as one extent, then cut it up into blocks for
        //   individual AEDs.  This way, we don't fragment our meta-data.

        // Find out how much more space we need.
        // RECALL:  First block is block zero.
        UINT32 numNewExtents = (metaDataELIndex - numExtents) + 1;

        LogExtent tempExtent;
        // NOTE:  We want to take one extent to guarantee all meta-data space
        //   for all AEDs is contiguous.
        space.takeLogExtent(tempExtent, numNewExtents * space.blockSize(), err);

        if(err){
            // If we had a problem getting the extent.
            if (Trace::logAlgorithms()) {
                printf("Could not take the new extent! size: %d, error: [%d], %s\n", 
                       numNewExtents * space.blockSize(), (UINT32)err, err.message());
            }
        } else {
            // We got our new extent.
            // Put the big extent into a temporary list.
            LogExtentList tempList(space.logVolume());
            LogExtentList tempList2(space.logVolume());

            tempList.append(tempExtent, err);

            // Grab the first block (head) of this list for each new
            //   extent.
            for(UINT32 i = 0; (i < numNewExtents) && (!err); i++) {
                // For each new extent.
                // Cut off the blocks before the block we want.
                tempList2.TailOf(tempList, i * space.blockSize()+1, err);

                if(!err) {
                    // If we could take the tail of the list.

                    // Cut off the blocks after the block we want.
                    // NOTE:  At this point, we always want the first block in the list.
                    tempList2.HeadOf(tempList2, space.blockSize(), err);

                    if(!err) {
                        // If we could take the head.
                        // Append this list to the meta data list (it is only one block).
                        metaDataEL_->concat(tempList2, err);
                        if (Trace::logAlgorithms()) {
                            if(err) {
                                // Problem concatenating.
                                printf("Could not concatenate to metaDataEL!\n");
                            } else {
                                // We got the extent.
                                printf("******************************We took the new meta-data extent.\n");
                                tempList2.at(0,err)->print(2, "NEW EXTENT:");
                            }
                        }
                    } else {
                        if (Trace::logAlgorithms()) {
                            // Problem taking the head.
                            printf("Could not take the head!  Offset: %d\n",
                                   i*space.blockSize());
                        }
                    }
                } else {
                    if (Trace::logAlgorithms()) {
                        // Problem taking the tail.
                        printf("Could not take the tail!  Offset: %d\n",
                               i*space.blockSize());
                    }
                }
            }

            if(!err) {
                // If we ran into no errors taking heads and tails.
                extent = metaDataEL_->at(metaDataELIndex, err);
            }
        }
    }
    if (Trace::logAlgorithms()) {
        printf("Leaving getMetaDataBlock_(), [%d] %s.\n",
               (UINT32)err, err.message());
    }

    return extent;
}


//----------------------------------------------------------------------
// METHOD: AEDWriter::setContinuationAD_()                              --CSB
//
// Set the AD in the ADTable to refer to the extent passed in as
// a continuation extent.
//
// Use the offset passed in to determine the index of the AED
// overflow sector in our metaDataEL_->
//
// The metaDataELIndex passed in will reference the FIRST overflow AED
// at offset 0, the second at 1, etc.
//
// ARGS:
//  SpaceResource& space    IN/OUT  The space resource we get blocks from
//                                  or free blocks to.
//  ADTable& adTable        OUT     The AD table we are setting into.
//  UINT32 adTableIndex     IN      The index to identify the AD in the table
//                                  we want to set.
//  UINT32 metaDataELIndex  IN      The index to the metaDataEL_ that identifies
//                                  the block we want the AD to reference.
//  Error& err              OUT     The return status of this operation.
//
// RETURNS:
//  error_None on success.
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
// 
// NOTES:
//
//----------------------------------------------------------------------
void
NSR::AEDWriter::setContinuationAD_(SpaceResource& space, ADTable& adTable, 
                                   UINT32 adTableIndex, UINT32 metaDataELIndex, 
                                   Error& err)
{
    err = error_None;

    // Get the first overflow block.
    LogExtent* extent = getMetaDataBlock_(space, metaDataELIndex, err);

    if (Trace::logAlgorithms()) {
        printf("!!!!!!!! Setting Continuation AD to refer to block %d!\n",
               extent->startBlock());
    }

    if(extent && (! err)) {
        // If we could get a sector for the overflow AED to
        //   write into, and we did not get an error.
        // Set the continuation extent.
        adTable.setContinuationLogExtent(*extent, adTableIndex, err);
    }
}

//----------------------------------------------------------------------
// METHOD: AEDWriter::fromDisk()                                        --CSB
//
// Given an extent that holds a FileEntry, populate ourselves with
//   all of the AEDWriter state in that FileEntry, including all overflow
//   AEDs, if there are any (additional blocks will be read from the
//   surface).
//
// ARGS:
//  LogExtent& logExtent   IN  The logical extent on the surface where
//                             the FileEntry is located.
//  Error& error           OUT The return status of this operation.
//
// RETURNS:
//  error_None on success.
// 
// PRE-CONDITIONS:
//  Assumes a FileEntry is at this LogExtent on the surface.  If the
//  FileEntry cannot successfully read from the surface, an error is
//  returned and our AEDWriter's state is not modified.
// 
// POST-CONDITIONS:
//  All previous AEDWriter state is cleared, and the node has an entirely
//  new state reflecting the FileEntry and overflow AEDs we read from
//  the surface.
// 
// ERRORS:
//  error_NODE_InfoLen_mismatch; 
//  error_NODE_LogBlocksRecorded_mismatch;
// 
// NOTES:
//
//----------------------------------------------------------------------
void 
NSR::AEDWriter::fromDisk( LogExtent& logExtent,
                          ADTable& adTable,
                          LogExtentList& bodyEL,
                          UINT64 lenFirstList,
                          LELSpaceResource& tailEL,
                          LogExtentList& metaDataEL,
                          Error & err )
{
    // Zero our error out, in case all goes well.
    err = error_None;

    if (Trace::logAlgorithms()) {
        printf("Enter AEDWriter::fromDisk(), infoLen is %d.\n",
               lenFirstList);
    }
  
    // We want to read this AEDWriter from the disk.  Start with the descriptor
    //   portion (in the FileEntry).

    if(adTable.error()) {
        err = error_Bad_Parameter_ADTable;
    } else if(bodyEL.error()) {
        err = error_Bad_Parameter_Extent_List;
    } else if(tailEL.error()) {
        err = error_Bad_Parameter_Extent_List;
    } else if(metaDataEL.error()) {
        err = error_Bad_Parameter_Extent_List;
    } else {
        // None of the parameters are in error.
        dataEL_     = &bodyEL;
        reserveLELSR_  = &tailEL;
        metaDataEL_ = &metaDataEL;
        adType_     = adTable.adType();

        if (Trace::logAlgorithms()) {
            printf("No parameters in error, adType is %d.\n", adType_);
        }
        // Capture the error value returned, in case something bad
        //   happened during the population process.
        err = populateELs_(logExtent, adTable, lenFirstList);
        // At this point, we are done.  We read the AEDWriter from the disk.
    }
    return; 
} // AEDWriter::fromDisk()


//----------------------------------------------------------------------
// METHOD: AEDWriter::toDisk()                                          --CSB
//
//  Given the address (extent) to write a FileEntry, write out this
//  AEDWriter with a FileEntry descriptor at the LogExtent provided, continuing
//  overflow AEDs (if necessary) at additional blocks.  The AEDs will
//  be written first to blocks already allocated for meta data (remembered
//  from the AEDWriter::fromDisk() operation), or additional blocks will be
//  allocated from the SpaceResource passed in (if we don't already have
//  enough meta data blocks).  If we have a surplus of available meta data
//  blocks remembered from the AEDWriter::fromDisk() operation, these surplus
//  blocks are freed back to the SpaceResource.
//
//  Because the AEDWriter class does not store the ADType internally, that 
//  parameter must be passed in so we know to convert the LogExtents
//  to shortAllocDesc, longAllocDesc, or extendedAllocDesc.
//
//  The user can first call the AEDWriter::ISOError() to get an Error
//  return value to confirm that this AEDWriter has correct internal state that
//  can be written to the surface (not too much data, AEDWriter can reconcile
//  embedded data from embedded ADs, etc.)
//  
// ARGS:
//
//  LogExtent& ext    IN          The extent on the surface where the FileEntry
//                                is to be written.
//                                See OSTA 2.3.10 for info on which type to use.
//  SpaceResource& space  IN/OUT  The space resource we can get available
//                                blocks from or free blocks to on the write.
//
// RETURNS:
//  error_None on success.
//
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
//
//  error_NODE_InfoLen_mismatch
//  error_NODE_LogBlocksRecorded_mismatch
// 
// NOTES:
//
//  This function ASSUMES the logical extent passed in is big enough to
//  write the entire FileEntry.  At present, this means the extent
//  should be one block (for non-WORM media, the FileEntry is written
//  in one block extents.)
//----------------------------------------------------------------------
void 
NSR::AEDWriter::toDisk( LogExtent& logExtent,
                        ADTable& adTable,
                        LogExtentList& bodyEL,
                        LELSpaceResource& tailEL,
                        LogExtentList& metaDataEL,
                        SpaceResource & space, 
                        Error & err)
{
    if (Trace::logAlgorithms()) {
        printf("Enter AEDWriter::toDisk().\n");
    }
    // We have written no AED blocks by default.
    UINT32 numAEDsWritten = 0;

    // Set to no error by default.
    err = error_None;

    if(adTable.error()) {
        err = error_Bad_Parameter_ADTable;    
    } else if(space.error()) {
        err = error_Bad_Parameter_Space_Resource;
    } else if(bodyEL.error()) {
        err = error_Bad_Parameter_Extent_List;
    } else if(tailEL.error()) {
        err = error_Bad_Parameter_Extent_List;
    } else if(metaDataEL.error()) {
        err = error_Bad_Parameter_Extent_List;
    } else {
        // Our parameters are ok.

        // First, we must track the lists passed in.
        dataEL_     = & bodyEL;
        reserveLELSR_  = & tailEL;
        metaDataEL_ = & metaDataEL;
        adType_     = adTable.adType();

        // We want to populate the ADTable first, and then overflow
        //   into AEDs (if necessary).
        if (Trace::logAlgorithms()) {
            printf("We have %d data and reserve ADs.\n",
                   numDataAndReserveExtents_());
            printf("We have data infoLen of %d, reserve infoLen %d.\n",
                   dataEL_->infoLen(),
                   reserveLELSR_->availBytes());
        }
        // We are ready to write out our ADs.

        // NOTE: We ASSUME the ADTable passed in is already resized
        //   to the maximum size allowed!  Thus, we populate it only
        //   to its current size.

        UINT32 maxNumADTEnts = adTable.numADs();
        UINT32 numDataAndReserveADs = numDataAndReserveExtents_();
        UINT32 adsInFileEntry;
        UINT32 leaveRoomForAEDReference = 0;
    
        if(maxNumADTEnts >= numDataAndReserveADs) {
            // If all our ADs can fit in this fileEntry.
            // Do all of them.
            adsInFileEntry = numDataAndReserveADs;
        } else {
            // Not all of our ADs can fit into this fileEntry.  Put in as many
            //   as we can hold.
            // Do what we can hold.
            adsInFileEntry = maxNumADTEnts;
            leaveRoomForAEDReference = 1;  // We need to leave room.
        }

        // RECALL:  We cannot resize the adTable.
        // NOTE:  We CAN'T resize the adTable directly! We MUST
        //   go through the descriptor! 
        // DON'T DO THIS:  adTable.fitEnts(adsInFileEntry, adType_);
        // Instead, do this:
        //   fileEntry.numADTEnts(ext.blockSize(), adsInFileEntry, adType_);
        // (but we're not going to do either because the adTable is already
        //  at maxSize).
    
        // Now, put all our ADs into that table.
        // NOTE:  If we can't fit all the ADs in the fileEntry, then
        //   populate as many as we can MINUS the AD entry that we
        //   must set aside for the AED reference.
        // NOTE:  We always start populating at the very first LogExtent
        //   (joinedIndex of zero).
        if(err = populateADTable_(adTable, 0)) {
            if (Trace::logAlgorithms()) {
                printf("Error from populateADTable_():  [%d], %s.\n",
                       (UINT32)err, err.message());
            }
        } else {
            // No error populating the ADTable.
            // Put in the AED reference, if necessary.
            if(leaveRoomForAEDReference){
                // If we must write out an AED.
    
                // NOTE:  Since we know we must write out overflow AEDs, we
                //   may as well do that now.  
                // NOTE:  ON WORM MEDIA, WE DON'T WANT THE START BLOCK FROM THE
                //   EXTENT (for the FileEntry block location).  Instead, we
                //   want the block in the extent where the latest fileEntry
                //   info is stored.
                numAEDsWritten = writeOverflowAEDs_(
                    // Remeber, one is the reference AD.
                    adsInFileEntry - 1, 
                    logExtent.startBlock(), 
                    space, err);
  
                if(!err) {
                    // If we were able to write the AEDs out.
                    if (Trace::logAlgorithms()) {
                        printf("---------------Successfully wrote %d overflow AEDs.\n",
                               numAEDsWritten);
                    }
                    // Set this last AD in the FileEntry as a reference to the
                    //   first overflow AED.
                    setContinuationAD_(space, 
                                       adTable, 
                                       adsInFileEntry -1, // The AD.
                                       0,  // Always reference the first overflow AED.
                                       err);
                } else { 
                    if (Trace::logAlgorithms()) {
                        // We could not write the overflow AEDs.
                        printf("ERROR!  COULD NOT WRITE OVERFLOW AEDs!\n");
                    }
                }
            }
            // At this point, we have set up our adTable with the correct state
            //   and our overflow AEDs are already written.
        }
    }
    // At this point, we know how many AED blocks are written.  If we
    //   have an error, don't free the meta-data space (don't do anything--
    //   the caller can clean that up by freeing the metaDataEL_ from
    //   a diskSpace() call).  However, if we do not have an error, then 
    //   the write successfully completed and we can get rid of any space not 
    //   used during the write.

    if(!err) {
        // If we could write all of ourselves out without error, free unused
        //   (un-needed) meta-data space.
        if (Trace::logAlgorithms()) {
            printf("Freeing meta-data space.\n");
        }
        freeUnusedMetaDataExtents_(space, numAEDsWritten, err);
    }
} // AEDWriter::toDisk()

//----------------------------------------------------------------------
// METHOD: AEDWriter::freeUnusedMetaDataExtents_()                      --CSB
//
// Free all LogExtents in our metaDataEL_ for the index passed in and
//   beyond.  Thus, if 0 were passed in, we free the entire list.
//
// ARGS:
//  SpaceResource& space  IN/OUT  The space resource to which we free
//                                meta data blocks we no longer need.
//  UINT32 numAEDsWritten IN      The index into the metaDataEL_ where
//                                we begin freeing blocks.  We free
//                                that block (if it exists) and all
//                                blocks after that index (if they
//                                exist).
//  Error& err            OUT     The exit status of this operation.
//
// RETURNS:
// 
// PRE-CONDITIONS:
// 
// POST-CONDITIONS:
// 
// ERRORS:
// 
// NOTES:
//  The index passed in is assumed to be the number of AED blocks
//   (meta-data blocks) required for this node; thus, we can free all
//   past those required.
//
//----------------------------------------------------------------------
void
NSR::AEDWriter::freeUnusedMetaDataExtents_(SpaceResource& space,
                                           UINT32 numAEDsWritten,
                                           Error& err)
{
    err = error_None;

    if(space.error()) {
        // If our space resource is in an error state.
        err = error_Bad_Parameter_Space_Resource;
    } else {
        // We are ok.
        // Iterate and free all nodes at this index until there are none
        //   left.
        while((metaDataEL_->numExtents() > numAEDsWritten) && (!err)) {
            // While we have extents at or after this supplied index, and
            // we don't have an error.
            // Free the extent to the space resource.
            // Should we check first that we got a logExtent pointer back?
            if (Trace::logAlgorithms()) {
                printf("---FREEING UNUSED META-DATA BLOCK %d!---\n", 
                       metaDataEL_->at(numAEDsWritten, err));
            }
            // ISSUE: Bug: Needs to check err between calls
            space.putLogExtent(*metaDataEL_->at(numAEDsWritten, err), err);
            if(!err)
                metaDataEL_->remove(numAEDsWritten, err);
        }
    }
}
  
//----------------------------------------------------------------------
// METHOD: AEDWriter::clear()                           --CSB
//
//  Resets the entire state of the AEDWriter object by calling clear()
//  for all data members.
//   
// ARGS:
//
// RETURNS:
// 
// PRE-CONDITIONS:
//  This object could be in any possible state; everything will be reset
//  in the clear() operation.
// 
// POST-CONDITIONS:
//  All internal members of this AEDWriter object are re-set.
// 
// ERRORS:
// 
// NOTES:
//
//----------------------------------------------------------------------
void 
NSR::AEDWriter::clear() {
    metaDataEL_ = NULL;
    dataEL_ = NULL;
    reserveLELSR_ = NULL;
    // adType_ = ??;
} // clear()

