/**
  * When $printStatus is true, the replication details are written to the
  * STDOUT. When $getFinalReport is true, detailed replication report is
  * returned and if false, only the success and failure counts are returned.
  * Both $printStatus and $getFinalReport are used only when the
  * replication is continuous and are ignored in case of normal replication.
  *
  * @param bool $printStatus
  * @param bool $getFinalReport
  * @return array
  * @throws HTTPException
  */
 public function locateChangedDocumentsAndReplicate($printStatus, $getFinalReport)
 {
     $finalResponse = array('multipartResponse' => array(), 'bulkResponse' => array(), 'errorResponse' => array());
     // Filtered changes stream is not supported. So Don't use the doc_ids
     // to specify the specific document ids.
     if ($this->task->getContinuous()) {
         $options = array('feed' => 'continuous', 'style' => $this->task->getStyle(), 'heartbeat' => $this->task->getHeartbeat(), 'since' => $this->task->getSinceSeq(), 'filter' => $this->task->getFilter());
         if ($this->task->getHeartbeat() != null) {
             $options['heartbeat'] = $this->task->getHeartbeat();
         } else {
             $options['timeout'] = $this->task->getTimeout() != null ? $this->task->getTimeout() : 10000;
         }
         $changesStream = $this->source->getChangesAsStream($options);
         $successCount = 0;
         $failureCount = 0;
         while (!feof($changesStream)) {
             $changes = fgets($changesStream);
             if ($changes == false || trim($changes) == '' || strpos($changes, 'last_seq') !== false) {
                 sleep(2);
                 continue;
             }
             $mapping = $this->getMapping($changes);
             $docId = array_keys($mapping)[0];
             try {
                 // getRevisionDifference throws bad request when JSON is
                 // empty. So check before sending.
                 $revDiff = count($mapping) > 0 ? $this->target->getRevisionDifference($mapping) : array();
                 $response = $this->replicateChanges($revDiff);
                 if ($getFinalReport == true) {
                     foreach ($response['multipartResponse'] as $docID => $res) {
                         // Add the response of posting each revision of the
                         // doc that had attachments.
                         foreach ($res as $singleRevisionResponse) {
                             // An Exception.
                             if (is_a($singleRevisionResponse, 'Exception')) {
                                 // Note: In this case there is no 'rev' field in
                                 // the response.
                                 $finalResponse['errorResponse'][$docID][] = $singleRevisionResponse;
                             } else {
                                 $finalResponse['multipartResponse'][$docID][] = $singleRevisionResponse;
                             }
                         }
                     }
                     foreach ($response['bulkResponse'] as $docID => $status) {
                         $finalResponse['bulkResponse'][$docID][] = $status;
                     }
                 }
                 if ($printStatus == true) {
                     echo 'Document with id = ' . $docId . ' successfully replicated.' . "\n";
                 }
                 $successCount++;
             } catch (\Exception $e) {
                 if ($getFinalReport == true) {
                     $finalResponse['errorResponse'][$docID][] = $e;
                 }
                 if ($printStatus == true) {
                     echo 'Replication of document with id = ' . $docId . ' failed with code: ' . $e->getCode() . ".\n";
                 }
                 $failureCount++;
             }
         }
         $finalResponse['successCount'] = $successCount;
         $finalResponse['failureCount'] = $failureCount;
         // The final response in case of continuous replication.
         // In case where $getFinalReport is true, response has five keys:
         // (i)multipartResponse, (ii) bulkResponse, (iii)errorResponse,
         // (iv) successCount, (v) failureCount. The errorResponse has the
         // responses from the failed replication attempt of docs having
         // attachments. To check failures related to bulk posting, the
         // returned status codes can be used.
         // When $getFinalReport is false, the returned response has only the
         // successCount and failureCount.
         return $finalResponse;
     } else {
         $changes = $this->source->getChanges(array('feed' => 'normal', 'style' => $this->task->getStyle(), 'since' => $this->task->getSinceSeq(), 'filter' => $this->task->getFilter(), 'doc_ids' => $this->task->getDocIds()));
         $mapping = $this->getMapping($changes);
         $revDiff = count($mapping) > 0 ? $this->target->getRevisionDifference($mapping) : array();
         $response = $this->replicateChanges($revDiff);
         foreach ($response['multipartResponse'] as $docID => $res) {
             // Add the response of posting each revision of the
             // doc that had attachments.
             foreach ($res as $singleRevisionResponse) {
                 // An Exception.
                 if (is_a($singleRevisionResponse, 'Exception')) {
                     // Note: In this case there is no 'rev' field in
                     // the response.
                     $finalResponse['errorResponse'][$docID][] = $singleRevisionResponse;
                 } else {
                     $finalResponse['multipartResponse'][$docID][] = $singleRevisionResponse;
                 }
             }
         }
         foreach ($response['bulkResponse'] as $docID => $res) {
             $finalResponse['bulkResponse'][$docID][] = $res;
         }
         // In case of normal replication the $finalResponse has three
         // keys: (i) multipartResponse, (ii) bulkResponse, (iii)
         // errorResponse.
         return $finalResponse;
     }
 }