#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct  {
  long long Kontonummer;
  int Pin;
  float Guthaben;
  int Eingabe;
  int deleted;
} Kundendaten;

/*************************************************************************/
/* hash.c */

enum { HTS = 200 }; /* 100 Datensätze, d.h. möglichst mehr Einträge vorsehen */

typedef struct {
  int s;
  char (*knr)[99];
  Kundendaten *kl;
} Hte;

typedef struct {
  Hte liste[HTS];
} Ht;

static unsigned long hash(const char *k)
{ /* einfache Hashfunktion für Kontonummer als String */
  unsigned long c, r = 5381;
  while (c = *k++) {
    r = ((r << 5) + r) + c;
  }
  return r;
}

void *ht_get(void *t,const char*key)
{
  Ht *ht = t;
  Hte e = ht->liste[hash(key) % HTS];
  if (e.s)
  {
    int i;
    for (i = 0; i < e.s; ++i)
    if (!strcmp(key, e.knr[i]))
      return &e.kl[i];
  }
  return 0;
}

void ht_put(void *t, const char *key, Kundendaten k)
{
  Ht *ht = t;
  Hte *e = &ht->liste[hash(key) % HTS];
  e->kl = realloc(e->kl, (e->s + 1)*sizeof*e->kl);
  e->knr = realloc(e->knr, ++e->s*sizeof*e->knr);
  strcpy(e->knr[e->s - 1], key);
  memcpy(&e->kl[e->s - 1], &k, sizeof k);  
}

void ht_free(void*t)
{
  Ht *h = t;
  int i;
  for (i = 0; i < HTS; ++i)
  {
    Hte e = h->liste[i];
    if (e.s) free(e.knr), free(e.kl);
  }
  free(t);
}

void *ht_new(void)
{
  return calloc(HTS, sizeof(Ht));
}

void ht_printall(void *t, FILE*f, void (*pr)(Kundendaten, FILE *))
{
  Ht *h = t;
  int i;
  for (i = 0; i < HTS; ++i)
  {
    Hte e = h->liste[i];
    while (e.s--) pr(e.kl[e.s],f);
  }
}

/* hash.c Ende */
/*************************************************************************/


const char *kontostr(Kundendaten k)
{
  static char s[99];
  sprintf(s, "%lld", k.Kontonummer);
  return s;
}

void k_out(Kundendaten k, FILE *f)
{ /* Callback zur Ausgabe 1x Kunde */
  fprintf(f, "\n%lld : %d : %f : %d : %d", k.Kontonummer,
    k.Pin,
    k.Guthaben,
    k.Eingabe,
    k.deleted);
}

int main()
{
  void *ht = ht_new(); /* anonymer void Zeiger für Hashtable-Objekt, der Aufrufer braucht die Interna nicht wissen */

  Kundendaten k1 = { 12345678900, 4711, 1000., 100, 1 };
  Kundendaten k2 = { 12345678902, 4713, 1002., 888, 0 };
  Kundendaten k3 = { 12345678904, 4715, 1004., 0, 0 };

  ht_printall(ht, stdout, k_out);
  ht_put(ht, kontostr(k1), k1);
  ht_printall(ht, stdout, k_out);
  ht_put(ht, kontostr(k2), k2);
  ht_printall(ht, stdout, k_out);
  ht_put(ht, kontostr(k3), k3);
  ht_printall(ht, stdout, k_out);
  ht_put(ht, kontostr(k2), k2);
  ht_printall(ht, stdout, k_out);

  {
    Kundendaten *k = ht_get(ht, kontostr(k2));
    puts("\nKunde k2");
    k_out(*k, stdout);
  }
  
  ht_free(ht);
  return 0;
}
