/*
     This file is part of anastasis-gtk.
     Copyright (C) 2020 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.  If not, write to the
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     Boston, MA 02110-1301, USA.
*/
/**
 * @file src/anastasis/anastasis-gtk_handle-identity-changed.c
 * @brief
 * @author Christian Grothoff
 * @author Dennis Neufeld
 */
#include <gnunet/gnunet_util_lib.h>
#include "anastasis-gtk_helper.h"
#include "anastasis-gtk_action.h"
#include "anastasis-gtk_attributes.h"
#include "anastasis-gtk_handle-identity-changed.h"
#include <jansson.h>


/**
 * CSS class our style sheet paints in the "invalid input" colour.
 */
#define INVALID_CSS_CLASS "anastasis-invalid"


/**
 * Enable or disable highlighting of widget @a w as problematic.
 *
 * @param w widget to highlight, NULL is tolerated
 * @param on true to enable highlighting, false to disable
 */
static void
highlight (GtkWidget *w,
           bool on)
{
  if (NULL == w)
    return;
  if (on)
    gtk_widget_add_css_class (w,
                              INVALID_CSS_CLASS);
  else
    gtk_widget_remove_css_class (w,
                                 INVALID_CSS_CLASS);
}


void
AG_mark_invalid_input (const char *name)
{
  const json_t *id_attributes;
  size_t index;
  json_t *id_attr;

  id_attributes = json_object_get (AG_redux_state,
                                   "required_attributes");
  json_array_foreach (id_attributes, index, id_attr)
  {
    const char *widget_name = NULL;
    const char *attr_type;
    const char *attr_uuid;
    const char *attr_name;
    struct GNUNET_JSON_Specification spec[] = {
      GNUNET_JSON_spec_mark_optional (
        GNUNET_JSON_spec_string ("widget",
                                 &widget_name),
        NULL),
      GNUNET_JSON_spec_string ("type",
                               &attr_type),
      GNUNET_JSON_spec_string ("uuid",
                               &attr_uuid),
      GNUNET_JSON_spec_string ("name",
                               &attr_name),
      GNUNET_JSON_spec_end ()
    };
    GtkWidget *w = NULL;

    GNUNET_assert (GNUNET_OK ==
                   GNUNET_JSON_parse (id_attr,
                                      spec,
                                      NULL, NULL));
    if (NULL != widget_name)
    {
      char *data_name;

      data_name = AG_expand_name (widget_name,
                                  attr_type);
      w = GTK_WIDGET (GCG_get_main_window_object (data_name));
      GNUNET_free (data_name);
    }
    if (NULL == w)
    {
      struct GNUNET_HashCode uh;

      GNUNET_CRYPTO_hash (attr_uuid,
                          strlen (attr_uuid),
                          &uh);
      w = GNUNET_CONTAINER_multihashmap_get (AG_entry_attributes,
                                             &uh);
    }
    highlight (w,
               (0 == strcmp (name,
                             attr_name)));
    GNUNET_JSON_parse_free (spec);
  }
}


/**
 * Function called with the results of #ANASTASIS_redux_action.
 *
 * @param cls closure
 * @param error_code Error code
 * @param response new state as result or config information of provider
 */
static void
test_ok_cb (void *cls,
            enum TALER_ErrorCode error_code,
            json_t *response)
{
  bool *result = cls;
  const char *name;

  switch (error_code)
  {
  case TALER_EC_NONE:
    *result = true;
    AG_mark_invalid_input ("__none__");
    break;
  case TALER_EC_GENERIC_PARAMETER_MISSING:
    /* should not be possible */
    GNUNET_break (0);
    break;
  case TALER_EC_ANASTASIS_REDUCER_STATE_INVALID:
    /* should not be possible */
    GNUNET_break (0);
    break;
  case TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID:
    /* should not be possible */
    GNUNET_break (0);
    break;
  case TALER_EC_ANASTASIS_REDUCER_INPUT_REGEX_FAILED:
    name = json_string_value (json_object_get (response,
                                               "detail"));
    AG_mark_invalid_input (name);
    break;
  case TALER_EC_ANASTASIS_REDUCER_INPUT_VALIDATION_FAILED:
    name = json_string_value (json_object_get (response,
                                               "detail"));
    AG_mark_invalid_input (name);
    break;
  default:
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                "Unexpected error code %d from reducer\n",
                error_code);
    break;
  }
}


/**
 * Function to ckeck if required attributes are set.
 *
 * @return true if user-provided attributes satisfy the constraints
 */
static bool
check_attributes_fullfilled (void)
{
  struct ANASTASIS_ReduxAction *ta;
  json_t *args;
  bool result;

  args = AG_collect_attributes (false);
  if (NULL == args)
    return false;
  result = false;
  ta = ANASTASIS_redux_action (AG_redux_state,
                               "enter_user_attributes",
                               args,
                               &test_ok_cb,
                               &result);
  if (NULL != ta)
  {
    result = true;
    AG_mark_invalid_input ("__none__");
    ANASTASIS_redux_action_cancel (ta);
  }
  json_decref (args);
  return result;
}


void
AG_identity_changed (void)
{
  if (check_attributes_fullfilled ())
    AG_enable_next ();
  else
    AG_insensitive ("anastasis_gtk_main_window_forward_button");
}
