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

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU Affero 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file taler_kyclogic_lib.h
 * @brief server-side KYC API
 * @author Christian Grothoff
 */
#ifndef TALER_KYCLOGIC_LIB_H
#define TALER_KYCLOGIC_LIB_H

#include "taler_exchangedb_plugin.h"
#include "taler_util.h"
#include "taler_kyclogic_plugin.h"


/**
 * KYC measure that can be taken.
 */
struct TALER_KYCLOGIC_Measure
{
  /**
   * Name of the KYC measure.
   */
  char *measure_name;

  /**
   * Name of the KYC check.
   */
  char *check_name;

  /**
   * Name of the AML program.
   */
  char *prog_name;

  /**
   * Context for the check. Can be NULL.
   */
  json_t *context;

  /**
   * Can this measure be triggered voluntarily?
   */
  bool voluntary;
};


/**
 * Information about a KYC provider.
 */
struct TALER_KYCLOGIC_KycProvider;


/**
 * Abstract representation of a KYC check.
 */
struct TALER_KYCLOGIC_KycCheck
{
  /**
   * Human-readable name given to the KYC check.
   */
  char *check_name;

  /**
   * Human-readable description of the check in English.
   */
  char *description;

  /**
   * Optional translations of @e description, can be
   * NULL.
   */
  json_t *description_i18n;

  /**
   * Array of fields that the context must provide as
   * inputs for this check.
   */
  char **requires;

  /**
   * Name of an original measure to take as a fallback
   * in case the check fails.
   */
  char *fallback;

  /**
   * Array of outputs provided by the check. Names of the attributes provided
   * by the check for the AML program.  Either from the configuration or
   * obtained via the converter.
   */
  char **outputs;

  /**
   * Length of the @e requires array.
   */
  unsigned int num_requires;

  /**
   * Length of the @e outputs array.
   */
  unsigned int num_outputs;

  /**
   * Type of the KYC check.
   */
  enum TALER_KYCLOGIC_CheckType type;

  /**
   * Details depending on @e type.
   */
  union
  {

    /**
     * Fields present only if @e type is #TALER_KYCLOGIC_CT_FORM.
     */
    struct
    {

      /**
       * Name of the form to render.
       */
      char *name;

    } form;

    /**
     * Fields present only if @e type is TALER_KYCLOGIC_CT_LINK.
     */
    struct
    {

      /**
       * Provider used.
       */
      const struct TALER_KYCLOGIC_KycProvider *provider;

    } link;

  } details;

};


/**
 * Rule that triggers some measure(s).
 */
struct TALER_KYCLOGIC_KycRule;

/**
 * Set of rules that applies to an account.
 */
struct TALER_KYCLOGIC_LegitimizationRuleSet;


/**
 * Parse KYC trigger string value from a string
 * into enumeration value.
 *
 * @param trigger_s string to parse
 * @param[out] trigger set to the value found
 * @return #GNUNET_OK on success, #GNUNET_NO if option
 *         does not exist, #GNUNET_SYSERR if option is
 *         malformed
 */
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_kyc_trigger_from_string (
  const char *trigger_s,
  enum TALER_KYCLOGIC_KycTriggerEvent *trigger);


/**
 * Initialize KYC subsystem. Loads the KYC configuration.
 *
 * @param cfg configuration to parse
 * @param cfg_fn configuration filename for AML helpers
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_kyc_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
                         const char *cfg_fn);


/**
 * Shut down the KYC subsystem.
 */
void
TALER_KYCLOGIC_kyc_done (void);


/**
 * Return JSON array with amounts with thresholds that
 * may change KYC requirements for the wallet.
 *
 * @return JSON array, NULL if no limits apply
 */
json_t *
TALER_KYCLOGIC_get_wallet_thresholds (void);


/**
 * Function called to iterate over KYC-relevant
 * transaction amounts for a particular time range.
 * Called within a database transaction, so must
 * not start a new one.
 *
 * @param cls closure, identifies the event type and
 *        account to iterate over events for
 * @param limit maximum time-range for which events
 *        should be fetched (timestamp in the past)
 * @param cb function to call on each event found,
 *        events must be returned in reverse chronological
 *        order
 * @param cb_cls closure for @a cb
 * @return transaction status
 */
typedef enum GNUNET_DB_QueryStatus
(*TALER_KYCLOGIC_KycAmountIterator)(
  void *cls,
  struct GNUNET_TIME_Absolute limit,
  TALER_EXCHANGEDB_KycAmountCallback cb,
  void *cb_cls);


/**
 * Function called to iterate over KYC-relevant
 * transaction thresholds amounts.
 *
 * @param cls closure, identifies the event type and
 *        account to iterate over events for
 * @param threshold a relevant threshold amount
 */
typedef void
(*TALER_KYCLOGIC_KycThresholdIterator)(
  void *cls,
  const struct TALER_Amount *threshold);


/**
 * Parse set of legitimization rules that applies to an account.
 *
 * @param jlrs JSON representation to parse
 * @return rule set, NULL if JSON is invalid
 */
struct TALER_KYCLOGIC_LegitimizationRuleSet *
TALER_KYCLOGIC_rules_parse (const json_t *jlrs);


/**
 * Free set of legitimization rules.
 *
 * @param[in] lrs set of rules to free
 */
void
TALER_KYCLOGIC_rules_free (struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs);


/**
 * Check if KYC is provided for a particular operation. Returns the set of
 * checks that still need to be satisfied.
 *
 * Called within a database transaction, so must
 * not start a new one.
 *
 * @param event what type of operation is triggering the
 *         test if KYC is required
 * @param lrs legitimization rules to apply;
 *         NULL to use default rules
 * @param ai callback offered to inquire about historic
 *         amounts involved in this type of operation
 *         at the given account
 * @param ai_cls closure for @a ai
 * @param[out] triggered_rule set to NULL if no rule
 *   is triggered, otherwise the rule with measures
 *   that must be satisfied (will be the highest
 *   applicable rule by display priority)
 * @param[out] next_threshold set to the next amount
 *   that may trigger a KYC check (note: only really
 *   useful for the wallet balance right now, as we
 *   cannot easily state the applicable timeframe)
 * @return transaction status
 */
enum GNUNET_DB_QueryStatus
TALER_KYCLOGIC_kyc_test_required (
  enum TALER_KYCLOGIC_KycTriggerEvent event,
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
  TALER_KYCLOGIC_KycAmountIterator ai,
  void *ai_cls,
  const struct TALER_KYCLOGIC_KycRule **triggered_rule,
  struct TALER_Amount *next_threshold);


/**
 * Return JSON array of AccountLimit objects with hard limits of this exchange
 * suitable for the "hard_limits" field of the "/keys" response.
 *
 * @return the JSON array of AccountLimit objects,
 *   empty array if there are no hard limits
 */
json_t *
TALER_KYCLOGIC_get_hard_limits (void);


/**
 * Return JSON array of ZeroLimitedOperation objects with
 * operations for which this exchange has a limit
 * of zero, that means KYC is always required (or
 * the operation is categorically forbidden).
 *
 * @return the JSON array of ZeroLimitedOperation objects,
 *   empty array if there are no hard limits
 */
json_t *
TALER_KYCLOGIC_get_zero_limits (void);


/**
 * Obtain the fallback measure to be run if @a prog_name fails
 *
 * @param prog_name name of an AML program
 * @return NULL if @a prog_name is unknown
 */
const char *
TALER_KYCLOGIC_get_aml_program_fallback (const char *prog_name);


/**
 * Obtain set of all measures that
 * could be triggered at an amount of zero and that
 * thus might be requested before a client even
 * has performed any operation.
 *
 * @param lrs rule set to investigate, NULL for default
 * @param is_wallet true to return measures for wallets,
 *    false to return measures for accounts
 * @return LegitimizationMeasures, NULL if there are no
 *   zero measures
 */
json_t *
TALER_KYCLOGIC_zero_measures (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
  bool is_wallet);


/**
 * Obtain set of all voluntary measures that
 * could be triggered by clients at will.
 *
 * @param lrs rule set to investigate, NULL for default
 * @return array of MeasureInformation, never NULL
 */
json_t *
TALER_KYCLOGIC_voluntary_measures (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs);


/**
 * Get human-readable name of KYC rule.
 *
 * @param r rule to convert
 * @return name of the rule
 */
const char *
TALER_KYCLOGIC_rule2s (const struct TALER_KYCLOGIC_KycRule *r);


/**
 * Convert KYC status to human-readable string.
 *
 * @param status status to convert
 * @return human-readable string
 */
const char *
TALER_KYCLOGIC_status2s (enum TALER_KYCLOGIC_KycStatus status);


/**
 * Get priority of KYC rule.
 *
 * @param r rule to convert
 * @return priority of the rule
 */
uint32_t
TALER_KYCLOGIC_rule2priority (const struct TALER_KYCLOGIC_KycRule *r);


/**
 * Iterate over all thresholds that are applicable to a particular type of @a
 * event under exposed global rules.
 *
 * @param event thresholds to look up
 * @param it function to call on each
 * @param it_cls closure for @a it
 */
void
TALER_KYCLOGIC_kyc_iterate_thresholds (
  enum TALER_KYCLOGIC_KycTriggerEvent event,
  TALER_KYCLOGIC_KycThresholdIterator it,
  void *it_cls);


/**
 * Check if a given @a rule can be satisfied in principle.
 *
 * @param rule the rule to check if it is verboten
 * @return true if the check can be satisfied,
 *         false if the check can never be satisfied,
 */
bool
TALER_KYCLOGIC_is_satisfiable (
  const struct TALER_KYCLOGIC_KycRule *rule);


/**
 * A KYC rule @a r has been triggered. Convert the resulting requirements into
 * JSON of type ``LegitimizationMeasures`` for the legitimization measures table.
 *
 * @param r a rule that was triggered
 * @return JSON serialization of the corresponding
 *   ``LegitimizationMeasures``, NULL on error
 */
json_t *
TALER_KYCLOGIC_rule_to_measures (
  const struct TALER_KYCLOGIC_KycRule *r);


/**
 * Tuple with information about a KYC check to perform.  Note that it will
 * have references into the legitimization rule set provided to
 * #TALER_KYCLOGIC_requirements_to_check() and thus has a lifetime that
 * matches the legitimization rule set.
 *
 * FIXME(fdold, 2024-11-07): Consider not making this public,
 * instead use struct TALER_KYCLOGIC_Measure.
 */
struct TALER_KYCLOGIC_KycCheckContext
{
  /**
   * KYC check to perform.
   */
  const struct TALER_KYCLOGIC_KycCheck *check;

  /**
   * Context for the check. Can be NULL.
   */
  const json_t *context;

  /**
   * Name of the AML program.
   */
  char *prog_name;
};


/**
 * A KYC check @a kcc has been triggered. Convert the resulting singular
 * requirement (only a single check is possible, not multiple alternatives)
 * into JSON of type ``LegitimizationMeasures`` for the legitimization
 * measures table.
 *
 * @param kcc check that was triggered
 * @return JSON serialization of the corresponding
 *   ``LegitimizationMeasures``
 */
json_t *
TALER_KYCLOGIC_check_to_jmeasures (
  const struct TALER_KYCLOGIC_KycCheckContext *kcc);


/**
 * Convert (internal) @a jrules to (public) @a jlimits.
 *
 * @param jrules a ``LegitimizationRuleSet`` with KYC rules;
 *     NULL to use default rules
 * @param is_wallet true if this is for a wallet
 * @return set to JSON array with public limits
 *   of type ``AccountLimit``
 */
json_t *
TALER_KYCLOGIC_rules_to_limits (const json_t *jrules,
                                bool is_wallet);


/**
 * Parse the given @a jmeasures and return the measure
 * at the @a measure_index.
 *
 * @param jmeasures a LegitimizationMeasures object
 * @param measure_index an index into the measures
 * @param[out] check_name set to the name of the check
 * @param[out] prog_name set to the name of the program
 * @param[out] context set to the measure context
 *   (or NULL if there is no context)
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TALER_KYCLOGIC_select_measure (
  const json_t *jmeasures,
  size_t measure_index,
  const char **check_name,
  const char **prog_name,
  const json_t **context);


/**
 * Check if the form data matches the requirements
 * of the selected measure.
 *
 * @param jmeasures a LegitimizationMeasures object
 * @param measure_index an index into the measures
 * @param form_data form data submitted for the measure
 * @param[out] form_name set to the form name (on success)
 * @param[out] error_message set to error details
 * @return #TALER_EC_NONE if the form data matches the measure
 */
enum TALER_ErrorCode
TALER_KYCLOGIC_check_form (
  const json_t *jmeasures,
  size_t measure_index,
  const json_t *form_data,
  char **form_name,
  const char **error_message);


/**
 * Convert MeasureInformation into the
 * KycRequirementInformation used by the client.
 *
 * @param check_name the prescribed check
 * @param prog_name the program to run
 * @param context context to return, can be NULL
 * @param access_token access token for the measure
 * @param offset offset of the measure
 * @param legitimization_measure_row_id row in the legitimization_measures table
 * @return JSON object with matching KycRequirementInformation
 */
json_t *
TALER_KYCLOGIC_measure_to_requirement (
  const char *check_name,
  const char *prog_name,
  const json_t *context,
  const struct TALER_AccountAccessTokenP *access_token,
  size_t offset,
  uint64_t legitimization_measure_row_id);


/**
 * Lookup measures from @a measures_spec in @a lrs and create JSON object with
 * the corresponding LegitimizationMeasures.
 *
 * @param lrs set of legitimization rules
 * @param measures_spec space-separated set of a measures to trigger from @a lrs; "+"-prefixed if AND-cominbation applies
 * @return JSON object of type LegitimizationMeasures
 */
json_t *
TALER_KYCLOGIC_get_jmeasures (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
  const char *measures_spec);

/**
 * Lookup the provider for the given @a check_name.
 *
 * @param check_name check to lookup provider for
 * @return NULL on error (@a check_name unknown or
 *    not a check that has a provider)
 */
const struct TALER_KYCLOGIC_KycProvider *
TALER_KYCLOGIC_check_to_provider (const char *check_name);


/**
 * Extract logic data from a KYC @a provider.
 *
 * @param provider provider to get logic data from
 * @param[out] plugin set to the KYC logic API
 * @param[out] pd set to the specific operation context
 * @param[out] provider_name set to the name
 *    of the KYC provider
 */
void
TALER_KYCLOGIC_provider_to_logic (
  const struct TALER_KYCLOGIC_KycProvider *provider,
  struct TALER_KYCLOGIC_Plugin **plugin,
  struct TALER_KYCLOGIC_ProviderDetails **pd,
  const char **provider_name);


/**
 * Find default measure @a measure_name.
 *
 * @param measure_name name of measure to find
 * @param[out] kcc initialized with KYC check data
 *    for the default measure
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_get_original_measure (
  const char *measure_name,
  struct TALER_KYCLOGIC_KycCheckContext *kcc);


/**
 * Obtain the provider logic for a given set of @a lrs
 * and a specific @a kyc_rule from @a lrs that was
 * triggered and the chosen @a measure_name from the
 * list of measures of that @a kyc_rule.  Can also be
 * used to obtain the "current" check of a @a lrs if
 * no trigger has been hit.
 *
 * @param lrs rule set
 * @param kyc_rule rule that was triggered, NULL
 *   to merely lookup the measure without any trigger
 * @param measure_name selected measure,
 *   NULL to return the "new_check" set by the @a lrs
 * @param[out] kcc set to check to run;
 *   kcc->check will be NULL if the "skip" check is used
 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
 */
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_requirements_to_check (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
  const struct TALER_KYCLOGIC_KycRule *kyc_rule,
  const char *measure_name,
  struct TALER_KYCLOGIC_KycCheckContext *kcc);


/**
 * Obtain the provider logic for a given @a name.
 *
 * @param name name of the logic or provider
 * @param[out] plugin set to the KYC logic API
 * @param[out] pd set to the specific operation context
 * @param[out] configuration_section set to the name of the KYC logic configuration section
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TALER_KYCLOGIC_lookup_logic (
  const char *name,
  struct TALER_KYCLOGIC_Plugin **plugin,
  struct TALER_KYCLOGIC_ProviderDetails **pd,
  const char **configuration_section);


/**
 * Return expiration time for the given @a lrs
 *
 * @param lrs legitimization rules to inspect
 * @return expiration time
 */
struct GNUNET_TIME_Timestamp
TALER_KYCLOGIC_rules_get_expiration (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs);


/**
 * Return successor measure for the given @a lrs
 *
 * @param lrs legitimization rules to inspect
 * @return successor measure;
 *    NULL to fall back to default rules;
 *    pointer will be valid as long as @a lrs is valid
 */
const struct TALER_KYCLOGIC_Measure *
TALER_KYCLOGIC_rules_get_successor (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs);


/**
 * Function called with the provider details and
 * associated plugin closures for matching logics.
 *
 * @param cls closure
 * @param pd provider details of a matching logic
 * @param plugin_cls closure of the plugin
 * @return #GNUNET_OK to continue to iterate
 */
typedef enum GNUNET_GenericReturnValue
(*TALER_KYCLOGIC_DetailsCallback)(
  void *cls,
  const struct TALER_KYCLOGIC_ProviderDetails *pd,
  void *plugin_cls);


/**
 * Call @a cb for all logics with name @a logic_name,
 * providing the plugin closure and the @a pd configurations.
 * Obtain the provider logic for a given set of @a lrs
 * and a specific @a kyc_rule from @a lrs that was
 * triggered and the chosen @a measure_name from the
 * list of measures of that @a kyc_rule.
  *
 * @param logic_name name of the logic to match
 * @param cb function to call on matching results
 * @param cb_cls closure for @a cb
 */
void
TALER_KYCLOGIC_kyc_get_details (
  const char *logic_name,
  TALER_KYCLOGIC_DetailsCallback cb,
  void *cb_cls);


/**
 * Return configuration data useful for the
 * /aml/$PUB/measures endpoint.
 *
 * @param[out] proots set to the root measures
 * @param[out] pprograms set to available AML programs
 * @param[out] pchecks set to available KYC checks
 */
void
TALER_KYCLOGIC_get_measure_configuration (
  json_t **proots,
  json_t **pprograms,
  json_t **pchecks);


/**
 * Check if there is a measure triggered by the
 * KYC rule @a r that has a check name of "SKIP" and
 * thus should be immediately executed. If such a
 * measure exists, return it.
 *
 * @param r rule to check for instant measures
 * @return NULL if there is no instant measure
 */
const struct TALER_KYCLOGIC_Measure *
TALER_KYCLOGIC_rule_get_instant_measure (
  const struct TALER_KYCLOGIC_KycRule *r);


/**
 * Check if there is a measure in @a lrs
 * that is included in @a measure_spec
 * and a SKIP measure, and thus should be immediately
 * executed.
 *
 * @param lrs legitimization rule set
 * @param measures_spec measures spec
 * @returns NULL if there is no instant measure
 */
const struct TALER_KYCLOGIC_Measure *
TALER_KYCLOGIC_get_instant_measure (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
  const char *measures_spec);


/**
 * Return default legitimization rule set in JSON.
 *
 * @param for_wallet true to return only rules that apply to
 *         wallets, false to return only rules that apply to accounts
 * @return default legitimization rules
 */
json_t *
TALER_KYCLOGIC_get_default_legi_rules (bool for_wallet);

/**
 * Check if there is a measure in @a lrs that is named @a measure.
 *
 * @param lrs legitimization rule set
 * @param measure_name measures spec
 * @returns NULL if not found
 */
const struct TALER_KYCLOGIC_Measure *
TALER_KYCLOGIC_get_measure (
  const struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs,
  const char *measure_name);


/**
 * Convert a measure to JSON.
 *
 * @param m measure to convert to JSON
 * @returns JSON representation of the measure
 */
json_t *
TALER_KYCLOGIC_measure_to_jmeasures (
  const struct TALER_KYCLOGIC_Measure *m);


/**
 * Handle to manage a running AML program.
 */
struct TALER_KYCLOGIC_AmlProgramRunnerHandle;


/**
 * Result from running an AML program.
 */
struct TALER_KYCLOGIC_AmlProgramResult
{
  /**
   * Possible outcomes from running the AML program.
   */
  enum
  {
    /**
     * The AML program completed successfully.
     */
    TALER_KYCLOGIC_AMLR_SUCCESS,

    /**
     * The AML program failed.
     */
    TALER_KYCLOGIC_AMLR_FAILURE

  } status;

  /**
   * Detailed results depending on @e status.
   */
  union
  {
    /**
     * Results if @e status is #TALER_KYCLOGIC_AMLR_SUCCESS.
     */
    struct
    {
      /**
       * New account properties to set for the account.
       */
      const json_t *account_properties;

      /**
       * Array of events to trigger.
       */
      const char **events;

      /**
       * New AML/KYC rules to apply to the account.
       */
      const json_t *new_rules;

      /**
       * New measures to trigger immediately.
       */
      const char *new_measures;

      /**
       * When do the new rules expire.
       */
      struct GNUNET_TIME_Timestamp expiration_time;

      /**
       * Length of the @e events array.
       */
      unsigned int num_events;

      /**
       * True if AML staff should investigate the account.
       */
      bool to_investigate;
    } success;

    /**
     * Results if @e status is #TALER_KYCLOGIC_AMLR_FAILURE.
     */
    struct
    {
      /**
       * Fallback measure to trigger.
       */
      const char *fallback_measure;

      /**
       * Human-readable error message describing the
       * failure (for logging).
       */
      const char *error_message;

      /**
       * Error code for the failure.
       */
      enum TALER_ErrorCode ec;

    } failure;

  } details;

};


/**
 * Type of function called after AML program was run.
 *
 * @param cls closure
 * @param apr result of the AML program.
 */
typedef void
(*TALER_KYCLOGIC_AmlProgramResultCallback) (
  void *cls,
  const struct TALER_KYCLOGIC_AmlProgramResult *apr);


/**
 * Type of function called to obtain an AML or KYC
 * history in JSON on-demand if needed.
 *
 * @param cls closure
 * @return AML or KYC history in JSON format, NULL on error
 */
typedef json_t *
(*TALER_KYCLOGIC_HistoryBuilderCallback) (void *cls);


/**
 * Run AML program based on @a jmeasures using
 * the the given inputs.
 *
 * @param jmeasures current KYC/AML rules to apply;
 *           they determine also the AML program and
 *           provide the context
 * @param is_wallet true if this is for a wallet
 * @param measure_index which KYC measure yielded the
 *       @a attributes
 * @param current_attributes_cb function to get current KYC attributes
 * @param current_attributes_cb_cls closure for @a current_attributes_cb
 * @param current_rules_cb callback to get current KYC rules that apply to the account
 * @param current_rules_cb_cls closure for @a current_rules_cb
 * @param aml_history_cb callback to get the AML history of the account
 * @param aml_history_cb_cls closure for @a aml_history_cb
 * @param kyc_history_cb callback to get the KYC history of the account
 * @param kyc_history_cb_cls closure for @a aml_history_cb
 * @param timeout timeout for running the AML program;
 *  terminates the AML program and runs the fallback measure immediately
 *  once the timeout is reached; in this case, the result from the
 *  fallback measure is returned; the fallback measure is also granted
 *  the same amount of time (so after 2x @a timeout we will call @a aprc)
 * @param aprc function to call with the result
 * @param aprc_cls closure for @a aprc
 * @return NULL if @a jmeasures is invalid for the
 *   selected @a measure_index or @a attributes
 */
struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
TALER_KYCLOGIC_run_aml_program (
  const json_t *jmeasures,
  bool is_wallet,
  unsigned int measure_index,
  TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
  void *current_attributes_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
  void *current_rules_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
  void *aml_history_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
  void *kyc_history_cb_cls,
  struct GNUNET_TIME_Relative timeout,
  TALER_KYCLOGIC_AmlProgramResultCallback aprc,
  void *aprc_cls);


/**
 * Run AML program @a prog_name with the given @a context.
 *
 * @param prog_name name of AML program to run
 * @param context context to run with
 * @param is_wallet true if this is for a wallet
 * @param current_attributes_cb function to get current KYC attributes
 * @param current_attributes_cb_cls closure for @a current_attributes_cb
 * @param current_rules_cb callback to get current KYC rules that apply to the account
 * @param current_rules_cb_cls closure for @a current_rules_cb
 * @param aml_history_cb callback to get the AML history of the account
 * @param aml_history_cb_cls closure for @a aml_history_cb
 * @param kyc_history_cb callback to get the KYC history of the account
 * @param kyc_history_cb_cls closure for @a aml_history_cb
 * @param timeout timeout for running the AML program;
 *  terminates the AML program and runs the fallback measure immediately
 *  once the timeout is reached; in this case, the result from the
 *  fallback measure is returned; the fallback measure is also granted
 *  the same amount of time (so after 2x @a timeout we will call @a aprc)
 * @param aprc function to call with the result
 * @param aprc_cls closure for @a aprc
 * @return NULL if @a jmeasures is invalid for the
 *   selected @a measure_index or @a attributes
 */
struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
TALER_KYCLOGIC_run_aml_program2 (
  const char *prog_name,
  const json_t *context,
  bool is_wallet,
  TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
  void *current_attributes_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
  void *current_rules_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
  void *aml_history_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
  void *kyc_history_cb_cls,
  struct GNUNET_TIME_Relative timeout,
  TALER_KYCLOGIC_AmlProgramResultCallback aprc,
  void *aprc_cls);


/**
 * Run AML program specified by the given
 * measure.
 *
 * @param is_wallet true if this is for a wallet
 * @param measure measure with program name and context
 *         to run
 * @param current_attributes_cb function to get current KYC attributes
 * @param current_attributes_cb_cls closure for @a current_attributes_cb
 * @param current_rules_cb callback to get current KYC rules that apply to the account
 * @param current_rules_cb_cls closure for @a current_rules_cb
 * @param aml_history_cb callback to get the AML history of the account
 * @param aml_history_cb_cls closure for @a aml_history_cb
 * @param kyc_history_cb callback to get the KYC history of the account
 * @param kyc_history_cb_cls closure for @a aml_history_cb
 * @param timeout timeout for running the AML program;
 *  terminates the AML program and runs the fallback measure immediately
 *  once the timeout is reached; in this case, the result from the
 *  fallback measure is returned; the fallback measure is also granted
 *  the same amount of time (so after 2x @a timeout we will call @a aprc)
 * @param aprc function to call with the result
 * @param aprc_cls closure for @a aprc
 * @return NULL if @a jmeasures is invalid for the
 *   selected @a measure_index or @a attributes
 */
struct TALER_KYCLOGIC_AmlProgramRunnerHandle *
TALER_KYCLOGIC_run_aml_program3 (
  bool is_wallet,
  const struct TALER_KYCLOGIC_Measure *measure,
  TALER_KYCLOGIC_HistoryBuilderCallback current_attributes_cb,
  void *current_attributes_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback current_rules_cb,
  void *current_rules_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback aml_history_cb,
  void *aml_history_cb_cls,
  TALER_KYCLOGIC_HistoryBuilderCallback kyc_history_cb,
  void *kyc_history_cb_cls,
  struct GNUNET_TIME_Relative timeout,
  TALER_KYCLOGIC_AmlProgramResultCallback aprc,
  void *aprc_cls);


/**
 * Get the name of the AML program run by @a aprh.
 * Can of course only be called while @a aprh is running.
 *
 * @param aprh handle to the AML program
 * @return name of the AML program
 */
const char *
TALER_KYCLOGIC_run_aml_program_get_name (
  const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh);


/**
 * Cancel running AML program.
 *
 * @param[in] aprh handle of program to cancel
 */
void
TALER_KYCLOGIC_run_aml_program_cancel (
  struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh);


/**
 * Handle to a sanction list evaluation helper process.
 */
struct TALER_KYCLOGIC_SanctionRater;

/**
 * Function called with the result of a sanction evaluation.
 *
 * @param cls closure
 * @param ec error code, #TALER_EC_NONE on success
 * @param best_match identifies the sanction list entry with the best match
 * @param expiration_time when does the sanction list entry expire
 * @param rating likelihood of the match, from 0 (none) to 1 (perfect)
 * @param confidence confidence in the evaluation, from 0 (none) to 1 (perfect)
 */
typedef void
(*TALER_KYCLOGIC_SanctionResultCallback)(
  void *cls,
  enum TALER_ErrorCode ec,
  const char *best_match,
  struct GNUNET_TIME_Timestamp expiration_time,
  double rating,
  double confidence);


/**
 * Launch sanction rating helper process
 *
 * @param binary program name
 * @param argv argument to give to the process
 * @return handle for sanction list rating
 */
struct TALER_KYCLOGIC_SanctionRater *
TALER_KYCLOGIC_sanction_rater_start (
  const char *binary,
  char *const*argv);


/**
 * KYC evaluation.
 */
struct TALER_KYCLOGIC_EvaluationEntry;

/**
 * Evaluate KYC attributes against sacntions list using @a sr
 *
 * @param[in,out] sr santion list evaluator
 * @param attributes KYC attributes to evaluate
 * @param cb function to call with the results
 * @param cb_cls closure
 * @return NULL on error
 */
struct TALER_KYCLOGIC_EvaluationEntry *
TALER_KYCLOGIC_sanction_rater_eval (
  struct TALER_KYCLOGIC_SanctionRater *sr,
  const json_t *attributes,
  TALER_KYCLOGIC_SanctionResultCallback cb,
  void *cb_cls);


/**
 * Stop sanction rating helper process.
 *
 * @param[in] sr process to stop
 */
void
TALER_KYCLOGIC_sanction_rater_stop (
  struct TALER_KYCLOGIC_SanctionRater *sr);

#endif
