/**
     * Updates from a more generic ascii file
     * @param filename :: The input filename
     */
    void UpdateInstrumentFromFile::updateFromAscii(const std::string & filename)
    {
      AsciiFileHeader header;
      const bool isSpectrum = parseAsciiHeader(header);

      Geometry::Instrument_const_sptr inst = m_workspace->getInstrument();
      // Throws for multiple detectors
      const spec2index_map specToIndex(m_workspace->getSpectrumToWorkspaceIndexMap());

      std::ifstream datfile(filename.c_str(), std::ios_base::in);
      const int skipNLines = getProperty("SkipFirstNLines");
      std::string line;
      int lineCount(0);
      while(lineCount < skipNLines)
      {
        std::getline(datfile,line);
        ++lineCount;
      }

      std::vector<double> colValues(header.colCount - 1, 0.0);
      while(std::getline(datfile,line))
      {
        boost::trim(line);
        std::istringstream is(line);
        // Column 0 should be ID/spectrum number
        int32_t detOrSpec(-1000);
        is >> detOrSpec;
        // If first thing read is not a number then skip the line
        if(is.fail())
        {
          g_log.debug() << "Skipping \"" << line << "\". Cannot interpret as list of numbers.\n";
          continue;
        }

        Geometry::IDetector_const_sptr det;
        try
        {
          if(isSpectrum)
          {
            auto it = specToIndex.find(detOrSpec);
            if(it != specToIndex.end())
            {
              const size_t wsIndex = it->second;
              det = m_workspace->getDetector(wsIndex);
            }
            else
            {
              g_log.debug() << "Skipping \"" << line << "\". Spectrum is not in workspace.\n";
              continue;
            }
          }
          else
          {
            det = inst->getDetector(detOrSpec);
          }
        }
        catch(Kernel::Exception::NotFoundError&)
        {
          g_log.debug() << "Skipping \"" << line << "\". Spectrum in workspace but cannot find associated detector.\n";
          continue;
        }

        // Special cases for detector r,t,p. Everything else is
        // attached as an detector parameter
        double R(0.0),theta(0.0), phi(0.0);
        for(size_t i = 1; i < header.colCount; ++i)
        {
          double value(0.0);
          is >> value;
          if(i < header.colCount - 1 && is.eof())
          {
            //If stringstream is at EOF & we are not at the last column then
            // there aren't enought columns in the file
            throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - "
                          "File contains fewer than expected number of columns, check AsciiHeader property.");
          }

          if(i == header.rColIdx) R = value;
          else if(i == header.thetaColIdx) theta = value;
          else if(i == header.phiColIdx) phi = value;
          else if(header.detParCols.count(i) == 1)
          {
            Geometry::ParameterMap & pmap = m_workspace->instrumentParameters();
            pmap.addDouble(det->getComponentID(), header.colToName[i],value);
          }
        }
        // Check stream state. stringstream::EOF should have been reached, if not then there is still more to
        // read and the file has more columns than the header indicated
        if(!is.eof())
        {
          throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - "
              "File contains more than expected number of columns, check AsciiHeader property.");
        }

        // If not supplied use current values
        double r,t,p;
        det->getPos().getSpherical(r,t,p);
        if(header.rColIdx == 0) R = r;
        if(header.thetaColIdx == 0) theta = t;
        if(header.phiColIdx == 0) phi = p;

        setDetectorPosition(det, static_cast<float>(R), static_cast<float>(theta), static_cast<float>(phi));
      }
    }
/**
 * スレッドの情報をOIDをキーとするmapに変換する
 * @param map<wxString,ThreadList>& oldThreadMap 古いスレッドの情報を保持するコンテナ
 */
void XrossBoardUtil::GenerateOldThreadMap(std::map<wxString,ThreadList>& oldThreadMap, URLvsBoardName& boardInfo) {

     // ファイルのパスを設定する
     wxString outputPath = ::wxGetHomeDir() 
	  + wxFILE_SEP_PATH 
	  + XROSSBOARD_DIR
	  + wxFILE_SEP_PATH
	  + wxT("dat")
	  + wxFILE_SEP_PATH
	  + boardInfo.boardNameAscii
	  + wxFILE_SEP_PATH
	  + boardInfo.boardNameAscii
	  + wxT(".dat");

     // ファイルが存在しなければそのままリターン
     // つまり完全に初回のスレッド一覧取得
     if(!wxFileExists(outputPath)) return;
     // テキストファイルの読み込み
     wxTextFile datfile(outputPath);
     datfile.Open();

     // スレッド一覧読み込み用正規表現を準備する
     wxRegEx reThreadLine(_T("([[:digit:]]+).dat<>(.+)\\(([[:digit:]]{1,4})\\)"), wxRE_ADVANCED + wxRE_ICASE);
     // スレッドに番号をつける
     int loopNumber = 1;

     // テキストファイルの終端まで読み込む
     for (wxString line = datfile.GetFirstLine(); !datfile.Eof(); line = datfile.GetNextLine()) {

	  if (line.Contains(_("&"))) { 
	       line = ConvCharacterReference(line);
	  }

	  ThreadList threadInfoList;
	  
	  // 番号
	  threadInfoList.number = loopNumber;
	  // 板名
	  threadInfoList.boardName = boardInfo.boardName;

	  // 正規表現で情報を取得する
	  if (reThreadLine.Matches(line)) {
	       // キー値を取得する
	       threadInfoList.oid = reThreadLine.GetMatch(line, 1);
	       // since
	       threadInfoList.since = XrossBoardUtil::CalcThreadCreatedTime(threadInfoList.oid);
	       // スレタイを取得する
	       threadInfoList.title = reThreadLine.GetMatch(line, 2);
	       // レス数を取得する
	       threadInfoList.response = wxAtoi(reThreadLine.GetMatch(line, 3));
	  }

	  /**
	   * 更新処理
	   */
	  // 取得
	  //itemCachedResponseNumber = wxEmptyString;
	  // 新着
	  //itemNewResponseNumber = wxEmptyString;
	  // 増レス
	  //itemIncreaseResponseNumber = wxEmptyString;
	  // 勢い
	  wxString response = wxString::Format(wxT("%d"), threadInfoList.response);
	  threadInfoList.momentum = XrossBoardUtil::CalcThreadMomentum(response, threadInfoList.oid);
	  // 最終取得
	  //itemLastUpdate = wxEmptyString;

	  // 項目を追加する
	  oldThreadMap.insert(std::map<wxString, ThreadList>::value_type(threadInfoList.oid, threadInfoList));
	  
	  // ループ変数をインクリメント
	  ++loopNumber;
     }

     datfile.Close();
}
/**
 * Updates from a more generic ascii file
 * @param filename :: The input filename
 */
void UpdateInstrumentFromFile::updateFromAscii(const std::string &filename) {
  AsciiFileHeader header;
  const bool isSpectrum = parseAsciiHeader(header);

  // Throws for multiple detectors
  const spec2index_map specToIndex(
      m_workspace->getSpectrumToWorkspaceIndexMap());

  std::ifstream datfile(filename.c_str(), std::ios_base::in);
  const int skipNLines = getProperty("SkipFirstNLines");
  std::string line;
  int lineCount(0);
  while (lineCount < skipNLines) {
    std::getline(datfile, line);
    ++lineCount;
  }

  Geometry::ParameterMap &pmap = m_workspace->instrumentParameters();
  auto &detectorInfo = m_workspace->mutableDetectorInfo();
  const auto &spectrumInfo = m_workspace->spectrumInfo();

  std::vector<double> colValues(header.colCount - 1, 0.0);
  while (std::getline(datfile, line)) {
    boost::trim(line);
    std::istringstream is(line);
    // Column 0 should be ID/spectrum number
    int32_t detOrSpec(-1000);
    is >> detOrSpec;
    // If first thing read is not a number then skip the line
    if (is.fail()) {
      g_log.debug() << "Skipping \"" << line
                    << "\". Cannot interpret as list of numbers.\n";
      continue;
    }

    bool skip{false};
    size_t index = static_cast<size_t>(-1);
    const Geometry::IDetector *det{nullptr};
    if (isSpectrum) {
      auto it = specToIndex.find(detOrSpec);
      if (it != specToIndex.end()) {
        index = it->second;
        if (spectrumInfo.hasDetectors(index)) {
          det = &spectrumInfo.detector(index);
        } else {
          skip = true;
        }
      } else {
        g_log.debug() << "Skipping \"" << line
                      << "\". Spectrum is not in workspace.\n";
        continue;
      }
    } else {
      try {
        index = detectorInfo.indexOf(detOrSpec);
        det = &detectorInfo.detector(index);
      } catch (std::out_of_range &) {
        skip = true;
      }
    }
    if (skip || index == static_cast<size_t>(-1)) {
      g_log.debug()
          << "Skipping \"" << line
          << "\". Spectrum in workspace but cannot find associated detector.\n";
      continue;
    }

    std::vector<size_t> indices;
    if (isSpectrum) {
      if (auto group = dynamic_cast<const Geometry::DetectorGroup *>(det)) {
        for (const auto detID : group->getDetectorIDs())
          indices.push_back(detectorInfo.indexOf(detID));
      } else {
        indices.push_back(detectorInfo.indexOf(det->getID()));
      }
    } else {
      indices.push_back(index);
    }

    // Special cases for detector r,t,p. Everything else is
    // attached as an detector parameter
    double R(0.0), theta(0.0), phi(0.0);
    for (size_t i = 1; i < header.colCount; ++i) {
      double value(0.0);
      is >> value;
      if (i < header.colCount - 1 && is.eof()) {
        // If stringstream is at EOF & we are not at the last column then
        // there aren't enought columns in the file
        throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - "
                                 "File contains fewer than expected number of "
                                 "columns, check AsciiHeader property.");
      }

      if (i == header.rColIdx)
        R = value;
      else if (i == header.thetaColIdx)
        theta = value;
      else if (i == header.phiColIdx)
        phi = value;
      else if (header.detParCols.count(i) == 1) {
        for (const auto index : indices) {
          auto id = detectorInfo.detector(index).getComponentID();
          pmap.addDouble(id, header.colToName[i], value);
        }
      }
    }
    // Check stream state. stringstream::EOF should have been reached, if not
    // then there is still more to
    // read and the file has more columns than the header indicated
    if (!is.eof()) {
      throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - "
                               "File contains more than expected number of "
                               "columns, check AsciiHeader property.");
    }

    // If not supplied use current values
    double r, t, p;
    if (isSpectrum)
      spectrumInfo.position(index).getSpherical(r, t, p);
    else
      detectorInfo.position(index).getSpherical(r, t, p);
    if (header.rColIdx == 0)
      R = r;
    if (header.thetaColIdx == 0)
      theta = t;
    if (header.phiColIdx == 0 || m_ignorePhi)
      phi = p;

    for (const auto index : indices)
      setDetectorPosition(detectorInfo, index, static_cast<float>(R),
                          static_cast<float>(theta), static_cast<float>(phi));
  }
}