// Copyright 2022 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

/// @file testlib.h C API for Testlib, a very real library that does things

#ifndef TESTLIB_TESTLIB_H
#define TESTLIB_TESTLIB_H

#include <stdbool.h>
#include <stdint.h>

#if defined(_WIN32) && !defined(TESTLIB_STATIC) && defined(TESTLIB_INTERNAL)
#  define TESTLIB_API __declspec(dllexport)
#elif defined(_WIN32) && !defined(TESTLIB_STATIC)
#  define TESTLIB_API __declspec(dllimport)
#elif defined(__GNUC__)
#  define TESTLIB_API __attribute__((visibility("default")))
#else
#  define TESTLIB_API
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
   @defgroup testlib Testlib C API

   The public C API of testlib.  Testlib is a fake library interface that only
   exists to test <https://gitlab.com/drobilla/sphinxygen>.

   @{
*/

/**
   @defgroup testlib_macros Macros

   Macros show as a name or prototype.  The value isn't shown.

   @{
*/

/// A constant defined as a macro value
#define TESTLIB_CONSTANT 42

/**
   A macro to do something.

   @param x An integer.
   @return The next integer, `x + 1`.
*/
#define TESTLIB_SUCCESSOR(x) ((x) + 1)

/**
   @}
   @defgroup testlib_types Types

   Types are tricky because there's many cases and things can be recursive.

   @{
*/

/// Return status code
typedef enum {
  TESTLIB_SUCCESS,   ///< Operation successful
  TESTLIB_FAILURE,   ///< Non-fatal failure
  TESTLIB_BAD_THING, ///< Invalid thing
} TestlibStatus;

/**
   Flags to control behaviour.

   These are values which can be combined with bitwise OR to do various things
   in various places by various methods.  They are uppercase in order to be
   _emphatic_.

   One has to resort to HTML<br>
   to force line breaks within paragraphs.

   There are several reasons why this is good:

   - It's extensible?
   - You can almost feel the synergy.

   Let me count the ways:

   1. In that adding new flags doesn't take up more space.

   2. In that, uh... the thin veneer represents a symbiosis of low and high
      level conceptualization.  Yeah.
*/
typedef enum {
  /**
     Force operation.

     This overrides default safe behaviour that, for example, overwrites data,
     to force the operation to be performed if at all possible.
  */
  TESTLIB_FLAG_FORCE = 1u << 0u,

  /**
     Write verbose logging output.

     This makes log output noisier, mainly for debugging purposes.  It's really
     quite noisy.  You probably don't want to use this by default unless you're
     some kind of log masochist.
  */
  TESTLIB_FLAG_VERBOSE = 1u << 1u
} TestlibFlag;

/// A bitwise OR of #TestlibFlag values
typedef uint32_t TestlibFlags;

/**
   A function pointer.

   @param input Magical input value to do magical things with.
   @return A status.
*/
typedef TestlibStatus (*TestlibMagicFunc)(int input);

/**
   A thingie which does things to stuff.

   The nature of things is very complicated and important, and this lengthy
   description exists to clarify exactly why and how that is the case, and not
   at all to ramble on about nothing in order to have enough text here to make
   for a useful test case for documentation formatting.
*/
typedef struct TestlibThingieImpl TestlibThingie;

/// A linked list of integer values
typedef struct TestlibIntList {
  struct TestlibIntList* next;  ///< Next node in list, or null
  int                    value; ///< Value of this list element
} TestlibIntList;

/// A union that stores either an integer or real number
typedef union {
  int   integer; ///< Integer value
  float real;    ///< Real value
} TestlibIntOrReal;

/// A tagged (and named) union
typedef struct {
  int              tag;   ///< Type tag
  TestlibIntOrReal value; ///< Value
} TestlibTaggedUnion;

/// A struct with an array member
typedef struct {
  int  header;    ///< Type tag header
  char body[128]; ///< Packet body
} TestlibPacket;

/// A struct with a nested struct member
typedef struct {
  int tag; ///< Type tag header
  struct {
    int  mode;    ///< Mode of operation
    char data[4]; ///< Data for operation
  } contents;     ///< Payload
} TestlibNestedStruct;

/// A struct with an anonymous struct member
typedef struct {
  int first; ///< Plain first member
  struct {
    int second; ///< Second member inside an anonymous struct
  };
} TestlibNestedAnonymousStruct;

typedef struct {
  int secret;
} TestlibUndocumented;

/**
   @}
   @defgroup testlib_variables Variables
   @{
*/

/// A string
static const char* const testlib_manifesto = "A spectre is haunting Doxygen";

/// A version as an array of integers
static const int testlib_version[3] = {1, 2, 3};

/// The major version number of testlib
extern int testlib_major_version;

/// The minor version number of testlib
extern int testlib_minor_version;

/// The micro version number of testlib
extern int testlib_micro_version;

/// A pointer, which seems questionable, but whatever
extern int* testlib_sketchy_api;

/**
   @}
   @defgroup testlib_functions Functions

   Some functions to call.  Perhaps read the #testlib_manifesto first though?
   You won't end up on a list, I promise.  Best check the
   #testlib_major_version first as well!

   Members like #TestlibNestedStruct::tag can also be useful from time to time.

   @{
*/

/**
   @defgroup testlib_error_handling Error-Handling
   @{
*/

/// A type in the same group as a function
typedef enum {
  TESTLIB_BAD,   ///< Things are not great
  TESTLIB_WORSE, ///< Things are even less great than usual
} TestlibPessimisticStatus;

/**
   Return a human-readable description of `status`.

   You can call this like so:
   @code
   const char* message = testlib_strerror(status);
   if (!strcmp(message, "Success")) {
     printf("This is a terrible way to do error checking\n");
   }
   @endcode

   @param status Status code.
   @return A textual description of `status`.
*/
TESTLIB_API
const char*
testlib_strerror(TestlibStatus status);

/**
   @}
*/

/**
   Do something.

   @param value Some value.  This parameter value in particular has a rather
   long description, although it doesn't use `parblock` because Sphinx emits
   invalid HTML when multiple paragraphs are here.  It seems pretty esoteric
   anyway.

   @param label Stick a label on it.
   @param flags Flags to control how something is done.

   @return #TESTLIB_SUCCESS if things go rather well, #TESTLIB_FAILURE if
   things go, shall we say, not so well, and #TESTLIB_BAD_THING if things go
   very badly indeed.
*/
TESTLIB_API
TestlibStatus
testlib_do_something(int value, char* label, TestlibFlags flags);

/**
   Do nothing with a description that includes every special character entity.

   Right-left marker can do things like teleport the exclamation point in the
   title &ldquo;مفتاح معايير الويب!&rlm;&rdquo;.

   There is also a left-right marker which doesn't do much in this
   left-to-right documentation.&lrm;

   Several separators: thin&thinsp;space, en&ensp;space, em&emsp;space,
   zero&zwnj;width&zwnj;non-joiner, and zero&zwj;width&zwj;joiner.

   Special characters:
   &nbsp;
   &iexcl;
   &cent;
   &pound;
   &curren;
   &yen;
   &brvbar;
   &sect;
   &uml;
   &copy;
   &ordf;
   &laquo;
   &not;
   &shy;
   &reg;
   &macr;
   &deg;
   &plusmn;
   &sup2;
   &sup3;
   &acute;
   &micro;
   &middot;
   &cedil;
   &sup1;
   &ordm;
   &raquo;
   &frac14;
   &frac12;
   &frac34;
   &iquest;
   &Agrave;
   &Aacute;
   &Acirc;
   &Atilde;
   &Auml;
   &Aring;
   &AElig;
   &Ccedil;
   &Egrave;
   &Eacute;
   &Ecirc;
   &Euml;
   &Igrave;
   &Iacute;
   &Icirc;
   &Iuml;
   &ETH;
   &Ntilde;
   &Ograve;
   &Oacute;
   &Ocirc;
   &Otilde;
   &Ouml;
   &times;
   &Oslash;
   &Ugrave;
   &Uacute;
   &Ucirc;
   &Uuml;
   &Yacute;
   &THORN;
   &szlig;
   &agrave;
   &aacute;
   &acirc;
   &atilde;
   &auml;
   &aring;
   &aelig;
   &ccedil;
   &egrave;
   &eacute;
   &ecirc;
   &euml;
   &igrave;
   &iacute;
   &icirc;
   &iuml;
   &eth;
   &ntilde;
   &ograve;
   &oacute;
   &ocirc;
   &otilde;
   &ouml;
   &divide;
   &oslash;
   &ugrave;
   &uacute;
   &ucirc;
   &uuml;
   &yacute;
   &thorn;
   &yuml;
   &fnof;
   &Alpha;
   &Beta;
   &Gamma;
   &Delta;
   &Epsilon;
   &Zeta;
   &Eta;
   &Theta;
   &Iota;
   &Kappa;
   &Lambda;
   &Mu;
   &Nu;
   &Xi;
   &Omicron;
   &Pi;
   &Rho;
   &Sigma;
   &Tau;
   &Upsilon;
   &Phi;
   &Chi;
   &Psi;
   &Omega;
   &alpha;
   &beta;
   &gamma;
   &delta;
   &epsilon;
   &zeta;
   &eta;
   &theta;
   &iota;
   &kappa;
   &lambda;
   &mu;
   &nu;
   &xi;
   &omicron;
   &pi;
   &rho;
   &sigmaf;
   &sigma;
   &tau;
   &upsilon;
   &phi;
   &chi;
   &psi;
   &omega;
   &thetasym;
   &upsih;
   &piv;
   &bull;
   &hellip;
   &prime;
   &Prime;
   &oline;
   &frasl;
   &weierp;
   &image;
   &real;
   &trade;
   &alefsym;
   &larr;
   &uarr;
   &rarr;
   &darr;
   &harr;
   &crarr;
   &lArr;
   &uArr;
   &rArr;
   &dArr;
   &hArr;
   &forall;
   &part;
   &exist;
   &empty;
   &nabla;
   &isin;
   &notin;
   &ni;
   &prod;
   &sum;
   &minus;
   &lowast;
   &radic;
   &prop;
   &infin;
   &ang;
   &and;
   &or;
   &cap;
   &cup;
   &int;
   &there4;
   &sim;
   &cong;
   &asymp;
   &ne;
   &equiv;
   &le;
   &ge;
   &sub;
   &sup;
   &nsub;
   &sube;
   &supe;
   &oplus;
   &otimes;
   &perp;
   &sdot;
   &lceil;
   &rceil;
   &lfloor;
   &rfloor;
   &lang;
   &rang;
   &loz;
   &spades;
   &clubs;
   &hearts;
   &diams;
   &quot;
   &amp;
   &lt;
   &gt;
   &OElig;
   &oelig;
   &Scaron;
   &scaron;
   &Yuml;
   &circ;
   &tilde;
   &ndash;
   &mdash;
   &lsquo;
   &rsquo;
   &sbquo;
   &ldquo;
   &rdquo;
   &bdquo;
   &dagger;
   &Dagger;
   &permil;
   &lsaquo;
   &rsaquo;
   &euro;
   &tm;
   &apos;

   @return A status code that left its hometown.
*/
TESTLIB_API
TestlibStatus
testlib_cosmopolitan(void);

/**
   Demonstrate the unfortunate sloppiness of many-parametered functions.

   Ten internet points for anyone who can figure out how to make Sphinx align
   things nicely, or preserve alignment.

   Perhaps try testlib_do_something(), it's much less bother.

   @see testlib_cosmopolitan().

   @return A somewhat less magical status code.
*/
TESTLIB_API
TestlibStatus
testlib_unfortunately_long_function(const int      left,
                                    const int      right,
                                    const int      top,
                                    const int      bottom,
                                    const char*    title,
                                    const uint32_t identifier,
                                    const uint32_t flags);

/**
   @}
   @}
*/

#ifdef __cplusplus
} // extern "C"
#endif

#endif // TESTLIB_TESTLIB_H
