/**
  * This function return an iterator on a list of documents (no folders).
  *
  * How it works:
  * 1. Get the list of all documents that match the criteria (if
  *    any!). (permissions apply).
  *    Note: the final list of documents is a subset of this result.
  * 2. Get the list of folders behind $parentId (permissions apply).
  * 3. Check that each document in list 1. is in a folder of list 2.
  * 5. Apply limits ($start, $offset) is only a subset of the list is required.
  * 6. If needed, add the metadata to the items. 
  */
 function &getItemSubTreeAsList($parentId, &$nbItemsFound, $params = null)
 {
     $_parentId = (int) $parentId;
     $user =& $params['user'];
     // Prepare filters if any
     $filter = null;
     if (isset($params['filter'])) {
         $filter =& $params['filter'];
     }
     // Obsolescence
     $searchItemsParams = array();
     if (isset($params['ignore_obsolete'])) {
         $searchItemsParams['ignore_obsolete'] = $params['ignore_obsolete'];
     }
     // Range of documents to return
     $start = 0;
     if (isset($params['start'])) {
         $start = $params['start'];
     }
     $end = 25;
     if (isset($params['offset'])) {
         $end = $start + $params['offset'];
     }
     $dao =& $this->_getItemDao();
     //
     // Build Folder List
     //
     $parentItem = $this->getItemFromDb($parentId);
     $dPm = Docman_PermissionsManager::instance($parentItem->getGroupId());
     $folderList = array($parentId => &$parentItem);
     $pathIdArray = array($parentId => array());
     $pathTitleArray = array($parentId => array());
     $parentIds = array($parentId);
     $folderIds = array($parentId);
     $i = 0;
     do {
         $i++;
         $dar = $dao->searchSubFolders($parentIds);
         $parentIds = array();
         $itemIds = array();
         $itemRows = array();
         if ($dar && !$dar->isError()) {
             $dar->rewind();
             while ($dar->valid()) {
                 $row = $dar->current();
                 $itemRows[$row['item_id']] = $row;
                 $itemIds[] = $row['item_id'];
                 $parentIds[$row['item_id']] = $row['item_id'];
                 $dar->next();
             }
             // Fetch all the permissions at the same time
             $dPm->retreiveReadPermissionsForItems($itemIds, $user);
             // Build hierarchy: only keep displayable items
             foreach ($itemIds as $id) {
                 if ($dPm->userCanRead($user, $id)) {
                     $folderList[$id] =& $this->getItemFromRow($itemRows[$id]);
                     // Update path
                     $pathIdArray[$id] = array_merge($pathIdArray[$folderList[$id]->getParentId()], array($id));
                     $pathTitleArray[$id] = array_merge($pathTitleArray[$folderList[$id]->getParentId()], array($folderList[$id]->getTitle()));
                 } else {
                     unset($parentIds[$id]);
                 }
             }
         }
     } while (count($parentIds) > 0);
     //
     // Keep only documents in allowed subfolders
     //
     $mdFactory = new Docman_MetadataFactory($this->groupId);
     $ci = null;
     if ($filter !== null) {
         $ci = $filter->getColumnIterator();
     }
     //
     // Build Document list
     //
     $itemArray = array();
     if (isset($params['obsolete_only']) && $params['obsolete_only']) {
         $dar = $dao->searchObsoleteByGroupId($this->groupId);
     } else {
         $dar = $dao->searchByGroupId($this->groupId, $filter, $searchItemsParams);
     }
     $nbItemsFound = 0;
     if ($dar && !$dar->isError()) {
         $this->preloadItemPerms($dar, $user, $this->groupId);
         $dar->rewind();
         while ($dar->valid()) {
             $row = $dar->current();
             // The document is not is one of the allowed subfolder so we
             // can delete it. As a side effect decrease the number of
             // document found.
             if ($dPm->userCanRead($user, $row['item_id']) && isset($folderList[$row['parent_id']])) {
                 if ($nbItemsFound >= $start && $nbItemsFound < $end || isset($params['getall']) && $params['getall']) {
                     $itemArray[$row['item_id']] =& $this->getItemFromRow($row);
                     // Append Path
                     $itemArray[$row['item_id']]->setPathTitle($pathTitleArray[$row['parent_id']]);
                     $itemArray[$row['item_id']]->setPathId($pathIdArray[$row['parent_id']]);
                     // Append metadata
                     if ($ci !== null) {
                         $ci->rewind();
                         while ($ci->valid()) {
                             $c = $ci->current();
                             if ($c->md !== null && $mdFactory->isRealMetadata($c->md->getLabel())) {
                                 $mdFactory->addMetadataValueToItem($itemArray[$row['item_id']], $c->md);
                             }
                             $ci->next();
                         }
                     }
                 }
                 $nbItemsFound++;
             }
             $dar->next();
         }
     }
     $docIter =& new ArrayIterator($itemArray);
     return $docIter;
 }