/** Create output workspace
 * @brief ConvertCWSDExpToMomentum::createExperimentMDWorkspace
 * @return
 */
API::IMDEventWorkspace_sptr ConvertCWSDMDtoHKL::createHKLMDWorkspace(
    const std::vector<Kernel::V3D> &vec_hkl,
    const std::vector<signal_t> &vec_signal,
    const std::vector<detid_t> &vec_detid) {
  // Check
  if (vec_hkl.size() != vec_signal.size() ||
      vec_signal.size() != vec_detid.size())
    throw std::invalid_argument("Input vectors for HKL, signal and detector "
                                "IDs are of different size!");

  // Create workspace in Q_sample with dimenion as 3
  size_t nDimension = 3;
  IMDEventWorkspace_sptr mdws =
      MDEventFactory::CreateMDWorkspace(nDimension, "MDEvent");

  // Extract Dimensions and add to the output workspace.
  std::vector<std::string> vec_ID(3);
  vec_ID[0] = "H";
  vec_ID[1] = "K";
  vec_ID[2] = "L";

  std::vector<std::string> dimensionNames(3);
  dimensionNames[0] = "H";
  dimensionNames[1] = "K";
  dimensionNames[2] = "L";

  Mantid::Kernel::SpecialCoordinateSystem coordinateSystem =
      Mantid::Kernel::HKL;

  // Add dimensions
  std::vector<double> m_extentMins(3);
  std::vector<double> m_extentMaxs(3);
  std::vector<size_t> m_numBins(3, 100);
  getRange(vec_hkl, m_extentMins, m_extentMaxs);

  // Get MDFrame of HKL type with RLU
  auto unitFactory = makeMDUnitFactoryChain();
  auto unit = unitFactory->create(Units::Symbol::RLU.ascii());
  Mantid::Geometry::HKL frame(unit);

  for (size_t i = 0; i < nDimension; ++i) {
    std::string id = vec_ID[i];
    std::string name = dimensionNames[i];
    // std::string units = "A^-1";
    mdws->addDimension(
        Geometry::MDHistoDimension_sptr(new Geometry::MDHistoDimension(
            id, name, frame, static_cast<coord_t>(m_extentMins[i]),
            static_cast<coord_t>(m_extentMaxs[i]), m_numBins[i])));
  }

  // Set coordinate system
  mdws->setCoordinateSystem(coordinateSystem);

  // Creates a new instance of the MDEventInserter to output workspace
  MDEventWorkspace<MDEvent<3>, 3>::sptr mdws_mdevt_3 =
      boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(mdws);
  MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3);

  // Go though each spectrum to conver to MDEvent
  for (size_t iq = 0; iq < vec_hkl.size(); ++iq) {
    Kernel::V3D hkl = vec_hkl[iq];
    std::vector<Mantid::coord_t> millerindex(3);
    millerindex[0] = static_cast<float>(hkl.X());
    millerindex[1] = static_cast<float>(hkl.Y());
    millerindex[2] = static_cast<float>(hkl.Z());

    signal_t signal = vec_signal[iq];
    signal_t error = std::sqrt(signal);
    uint16_t runnumber = 1;
    detid_t detid = vec_detid[iq];

    // Insert
    inserter.insertMDEvent(
        static_cast<float>(signal), static_cast<float>(error * error),
        static_cast<uint16_t>(runnumber), detid, millerindex.data());
  }

  return mdws;
}
/** Execute the algorithm.
 */
void ImportMDEventWorkspace::exec() {
  std::string filename = getProperty("Filename");

  std::ifstream file;
  try {
    file.open(filename.c_str(), std::ios::in);
  } catch (std::ifstream::failure &e) {
    g_log.error() << "Cannot open file: " << filename;
    throw(e);
  }

  // Extract data from the file, excluding comment lines.
  std::string line;
  std::string lastLine;
  size_t nActualColumns = 0;
  while (std::getline(file, line)) {
    boost::algorithm::trim(line);
    if (std::string::npos == line.find_first_of(CommentLineStartFlag())) {
      std::stringstream buffer(line);
      std::copy(std::istream_iterator<std::string>(buffer),
                std::istream_iterator<std::string>(),
                std::back_inserter(m_file_data));

      if (lastLine == MDEventBlockFlag()) {
        std::vector<std::string> strVec;
        boost::algorithm::split(strVec, line, boost::is_any_of("\t "),
                                boost::token_compress_on);
        nActualColumns = strVec.size();
      }
    }
    lastLine = line;
  }

  file.close();

  // Check the file format.
  quickFileCheck();

  // Extract some well used posisions
  m_posDimStart =
      std::find(m_file_data.begin(), m_file_data.end(), DimensionBlockFlag());
  m_posMDEventStart =
      std::find(m_file_data.begin(), m_file_data.end(), MDEventBlockFlag());

  // Calculate the dimensionality
  int posDiffDims =
      static_cast<int>(std::distance(m_posDimStart, m_posMDEventStart));
  m_nDimensions = (posDiffDims - 1) / 4;

  // Calculate the actual number of columns in the MDEvent data.
  int posDiffMDEvent =
      static_cast<int>(std::distance(m_posMDEventStart, m_file_data.end()));
  const size_t columnsForFullEvents =
      m_nDimensions + 4; // signal, error, run_no, detector_no
  m_IsFullDataObjects = (nActualColumns == columnsForFullEvents);

  if (0 == nActualColumns) {
    m_nDataObjects = 0;
    g_log.warning() << "The number of actual columns found in the file "
                       "(exlcuding comments) is zero" << std::endl;
  } else {
    m_nDataObjects = posDiffMDEvent / nActualColumns;
  }

  // Get the min and max extents in each dimension.
  std::vector<double> extentMins(m_nDimensions);
  std::vector<double> extentMaxs(m_nDimensions);
  DataCollectionType::iterator mdEventEntriesIterator = m_posMDEventStart;
  for (size_t i = 0; i < m_nDataObjects; ++i) {
    mdEventEntriesIterator += 2;
    if (m_IsFullDataObjects) {
      mdEventEntriesIterator += 2;
    }
    for (size_t j = 0; j < m_nDimensions; ++j) {
      double coord = convert<double>(*(++mdEventEntriesIterator));
      extentMins[j] = coord < extentMins[j] ? coord : extentMins[j];
      extentMaxs[j] = coord > extentMaxs[j] ? coord : extentMaxs[j];
    }
  }

  // Create a target output workspace.
  IMDEventWorkspace_sptr outWs = MDEventFactory::CreateMDWorkspace(
      m_nDimensions, m_IsFullDataObjects ? "MDEvent" : "MDLeanEvent");

  // Extract Dimensions and add to the output workspace.
  DataCollectionType::iterator dimEntriesIterator = m_posDimStart;
  auto unitFactory = makeMDUnitFactoryChain();
  for (size_t i = 0; i < m_nDimensions; ++i) {
    std::string id = convert<std::string>(*(++dimEntriesIterator));
    std::string name = convert<std::string>(*(++dimEntriesIterator));
    std::string units = convert<std::string>(*(++dimEntriesIterator));
    int nbins = convert<int>(*(++dimEntriesIterator));

    auto mdUnit = unitFactory->create(units);
    Mantid::Geometry::GeneralFrame frame(
        Mantid::Geometry::GeneralFrame::GeneralFrameName, std::move(mdUnit));
    outWs->addDimension(MDHistoDimension_sptr(new MDHistoDimension(
        id, name, frame, static_cast<coord_t>(extentMins[i]),
        static_cast<coord_t>(extentMaxs[i]), nbins)));
  }

  CALL_MDEVENT_FUNCTION(this->addEventsData, outWs)

  // set output
  this->setProperty("OutputWorkspace", outWs);
}