/*
  This file is part of Anastasis
  Copyright (C) 2020, 2021, 2022 Anastasis SARL

  Anastasis 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.

  Anastasis 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
  Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file reducer/anastasis_api_redux_state.c
 * @brief lookup helpers for the typed reducer state
 * @author Christian Grothoff
 */
#include "platform.h"
#include "anastasis_redux.h"
#include "anastasis_api_redux.h"
#include "anastasis_api_redux_state.h"


void
ANASTASIS_REDUX_provider_url_set_ (struct ANASTASIS_ProviderUrl *pu,
                                   const char *url)
{
  GNUNET_free (pu->url);
  pu->url = GNUNET_strdup (url);
}


struct ANASTASIS_ReduxProvider *
ANASTASIS_REDUX_provider_find_ (const struct ANASTASIS_ReduxCommon *common,
                                const char *url)
{
  for (unsigned int i = 0; i < common->providers_len; i++)
    if (0 == strcmp (common->providers[i].url.url,
                     url))
      return &common->providers[i];
  return NULL;
}


struct ANASTASIS_ReduxProvider *
ANASTASIS_REDUX_provider_get_ (struct ANASTASIS_ReduxCommon *common,
                               const char *url)
{
  struct ANASTASIS_ReduxProvider *p;
  unsigned int off;

  p = ANASTASIS_REDUX_provider_find_ (common,
                                      url);
  if (NULL != p)
    return p;
  off = common->providers_len;
  GNUNET_array_append (common->providers,
                       common->providers_len,
                       (struct ANASTASIS_ReduxProvider) {
    .status = ANASTASIS_RPS_NOT_CONTACTED
  });
  common->have_providers = true;
  p = &common->providers[off];
  ANASTASIS_REDUX_provider_url_set_ (&p->url,
                                     url);
  return p;
}


struct ANASTASIS_ReduxFeedback *
ANASTASIS_REDUX_feedback_find_ (const struct ANASTASIS_ReduxRecovery *rr,
                                const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid)
{
  for (unsigned int i = 0; i < rr->challenge_feedback_len; i++)
    if (0 ==
        GNUNET_memcmp (&rr->challenge_feedback[i].uuid,
                       uuid))
      return &rr->challenge_feedback[i];
  return NULL;
}


struct ANASTASIS_ReduxFeedback *
ANASTASIS_REDUX_feedback_get_ (struct ANASTASIS_ReduxRecovery *rr,
                               const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid)
{
  struct ANASTASIS_ReduxFeedback *fb;
  unsigned int off;

  fb = ANASTASIS_REDUX_feedback_find_ (rr,
                                       uuid);
  if (NULL != fb)
  {
    /* Overwriting an earlier verdict: drop whatever the old variant
       owned so the caller can fill in a fresh one. */
    ANASTASIS_REDUX_feedback_clear_ (fb);
    return fb;
  }
  off = rr->challenge_feedback_len;
  GNUNET_array_append (rr->challenge_feedback,
                       rr->challenge_feedback_len,
                       (struct ANASTASIS_ReduxFeedback) {
    .uuid = *uuid
  });
  rr->have_challenge_feedback = true;
  return &rr->challenge_feedback[off];
}


struct ANASTASIS_ReduxChallengeInfo *
ANASTASIS_REDUX_challenge_find_ (const struct ANASTASIS_ReduxRecovery *rr,
                                 const struct
                                 ANASTASIS_CRYPTO_TruthUUIDP *uuid)
{
  if (NULL == rr->ri)
    return NULL;
  for (unsigned int i = 0; i < rr->ri->challenges_len; i++)
    if (0 ==
        GNUNET_memcmp (&rr->ri->challenges[i].uuid,
                       uuid))
      return &rr->ri->challenges[i];
  return NULL;
}


void
ANASTASIS_REDUX_return_ (struct ANASTASIS_ReduxState *rs,
                         ANASTASIS_ActionCallback cb,
                         void *cb_cls,
                         enum TALER_ErrorCode ec)
{
  json_t *json;

  json = ANASTASIS_REDUX_state_serialize_ (rs);
  GNUNET_assert (NULL != json);
  cb (cb_cls,
      ec,
      json);
  json_decref (json);
  ANASTASIS_REDUX_state_free_ (rs);
}


void
ANASTASIS_REDUX_fail_ (struct ANASTASIS_ReduxState *rs,
                       ANASTASIS_ActionCallback cb,
                       void *cb_cls,
                       enum TALER_ErrorCode ec,
                       const char *detail)
{
  ANASTASIS_redux_fail_ (cb,
                         cb_cls,
                         ec,
                         detail);
  ANASTASIS_REDUX_state_free_ (rs);
}


/* end of anastasis_api_redux_state.c */
