#include "km_internal.h"

/* The PKI systems known. */
PKI pki[2];

/*
  Initializes a specific key system.

  context       - System type.
  configuration - Specific configuration parameters.

  return - The status of initialization.
 */
KM_status_t KM_init(KM_context_t context, LG_context_t* ctx,
                    KM_context_data_t* configuration) {
  switch (context) {
    case KM_PGP:
      pki[context] = km_pgp_register();
      break;
    default:
      return KM_UNKNOWN_PKI;
  }
  return pki[context].init(ctx, configuration);
}

/*
  Termininates a specific context.

  context - Context to terminate.
 */
void KM_end(KM_context_t context) {
  pki[context].end();
}

/*
  Verifies the signature of a document.

  context   - System type.
  text      - Signed text.
  signature - Signature.

  return - A key_return structure.

  If signature is NULL then its considered that the signature is
  attached to the document.
 */
KM_key_return_t* KM_signature_verify(KM_context_t context, 
  gchar* text, gchar* signature) {
  //no init == seg fault
  return pki[context].signature_verify(text, signature);
}

/*
  Gets information about a key.

  context - System type.
  key     - Text representation of the key.

  return - A key_return structure.
 */
KM_status_t KM_key_get_info(KM_context_t context, 
  gchar* key, KM_key_return_t** pkr) {
  KM_key_return_t* kr;
  //no init == seg fault
  kr = pki[context].key_get_info(key);
  *pkr = kr;
  return KM_key_return_get_status(kr);
}

/*
  Adds a key to the key system.

  context - System type.
  key     - Text representation of the key.

  return - The status of the operation.
 */
KM_status_t KM_key_add(KM_context_t context, 
  gchar* key) {
  //no init == seg fault
  return pki[context].key_add(key);
}


/*
  Removes a key from the key system.

  context - System type.
  key_id  - Key Id.

  return - A key_return structure.
 */
KM_status_t KM_key_remove(KM_context_t context, 
  gchar* key_id) {
  //no init == seg fault
  if (key_id == NULL || strcmp(key_id, "") == 0) {
    return KM_NO_KEY;
  }
  return pki[context].key_remove(key_id);
}

/*
  Modifies a key in the key system.

  context - System type.
  key_id  - Key Id.
  key     - Text representation of the key.

  return - Status of the operation.
 */
KM_status_t KM_key_modify(KM_context_t context, 
  gchar* key_id, gchar* key) {
  //no init == seg fault
  if (key_id == NULL || strcmp(key_id, "") == 0) {
    return KM_NO_KEY;
  }
  return pki[context].key_update(key_id, key);
}

/*
  Commits a set of operations.

  context - System type.

  return - Status of the operation.
 */
KM_status_t KM_commit(KM_context_t context) {
  pki[context].commit();
}

/*
  Rolls back a set of operations.

  context - System type.

  return - Status of the operation.
 */
KM_status_t KM_rollback(KM_context_t context) {
  pki[context].rollback();
}

/*
  Creates a new context data structure.

  return - New context data structure.
 */
KM_context_data_t* KM_context_data_new() {
  GHashTable* hash;

  hash = g_hash_table_new(g_str_hash, g_str_equal);
  return (KM_context_data_t*)hash;
}

/*
  Adds data to a context data structure.

  context_data - Context data structure.
  key          - Key to the data.
  value        - Data.
 */
void KM_context_data_add(KM_context_data_t* context_data, gchar* key, gchar* value) {
  GHashTable* hash;

  hash = (GHashTable*) context_data;
  g_hash_table_insert(hash, g_strdup(key), g_strdup(value));
}

void km_hash_clear(gpointer key, gpointer value, gpointer user_data) {
  g_free(key);
  g_free(value);
}
/*
  Frees the context_data.

  context_data - Context data to be freed.
 */
void KM_context_data_free(KM_context_data_t* context_data) {
  GHashTable* hash;

  hash = (GHashTable*) context_data;
  g_hash_table_foreach(hash, km_hash_clear, NULL);
  g_hash_table_destroy(hash);
}


/*
  Creates a new key_return structure.

  key_id       - Key Id.
  signature_ok - TRUE is signature is correct, FALSE if not.
  signed_text  - Signed text (detached from the signature).
  status       - Status of the operation.

  return - Structure representing the given parameters.
 */
km_key_return_t* km_key_return_new(
  gchar* key_id, gboolean signature_ok, gchar* signed_text, KM_status_t status) {
  km_key_return_t* key_ret;

  key_ret = g_malloc(sizeof(km_key_return_t));

  if (key_id) {
    key_ret->key_id = g_malloc(strlen(key_id)+1);
    strcpy(key_ret->key_id, key_id);
  }
  else {
    key_ret->key_id = NULL;
  }
  key_ret->signature_ok = signature_ok;
  key_ret->status = status;
  if (signed_text) {
    key_ret->signed_text = g_malloc(strlen(signed_text)+1);
    strcpy(key_ret->signed_text, signed_text);
  }
  else {
    key_ret->signed_text = NULL;
  }
  key_ret->hash = g_hash_table_new(g_str_hash, g_str_equal);

  return key_ret;
}

static gboolean km_hash_remove(gpointer key,
  gpointer value, gpointer user_data) {
  g_free(key);
  g_free(value);
  return TRUE;
}

/*
  Frees a key_return structure.

  kr - The structure to free.
 */
void KM_key_return_free(KM_key_return_t* kr) {
  km_key_return_t* key_ret;

  key_ret = (km_key_return_t*)kr;

  g_free(key_ret->key_id);
  g_free(key_ret->signed_text);
  g_hash_table_foreach_remove(key_ret->hash, km_hash_remove, NULL);
  g_hash_table_destroy(key_ret->hash);
  g_free(key_ret);
}

/*
  Returns the signed text (without any signature) from a key_return.

  key_info - Key return structure with the signed text.

  return - Signed text.
 */
const gchar* KM_key_return_get_signed_text(KM_key_return_t* key_info) {
  return ((km_key_return_t*)key_info)->signed_text;
}

/*
  Returns the Key Id from a key_return.

  key_info - Key return structure with the key id.

  return - Key Id.
 */
const gchar* KM_key_return_get_key_id(KM_key_return_t* key_info) {
  return ((km_key_return_t*)key_info)->key_id;
}

/*
  Returns the status from a key_return.

  key_info - Key return structure with the status.

  return - Status.
 */
KM_status_t KM_key_return_get_status(KM_key_return_t* key_info) {
  return ((km_key_return_t*)key_info)->status;
}

/*
  Returns the signature validity from a key_return.

  key_info - Key return structure with the signature validity.

  return - Signature validity.
 */
gboolean KM_key_return_get_signature_ok(KM_key_return_t* key_info) {
  return ((km_key_return_t*)key_info)->signature_ok;
}

/*
  Adds a parameter to the key_return hash table

  key_info - Key return structure
  key      - (Hash)Key
  value    - Value

 */
void km_key_return_add(km_key_return_t* kr,
  gchar* key, gchar* value) {
  g_hash_table_insert(kr->hash, g_strdup(key), g_strdup(value));
}

/*
  Returns a parameter from the key_return hash table

  key_info - Key return structure
  key      - (Hash)Key

  return - Value (or NULL)
 */
const gchar* KM_key_return_get_parameter(KM_key_return_t* kr,
  gchar* key) {
  km_key_return_t* kkr;
 
  kkr = kr;
  return g_hash_table_lookup(kkr->hash, key);
}

