/*
  This file is part of TALER
  (C) 2014 Christian Grothoff (and other contributing authors)
  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, If not, see 
*/
/**
 * @file util/json.c
 * @brief helper functions for JSON processing using libjansson
 * @author Sree Harsha Totakura 
 */
#include "platform.h"
#include 
#include "taler_util.h"
#include "taler_json_lib.h"
/**
 * Shorthand for exit jumps.
 */
#define EXITIF(cond)                                              \
  do {                                                            \
    if (cond) { GNUNET_break (0); goto EXITIF_exit; }             \
  } while (0)
/**
 * Print JSON parsing related error information
 */
#define WARN_JSON(error)                                                \
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,                              \
                "JSON parsing failed at %s:%u: %s (%s)",                \
                __FILE__, __LINE__, error.text, error.source)
/**
 * Shorthand for JSON parsing related exit jumps.
 */
#define UNPACK_EXITIF(cond)                                              \
  do {                                                                  \
    if (cond) { WARN_JSON(error); goto EXITIF_exit; }                   \
  } while (0)
/**
 * Convert a TALER amount to a JSON
 * object.
 *
 * @param amount the amount
 * @return a json object describing the amount
 */
json_t *
TALER_JSON_from_amount (struct TALER_Amount amount)
{
  json_t *j;
  j = json_pack ("{s: s, s:I, s:I}",
                 "currency", amount.currency,
                 "value", (json_int_t) amount.value,
                 "fraction", (json_int_t) amount.fraction);
  GNUNET_assert (NULL != j);
  return j;
}
/**
 * Convert absolute timestamp to a json string.
 *
 * @param the time stamp
 * @return a json string with the timestamp in @a stamp
 */
json_t *
TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp)
{
  json_t *j;
  char *mystr;
  int ret;
  ret = GNUNET_asprintf (&mystr, "%llu",
                         (long long) (stamp.abs_value_us / (1000 * 1000)));
  GNUNET_assert (ret > 0);
  j = json_string (mystr);
  GNUNET_free (mystr);
  return j;
}
/**
 * Convert a signature (with purpose) to a JSON object representation.
 *
 * @param purpose purpose of the signature
 * @param signature the signature
 * @return the JSON reporesentation of the signature with purpose
 */
json_t *
TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
                     const struct GNUNET_CRYPTO_EddsaSignature *signature)
{
  json_t *root;
  json_t *el;
  root = json_object ();
  el = json_integer ((json_int_t) ntohl (purpose->size));
  json_object_set_new (root, "size", el);
  el = json_integer ((json_int_t) ntohl (purpose->purpose));
  json_object_set_new (root, "purpose", el);
  el = TALER_JSON_from_data (signature,
                             sizeof (struct GNUNET_CRYPTO_EddsaSignature));
  json_object_set_new (root, "sig", el);
  return root;
}
/**
 * Convert binary data to a JSON string
 * with the base32crockford encoding.
 *
 * @param data binary data
 * @param size size of @a data in bytes
 * @return json string that encodes @a data
 */
json_t *
TALER_JSON_from_data (const void *data, size_t size)
{
  char *buf;
  json_t *json;
  buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
  json = json_string (buf);
  GNUNET_free (buf);
  return json;
}
/**
 * Parse given JSON object to Amount
 *
 * @param json the json object representing Amount
 * @param r_amount where the amount has to be written
 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
 */
int
TALER_JSON_to_amount (json_t *json,
                      struct TALER_Amount *r_amount)
{
  char *currency;
  json_int_t value;
  json_int_t fraction;
  json_error_t error;
  UNPACK_EXITIF (0 != json_unpack_ex (json, &error, JSON_STRICT,
                                      "{s:s, s:I, s:I}",
                                      "curreny", ¤cy,
                                      "value", &value,
                                      "fraction", &fraction));
  EXITIF (3 < strlen (currency));
  r_amount->value = (uint32_t) value;
  r_amount->fraction = (uint32_t) fraction;
  return GNUNET_OK;
 EXITIF_exit:
  return GNUNET_SYSERR;
}
/**
 * Parse given JSON object to Amount
 *
 * @param json the json object representing Amount
 * @param r_amount where the amount has to be written
 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
 */
int
TALER_JSON_to_abs (json_t *json,
                   struct GNUNET_TIME_Absolute *abs)
{
  const char *str;
  unsigned long long abs_value_s;
  GNUNET_assert (NULL != abs);
  EXITIF (NULL == (str = json_string_value (json)));
  EXITIF (1 > sscanf (str, "%llu", &abs_value_s));
  abs->abs_value_us = abs_value_s * 1000 * 1000;
  return GNUNET_OK;
 EXITIF_exit:
  return GNUNET_SYSERR;
}
/**
 * Parse given JSON object to data
 *
 * @param json the json object representing data
 * @param out the pointer to hold the parsed data.
 * @param out_size the size of @a out
 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
 */
int
TALER_JSON_to_data (json_t *json,
                    void *out,
                    size_t out_size)
{
  const char *enc;
  unsigned int len;
  EXITIF (NULL == (enc = json_string_value (json)));
  len = strlen (enc);
  EXITIF ((((len * 5) / 8) + ((((len * 5) % 8) == 0) ? 0 : 1)) == out_size);
  EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, len, out, out_size));
  return GNUNET_OK;
 EXITIF_exit:
  return GNUNET_SYSERR;
}
/* End of util/json.c */