#include <u.h>
#include <sys/stat.h>
#include <libc.h>
#include <stdio.h>
#include "config.h"
#include "util.h"
#include "cart.h"
#include "realm.h"
#include "user.h"

extern UserInfo users_table[64];

UserInfo* find_user(UserInfo* table, char* uname) {
  UserInfo* u = table;
  int i;
  for (i = 0; i < MAX_USERS; i++) {
    if (scmp(uname, u->name))
      return u;
    u++;
  }
  return nil;
}

int* ctl_code_handle(UserInfo* table, char* uname) {
  UserInfo* u = find_user(table, uname);
  if (u != nil)
    return &(u->ctl_code);
  return nil;
}

int login(UserInfo* table, char* uname, char* password) {
  UserInfo* u = find_user(table, uname);

  if (u == nil)
    return 0;

  u->password = hash(password, 0);
  return 1;
}

int logout(UserInfo* table, char* uname) {
  UserInfo* u = table;

  if (u == nil)
    return 0;

  *(u->name) = 0;
  u->password = 0;

  if (u->scope != nil) {
    free(u->scope);
    u->scope = nil;
  }

  u->random = -1;

  if (u->realm != nil)
    leave_realm(table, uname);

  if (u->cart != nil)
    unload_cart(table, uname);

  return 1;
}

int protect_realm(UserInfo* table, char* uname, char* password) {
  UserInfo* u = find_user(table, uname);

  if (u != nil && u->realm != nil && scmp(uname, u->realm->master)) {
    u->realm->password = hash(password, 0);
    return 1;
  }
  return 0;
}

int transfer_realm(UserInfo* table, char* from, char* to) {
  UserInfo* old_user = find_user(table, from);
  UserInfo* new_user = find_user(table, to);

  if (old_user == nil || new_user == nil || old_user->realm == nil)
    return 0;

  scpy(to, old_user->realm->master, 32);
  return 1;
}

int load_cart(UserInfo* table, char* uname, char* cart_name) {
  UserInfo* u = find_user(table, uname);

  if (u == nil)
    return 0;

  u->cart = create_cart(cart_name);
  if (u->cart == nil) {
    fprintf(stderr, "failed creating cart\n");
    return 0;
  } else {
    return 1;
  }
}

int enter_realm(UserInfo* table, char* uname, char* realm_name) {
  Realm* r = find_realm(table, realm_name);
  UserInfo* u = find_user(table, uname);
  int i, j = 0;

  if (u == nil) {
    fprintf(stderr, "no user\n");
    return 0;
  }
  if (u->cart == nil) {
    fprintf(stderr, "no cart\n");
    return 0;
  }

  for (i = 0; i < MAX_USERS; i++) {
    if (table[i].realm != nil && scmp(table[i].realm->name, realm_name))
      j++;
  }

  if (r != nil) {
    if (j < r->max) {
      u->realm = r;
      return 1;
    } else {
      return 0;
    }
  } else {
    r = parse_realm(u->cart->name, realm_name);
    if (r == nil)
      return 0;
    if (j >= r->max)
      return 0;
    u->realm = r;
    return 1;
  }
}

int leave_realm(UserInfo* table, char* uname) {
  UserInfo* u = find_user(table, uname);
  Realm* r;

  if (u == nil) {
    fprintf(stderr, "couldn't find user: %s\n", uname);
    return 0;
  }

  r = u->realm;
  if (r == nil) {
    fprintf(stderr, "%s is not in a realm!\n", uname);
    return 0;
  }

  if (u->cart == nil)
    return 0;

  save_realm(u->cart->name, r);
  u->realm = nil;
  if (find_realm(table, r->name) == nil)
    destroy_realm(r);
  return 1;
}

int unload_cart(UserInfo* table, char* uname) {
  UserInfo* u = find_user(table, uname);

  if (u == nil || u->cart == nil)
    return 0;

  destroy_cart(u->cart);
  u->cart = nil;
  return 1;
}

int delete_realm(UserInfo* table, char* uname, char* realm) {
  UserInfo* u = find_user(table, uname);
  char path[256] = {0};
  char file[256] = {0};
  Blob* realm_data;
  char garbage[32] = {0};
  char master[32] = {0};
  int i;
  if (u == nil || u->cart == nil) {
    fprintf(stderr, "no user/cart\n");
    return 0;
  }

  for (i = 0; i < MAX_USERS; i++) {
    if (table[i].realm != nil && scmp(table[i].realm->name, realm)) {
      fprintf(stderr, "realm not empty\n");
      return 0;
    }
  }

  scat(path, DATA_DIR);
  scat(path, u->cart->name);
  scat(path, "/realms/");
  scat(path, realm);
  scpy(path, file, 256);
  ccat(file, '/');
  scat(file, "realm");

  fprintf(stderr, "%s\n", file);
  realm_data = read_chars(file);
  if (realm_data == nil)
    return 0;

  sscanf(
    realm_data->data,
    "%u %32s %llu",
    (uint*)garbage,
    master,
    (uvlong*)garbage);
  if (scmp(master, uname) && rm_dir(path))
    return 1;
  else
    return 0;
}