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

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU 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 pq/pq_result_helper.c
 * @brief functions to initialize parameter arrays
 * @author Johannes Casaburi
 */
#include "donau_config.h"
#include <taler/taler_pq_lib.h>
#include "donau_util.h"
#include "donau_pq_lib.h"

/**
 * Extract data from a Postgres database @a result at row @a row.
 *
 * @param cls closure
 * @param result where to extract data from
 * @param row the row to extract data from
 * @param fname name (or prefix) of the fields to extract from
 * @param[in,out] dst_size where to store size of result, may be NULL
 * @param[out] dst where to store the result
 * @return
 *   #GNUNET_YES if all results could be extracted
 *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
 */
static enum GNUNET_GenericReturnValue
extract_donation_unit_pub (void *cls,
                           PGresult *result,
                           int row,
                           const char *fname,
                           size_t *dst_size,
                           void *dst)
{
  struct DONAU_DonationUnitPublicKey *pk = dst;
  struct GNUNET_CRYPTO_BlindSignPublicKey *bpk;
  size_t len;
  const char *res;
  int fnum;
  uint32_t be[1];

  (void) cls;
  (void) dst_size;
  fnum = PQfnumber (result,
                    fname);
  if (fnum < 0)
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  if (PQgetisnull (result,
                   row,
                   fnum))
    return GNUNET_NO;

  /* if a field is null, continue but
   * remember that we now return a different result */
  len = PQgetlength (result,
                     row,
                     fnum);
  res = PQgetvalue (result,
                    row,
                    fnum);
  if (len < sizeof (be))
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  GNUNET_memcpy (be,
                 res,
                 sizeof (be));
  res += sizeof (be);
  len -= sizeof (be);
  bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
  bpk->cipher = ntohl (be[0]);
  bpk->rc = 1;
  switch (bpk->cipher)
  {
  case GNUNET_CRYPTO_BSA_INVALID:
    break;
  case GNUNET_CRYPTO_BSA_RSA:
    bpk->details.rsa_public_key
      = GNUNET_CRYPTO_rsa_public_key_decode (res,
                                             len);
    if (NULL == bpk->details.rsa_public_key)
    {
      GNUNET_break (0);
      GNUNET_free (bpk);
      return GNUNET_SYSERR;
    }
    GNUNET_CRYPTO_hash (res,
                        len,
                        &bpk->pub_key_hash);
    pk->bsign_pub_key = bpk;
    return GNUNET_OK;
  case GNUNET_CRYPTO_BSA_CS:
    if (sizeof (bpk->details.cs_public_key) != len)
    {
      GNUNET_break (0);
      GNUNET_free (bpk);
      return GNUNET_SYSERR;
    }
    GNUNET_memcpy (&bpk->details.cs_public_key,
                   res,
                   len);
    GNUNET_CRYPTO_hash (res,
                        len,
                        &bpk->pub_key_hash);
    pk->bsign_pub_key = bpk;
    return GNUNET_OK;
  }
  GNUNET_break (0);
  GNUNET_free (bpk);
  return GNUNET_SYSERR;
}


/**
 * Function called to clean up memory allocated
 * by a #GNUNET_PQ_ResultConverter.
 *
 * @param cls closure
 * @param rd result data to clean up
 */
static void
clean_donation_unit_pub (void *cls,
                         void *rd)
{
  struct DONAU_DonationUnitPublicKey *donation_unit_pub = rd;

  (void) cls;
  DONAU_donation_unit_pub_free (donation_unit_pub);
}


struct GNUNET_PQ_ResultSpec
DONAU_PQ_result_spec_donation_unit_pub (
  const char *name,
  struct DONAU_DonationUnitPublicKey *donation_unit_pub)
{
  struct GNUNET_PQ_ResultSpec res = {
    .conv = &extract_donation_unit_pub,
    .cleaner = &clean_donation_unit_pub,
    .dst = (void *) donation_unit_pub,
    .fname = name
  };

  return res;
}


/* end of pq_result_helper.c */
