/**
 * Setup the filebackend for the output workspace. It assumes that the
 * box controller has already been initialized
 * @param filebackPath :: Path to the file used for backend storage
 * @param outputWS :: Workspace on which to set the file back end
 */
void ConvertToMD::setupFileBackend(
    std::string filebackPath, Mantid::API::IMDEventWorkspace_sptr outputWS) {
  using DataObjects::BoxControllerNeXusIO;
  auto savemd = this->createChildAlgorithm("SaveMD", 0.01, 0.05, true);
  savemd->setProperty("InputWorkspace", outputWS);
  savemd->setPropertyValue("Filename", filebackPath);
  savemd->setProperty("UpdateFileBackEnd", false);
  savemd->setProperty("MakeFileBacked", false);
  savemd->executeAsChildAlg();

  // create file-backed box controller
  auto boxControllerMem = outputWS->getBoxController();
  auto boxControllerIO =
      boost::make_shared<BoxControllerNeXusIO>(boxControllerMem.get());
  boxControllerMem->setFileBacked(boxControllerIO, filebackPath);
  outputWS->setFileBacked();
  boxControllerMem->getFileIO()->setWriteBufferSize(1000000);
}
  /** Perform the merging, but clone the initial workspace and use the same splitting
   * as its structure is equivalent to the partial box structures. 
   *
   * @param ws :: first MDEventWorkspace in the list to merge to.
   * @param outputFile :: the name of the output file where file-based workspace should be saved
   */
  void MergeMDFiles::doExecByCloning(Mantid::API::IMDEventWorkspace_sptr ws,const std::string &outputFile)
  {
    m_OutIWS = ws;
    m_MDEventType = ws->getEventTypeName();


   // Run the tasks in parallel? TODO: enable
    //bool Parallel = this->getProperty("Parallel");

    // Fix the box controller settings in the output workspace so that it splits normally
    BoxController_sptr bc = ws->getBoxController();
    // set up internal variables characterizing the workspace. 
    m_nDims = static_cast<int>(bc->getNDims());


    // Fix the max depth to something bigger.
    bc->setMaxDepth(20);
    bc->setSplitThreshold(5000);
    auto saver = boost::shared_ptr<API::IBoxControllerIO>(new MDEvents::BoxControllerNeXusIO(bc.get()));
    saver->setDataType(sizeof(coord_t),m_MDEventType);    
    if(m_fileBasedTargetWS)
    {
        bc->setFileBacked(saver,outputFile);
    // Complete the file-back-end creation.
        g_log.notice() << "Setting cache to 400 MB write." << std::endl;
        bc->getFileIO()->setWriteBufferSize(400000000/m_OutIWS->sizeofEvent());
    }

 /*   else
    {
        saver->openFile(outputFile,"w");
    }*/
    // Init box structure used for memory/file space calculations
    m_BoxStruct.initFlatStructure(ws,outputFile);

    // First, load all the box data and experiment info and calculate file positions of the target workspace
    this->loadBoxData();



    size_t numBoxes = m_BoxStruct.getNBoxes();
      // Progress report based on events processed.
    this->prog = new Progress(this, 0.1, 0.9, size_t(numBoxes));
    prog->setNotifyStep(0.1);

    // For tracking progress
    //uint64_t totalEventsInTasks = 0;
   
    // Prepare thread pool
    CPUTimer overallTime;

    ThreadSchedulerFIFO * ts = new ThreadSchedulerFIFO();
    ThreadPool tp(ts);

    Kernel::DiskBuffer *DiskBuf(NULL);
    if(m_fileBasedTargetWS)
    {
        DiskBuf = bc->getFileIO();
    }

    this->totalLoaded = 0;
    std::vector<API::IMDNode *> &boxes = m_BoxStruct.getBoxes();

    for(size_t ib=0;ib<numBoxes;ib++)
    {
      auto box = boxes[ib];
      if(!box->isBox())continue;
      // load all contributed events into current box;
      this->loadEventsFromSubBoxes(boxes[ib]);

      if(DiskBuf)
      {
        if(box->getDataInMemorySize()>0)
        {  // data position has been already precalculated 
            box->getISaveable()->save();
            box->clearDataFromMemory();
            //Kernel::ISaveable *Saver = box->getISaveable();
            //DiskBuf->toWrite(Saver);
        }
      }
      //else
      //{   size_t ID = box->getID();
      //    uint64_t filePosition = targetEventIndexes[2*ID];
      //    box->saveAt(saver.get(), filePosition);
      //}
      //
      //if (!Parallel)
      //{
      //  // Run the task serially only
      //  task->run();
      //  delete task;
      //}
      //else
      //{
      //  // Enqueue to run in parallel (at the joinAll() call below).
      //  ts->push(task);
      //}

      prog->reportIncrement(ib,"Loading and merging box data");
    }
    if(DiskBuf)
    {
      DiskBuf->flushCache();
      bc->getFileIO()->flushData();
    }
    //// Run any final tasks
    //tp.joinAll();
    g_log.information() << overallTime << " to do all the adding." << std::endl;

    // Close any open file handle
    clearEventLoaders();

    // Finish things up
    this->finalizeOutput(outputFile);
  }