/*
  This file is part of TALER
  (C) 2025 Taler Systems SA

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU Lesser General Public License as published by the Free Software
  Foundation; either version 3, or (at your option) any later version.

  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file util/json.c
 * @brief helper functions to parse JSON
 * @author Christian Grothoff
 */
#include "platform.h"
#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
#include <taler/taler_json_lib.h>
#include <taler/taler_util.h>
#include "taler_merchant_util.h"


/**
 * Parse given JSON object to `enum TALER_MERCHANT_ContractInputType`
 *
 * @param cls closure, NULL
 * @param root the json object representing data
 * @param[out] spec where to write the data
 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
 */
static enum GNUNET_GenericReturnValue
parse_contract_input_type (void *cls,
                           json_t *root,
                           struct GNUNET_JSON_Specification *spec)
{
  static const struct Entry
  {
    const char *name;
    enum TALER_MERCHANT_ContractInputType val;
  } lt [] = {
#if FUTURE
    { .name = "coin",
      .val = TALER_MERCHANT_CONTRACT_INPUT_TYPE_COIN },
#endif
    { .name = "token",
      .val = TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN },
    { .name = NULL,
      .val = TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID }
  };
  enum TALER_MERCHANT_ContractInputType *res
    = (enum TALER_MERCHANT_ContractInputType *) spec->ptr;

  (void) cls;
  if (json_is_string (root))
  {
    const char *str;

    str = json_string_value (root);
    if (NULL == str)
    {
      GNUNET_break_op (0);
      return GNUNET_SYSERR;
    }
    for (unsigned int i = 0; NULL != lt[i].name; i++)
    {
      if (0 == strcasecmp (str,
                           lt[i].name))
      {
        *res = lt[i].val;
        return GNUNET_OK;
      }
    }
  }
  GNUNET_break_op (0);
  return GNUNET_SYSERR;
}


struct GNUNET_JSON_Specification
TALER_MERCHANT_json_spec_cit (const char *name,
                              enum TALER_MERCHANT_ContractInputType *cit)
{
  struct GNUNET_JSON_Specification ret = {
    .parser = &parse_contract_input_type,
    .field = name,
    .ptr = cit
  };

  *cit = TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID;
  return ret;
}


/**
 * Parse given JSON object to `enum TALER_MERCHANT_ContractOutputType`
 *
 * @param cls closure, NULL
 * @param root the json object representing data
 * @param[out] spec where to write the data
 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
 */
static enum GNUNET_GenericReturnValue
parse_contract_output_type (void *cls,
                            json_t *root,
                            struct GNUNET_JSON_Specification *spec)
{
  static const struct Entry
  {
    const char *name;
    enum TALER_MERCHANT_ContractOutputType val;
  } lt [] = {
    { .name = "token",
      .val = TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN },
    { .name = "tax-receipt",
      .val = TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT },
#if FUTURE
    { .name = "coin",
      .val = TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_COIN },
#endif
    { .name = NULL,
      .val = TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID }
  };
  enum TALER_MERCHANT_ContractOutputType *res
    = (enum TALER_MERCHANT_ContractOutputType *) spec->ptr;

  (void) cls;
  if (json_is_string (root))
  {
    const char *str;

    str = json_string_value (root);
    if (NULL == str)
    {
      GNUNET_break_op (0);
      return GNUNET_SYSERR;
    }
    for (unsigned int i = 0; NULL != lt[i].name; i++)
    {
      if (0 == strcasecmp (str,
                           lt[i].name))
      {
        *res = lt[i].val;
        return GNUNET_OK;
      }
    }
  }
  GNUNET_break_op (0);
  return GNUNET_SYSERR;
}


struct GNUNET_JSON_Specification
TALER_MERCHANT_json_spec_cot (const char *name,
                              enum TALER_MERCHANT_ContractOutputType *cot)
{
  struct GNUNET_JSON_Specification ret = {
    .parser = &parse_contract_output_type,
    .field = name,
    .ptr = cot
  };

  *cot = TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID;
  return ret;
}
