text: #include "Worker.h"
  #include <nlohmann/json.hpp>
  
  namespace adios2
  {
  namespace query
  {
  namespace JsonUtil
  {
  bool HasEntry(nlohmann::json &jsonO, const char *name)
  {
      int countMe = jsonO.count(name);
      if (countMe == 0)
          return false;
      return true;
  }
  
  void ConstructTree(adios2::query::RangeTree &host, nlohmann::json &opO)
  {
      if (!HasEntry(opO, "value"))
          return;
      auto relationStr = opO["value"];
      host.SetRelation(adios2::query::strToRelation(relationStr));
  
      if (HasEntry(opO, "range"))
      {
          auto const rangeOs = opO["range"];
          for (auto r : rangeOs)
          {
              std::string valStr = r["value"];
              std::string opStr = r["compare"];
              host.AddLeaf(adios2::query::strToQueryOp(opStr), valStr);
          }
      }
      if (HasEntry(opO, "op"))
      {
          auto subOpO = opO["op"];
          if (subOpO.is_array())
          {
              for (auto sub : subOpO)
              {
                  adios2::query::RangeTree subNode;
                  ConstructTree(subNode, sub);
                  host.AddNode(subNode);
              }
          }
          else
          {
              adios2::query::RangeTree subNode;
              ConstructTree(subNode, subOpO);
              host.AddNode(subNode);
          }
      }
  } // construct tree
  
  void LoadVarQuery(QueryVar *q, nlohmann::json &varO)
  {
      if (!adios2::query::JsonUtil::HasEntry(varO, "op"))
          throw std::ios_base::failure("No op entry specified for var:" +
                                       q->m_VarName);
  
      if (adios2::query::JsonUtil::HasEntry(varO, "boundingbox"))
      {
          auto bbO = varO["boundingbox"];
          q->LoadSelection(bbO["start"], bbO["count"]);
      }
      if (adios2::query::JsonUtil::HasEntry(varO, "op"))
      {
          auto opO = varO["op"];
          adios2::query::JsonUtil::ConstructTree(q->m_RangeTree, opO);
      }
  } // LoadVarQuery
  
  }
  }
  }
  
  namespace adios2
  {
  namespace query
  {
  void JsonWorker::ParseJson()
  {
      // local functions:
  
      auto lf_assertArray = [&](nlohmann::json &jsonO,
                                const std::string &name) -> void {
          if (!jsonO.is_array())
              throw std::ios_base::failure("Expecting Array for node:" + name);
      }; // lf assert
  
      auto lf_parseVar = [&](nlohmann::json &varO) -> QueryVar * {
          if (!adios2::query::JsonUtil::HasEntry(varO, "name"))
              throw std::ios_base::failure("No var name specified!!");
          auto varName = (varO)["name"];
          adios2::core::IO &currIO = m_SourceReader->m_IO;
          const std::string varType = currIO.InquireVariableType(varName);
          if (varType.size() == 0)
          {
              std::cerr << "No such variable: " << varName << std::endl;
              return nullptr;
          }
  
          QueryVar *simpleQ = GetBasicVarQuery(currIO, varName);
          if (simpleQ)
              adios2::query::JsonUtil::LoadVarQuery(simpleQ, varO);
          return simpleQ;
      }; // local function to Parse var
  
      auto lf_parseTag = [&](nlohmann::json &tagO) -> QueryBase * {
          if (adios2::query::JsonUtil::HasEntry(tagO, "var"))
              return lf_parseVar(tagO["var"]);
          return nullptr;
      };
  
      std::ifstream fileStream(m_QueryFile);
      nlohmann::json jsonObj = nlohmann::json::parse(fileStream);
  
      if (!adios2::query::JsonUtil::HasEntry(jsonObj, "io"))
      {
          std::cerr << " no io node in json query file" << std::endl;
          throw std::ios_base::failure("Expecting the io node: " +
                                       m_SourceReader->m_IO.m_Name);
      }
  
      auto ioO = jsonObj.find("io");
      std::string const ioName = (*ioO)["name"];
      if (m_SourceReader->m_IO.m_Name.compare(ioName) != 0)
          throw std::ios_base::failure("invalid query io. Expecting io name = " +
                                       m_SourceReader->m_IO.m_Name);
      if (adios2::query::JsonUtil::HasEntry(*ioO, "var"))
      {
          auto varO = (*ioO).find("var");
          m_Query = lf_parseVar(*varO);
          m_Query->Print();
          return;
      }
      if (!adios2::query::JsonUtil::HasEntry(*ioO, "query"))
          throw std::ios_base::failure(
              "no query entry was defined for composite query. ");
      auto queryO = (*ioO)["query"];
      auto relationO = queryO["op"];
      QueryComposite *result =
          new QueryComposite(adios2::query::strToRelation(relationO));
  
      auto tagO = (*ioO)["tag"];
      lf_assertArray(tagO, "tag");
      std::map<std::string, QueryBase *> subqueries;
  
      for (auto tag : tagO)
      {
          QueryBase *q = lf_parseTag(tag);
          subqueries[tag["name"]] = q;
      }
      // for (nlohmann::json::iterator it = queryO.begin(); it != queryO.end();
      // ++it) {
  
      auto compO = queryO["comp"];
      lf_assertArray(compO, "comp");
  
      for (auto qname : compO)
      {
          std::cout << qname << std::endl;
          result->AddNode(subqueries[qname]);
      }
  
      m_Query = result;
      return;
  } // parse
  
  }
  }
  