// file      : bbot/utility.hxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#ifndef BBOT_UTILITY_HXX
#define BBOT_UTILITY_HXX

#include <memory>    // make_shared()
#include <string>    // to_string(), stoull()
#include <utility>   // move(), forward(), declval(), make_pair()
#include <cassert>   // assert()
#include <iterator>  // make_move_iterator()
#include <algorithm> // *

#include <libbutl/ft/lang.hxx>

#include <libbutl/curl.hxx>
#include <libbutl/process.hxx>
#include <libbutl/process-io.hxx>
#include <libbutl/utility.hxx>    // icasecmp(), reverse_iterate(), etc
#include <libbutl/filesystem.hxx>

#include <bbot/types.hxx>
#include <bbot/version.hxx>

namespace bbot
{
  using std::move;
  using std::forward;
  using std::declval;

  using std::make_pair;
  using std::make_shared;
  using std::make_move_iterator;
  using std::to_string;
  using std::stoull;

  // <libbutl/utility.hxx>
  //
  using butl::ucase;
  using butl::make_ucase;
  using butl::lcase;
  using butl::make_lcase;
  using butl::icasecmp;
  using butl::sanitize_identifier;
  using butl::make_sanitized_identifier;
  using butl::reverse_iterate;

  using butl::make_guard;
  using butl::make_exception_guard;

  using butl::getenv;
  using butl::setenv;
  using butl::unsetenv;

  // <libbutl/filesystem.hxx>
  //
  using butl::auto_rmdir;
  using butl::auto_rmfile;

  // Process execution.
  //
  class tracer;

  using butl::process;
  using butl::process_env;
  using butl::process_exit;
  using butl::process_error;

  template <typename I, typename O, typename E, typename P, typename... A>
  void
  run_io (tracer&, I&& in, O&& out, E&& err, const P&, A&&...);

  template <typename I, typename O, typename E, typename P, typename... A>
  process_exit::code_type
  run_io_exit (tracer&, I&& in, O&& out, E&& err, const P&, A&&...);

  template <typename I, typename O, typename E, typename... A>
  process
  run_io_start (tracer&,
                I&& in,
                O&& out,
                E&& err,
                const process_env&,
                A&&...);

  template <typename P>
  void
  run_io_finish (tracer&, process&, const P&, bool fail_hard = true);

  template <typename P>
  process_exit::code_type
  run_io_finish_exit (tracer&, process&, const P&, bool fail_hard = true);

  template <typename P, typename... A>
  inline void
  run (tracer& t, const P& p, A&&... a)
  {
    run_io (t, butl::fdopen_null (), 2, 2, p, forward<A> (a)...);
  }

  template <typename P, typename... A>
  inline process_exit::code_type
  run_exit (tracer& t, const P& p, A&&... a)
  {
    return run_io_exit (
      t, butl::fdopen_null (), 2, 2, p, forward<A> (a)...);
  }

  // The curl process wrapper (command line tracing, etc).
  //
  class http_curl: public butl::curl
  {
  public:
    template <typename I, typename O, typename... A>
    http_curl (tracer&,
               I&& in,
               O&& out,
               method_type,
               const string& url,
               A&&... options);
  };

  class tftp_curl: public butl::curl
  {
  public:
    template <typename I, typename O, typename... A>
    tftp_curl (tracer&,
               I&& in,
               O&& out,
               method_type,
               const string& url,
               A&&... options);
  };

  // Manifest parsing and serialization.
  //
  // For parsing, if path is '-', then read from stdin. If path has the .lz4
  // extension, then assume the content is compressed.
  //
  template <typename T>
  T
  parse_manifest (const path&,
                  const char* what,
                  bool fail_hard = true,
                  bool ignore_unknown = true);

  template <typename T>
  T
  parse_manifest (istream&,
                  const string& name,
                  const char* what,
                  bool fail_hard = true,
                  bool ignore_unknown = true);

  template <typename T>
  void
  serialize_manifest (const T&,
                      const path&,
                      const char* what,
                      bool long_lines = false);

  template <typename T>
  void
  serialize_manifest (const T&,
                      ostream&,
                      const string& name,
                      const char* what,
                      bool fail_hard = true,
                      bool long_lines = false);
}

#include <bbot/utility.txx>

#endif // BBOT_UTILITY_HXX
