/*
   mkvmerge -- utility for splicing together matroska files
   from component media subtypes

   Distributed under the GPL v2
   see the file COPYING for details
   or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html

   definitions used in all programs, helper functions

   Written by Moritz Bunkus <moritz@bunkus.org>.
*/

#pragma once

#undef min
#undef max

#include "common/os.h"

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <functional>
#include <memory>
#include <numeric>
#include <optional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

#include <stdint.h>

#if !defined(HAVE_FMT_V8) || !HAVE_FMT_V8
// Don't support user-defined literals in fmt as they aren't used by
// MKVToolNix and produce a compiler warning in -Wpedantic with fmt < v8
#  define FMT_USE_USER_DEFINED_LITERALS 0
#endif

#include <fmt/format.h>
#include <fmt/ostream.h>

#include <boost/algorithm/string.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/gmp.hpp>

namespace balg = boost::algorithm;

using namespace std::string_literals;

#include <ebml/c/libebml_t.h>
#undef min
#undef max

#include <ebml/EbmlElement.h>
#include <ebml/EbmlMaster.h>

/* i18n stuff */
#if defined(HAVE_LIBINTL_H)
# include <libintl.h>
// libintl defines 'snprintf' to 'libintl_snprintf' on certain
// platforms such as mingw or macOS.  'std::snprintf' becomes
// 'std::libintl_snprintf' which doesn't exist.
# undef fprintf
# undef snprintf
# undef sprintf
#else
# define gettext(s)                            (s)
# define ngettext(s_singular, s_plural, count) ((count) != 1 ? (s_plural) : (s_singular))
#endif

#undef Y
#undef NY
#define Y(s)                            gettext(u8##s)
#define NY(s_singular, s_plural, count) ngettext(u8##s_singular, u8##s_plural, count)

#define BUGMSG Y("This should not have happened. Please file an issue at " \
                 "https://mkvtoolnix.download/issues with this error/warning " \
                 "message, a description of what you were trying to do, " \
                 "the command line used and which operating system you are " \
                 "using. Thank you.")

namespace mtx {
constexpr uint32_t calc_fourcc(char a, char b, char c, char d) {
  return (static_cast<uint32_t>(a) << 24)
       + (static_cast<uint32_t>(b) << 16)
       + (static_cast<uint32_t>(c) <<  8)
       +  static_cast<uint32_t>(d);
}
}

constexpr auto TIMESTAMP_SCALE = 1'000'000;

void mxrun_before_exit(std::function<void()> function);
[[noreturn]]
void mxexit(int code = -1);

extern unsigned int verbose;

void mtx_common_init(std::string const &program_name, char const *argv0);
std::string const &get_program_name();

#define MTX_DECLARE_PRIVATE(PrivateClass) \
  inline PrivateClass* p_func() { return reinterpret_cast<PrivateClass *>(&(*p_ptr)); } \
  inline const PrivateClass* p_func() const { return reinterpret_cast<const PrivateClass *>(&(*p_ptr)); } \
  friend class PrivateClass;

#define MTX_DECLARE_PUBLIC(Class)                                    \
  inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
  inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
  friend class Class;

#include "common/debugging.h"
#include "common/error.h"
#include "common/memory.h"
#include "common/mm_io.h"
#include "common/output.h"
