#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "main.h"

void get_node_near_position(struct s_game *, int, int, char *, size_t);
void set_goody_to_osoft(struct s_game *);
void create_new_goody(struct s_game *, const char *, int, int);


/* get nearest node of a x,y position */
void
get_node_near_position(struct s_game *sgame, int xm, int ym, char *hkey, size_t keysize)
{
  struct VG_Point *pntp;
  int ileft, iright, ix, iy, ialt, ipnt;
  char buf[32];

  if (sgame == NULL) { return; }

  ialt = -1;
  ix = ileft = 0;
  iright = sgame->nodes.max_x - 1;
  while (ileft <= iright) {
    ix = (ileft + iright) / 2;
    snprintf(buf, sizeof(buf), "%d/1", ix + 1);
    pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, buf, NULL);
    my_assert(pntp != NULL);
    if (pntp->x > xm) {
      iright = ialt = ix - 1;
    } else if (pntp->x < xm) {
      ileft = ialt = ix + 1;
    } else {
      ialt = -1;
      break;
    }
  }
  if (ialt >= 0 && ialt <= sgame->nodes.max_x - 1) {
    ipnt = pntp->x;
    snprintf(buf, sizeof(buf), "%d/1", ialt + 1);
    pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, buf, NULL);
    my_assert(pntp != NULL);
    if (abs(pntp->x - xm) < abs(ipnt - xm)) { ix = ialt; }
  }

  ialt = -1;
  iy = ileft = 0;
  iright = sgame->nodes.max_y - 1;
  while (ileft <= iright) {
    iy = (ileft + iright) / 2;
    snprintf(buf, sizeof(buf), "1/%d", iy + 1);
    pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, buf, NULL);
    my_assert(pntp != NULL);
    if (pntp->y > ym) {
      iright = ialt = iy - 1;
    } else if (pntp->y < ym) {
      ileft = ialt = iy + 1;
    } else {
      ialt = -1;
      break;
    }
  }
  if (ialt >= 0 && ialt <= sgame->nodes.max_y - 1) {
    ipnt = pntp->y;
    snprintf(buf, sizeof(buf), "1/%d", ialt + 1);
    pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, buf, NULL);
    my_assert(pntp != NULL);
    if (abs(pntp->y - ym) < abs(ipnt - ym)) { iy = ialt; }
  }

  if (hkey != NULL && keysize > 0) {
    snprintf(hkey, keysize, "%d/%d", ix + 1, iy + 1);
  }
}


/* set a goody to a OBJID_OSOFT */
void
set_goody_to_osoft(struct s_game *sgame)
{
  int numberof, ipos;
  unsigned int *idlist;
  unsigned char *gdlist;
  unsigned short *osoftlist;
  enum { goody_key = 1, goody_keyhole, goody_bombs, goody_dyn, goody_heart, goody_pill, goody_portal, goody_gold, goody_max };
  int goodyf[goody_key + goody_max], gdidx, gdx, i1, i2, i0;
  char *gton[] = {
    NULL,
    OBJID_GD_KEY,
    OBJID_GD_KEYHOLE,
    OBJID_GD_BOMBS,
    OBJID_GD_DYN,
    OBJID_GD_HEART,
    OBJID_GD_PILL,
    OBJID_GD_PORTAL,
    OBJID_GD_GOLD,
    NULL
  };

  if (sgame == NULL) { return; }

  /* number of OBJID_OSOFT */
  numberof = vg4->object->list(OBJID_OSOFT, 0, &idlist);
  if (numberof == 0) { return; }

  /* number of each goody */
  goodyf[goody_key] = goodyf[goody_keyhole] = 1;
  goodyf[goody_bombs] = 3 - (sgame->svdt.dnew.gamelevel + 1) / 2;
  goodyf[goody_dyn] = (10 + ZUFALL("MISC", 0, 8)) * numberof / 100;
  goodyf[goody_heart] = 2;
  goodyf[goody_pill] = 2;
  goodyf[goody_portal] = (4 + sgame->svdt.dnew.gamelevel * 3 / 2) * numberof / 100;
  goodyf[goody_gold] = 30 * numberof / 100;

#ifdef VERBOSE
  gdx = 0;
  for (gdidx = goody_key; gdidx < goody_max; gdidx++) {
    fprintf(stderr, "Goody(%s)=%d\n", gton[gdidx], goodyf[gdidx]);
    gdx += goodyf[gdidx];
  }
  fprintf(stderr, "Numberof(osoft)=%d, Goody-sum=%d\n", numberof, gdx);
#endif

  /* list of goodies */
  gdlist = calloc(numberof, sizeof(*gdlist));
  my_assert(gdlist != NULL);
  ipos = 0;
  for (gdidx = goody_key; gdidx < goody_max; gdidx++) {
    for (gdx = 0; gdx < goodyf[gdidx]; gdx++) {
      gdlist[ipos++] = gdidx;
    }
  }
  for (ipos = 0; ipos < numberof; ipos++) {
    i1 = ZUFALL("MISC", 0, numberof - 1);
    i2 = ZUFALL("MISC", 0, numberof - 1);
    i0 = gdlist[i1];
    gdlist[i1] = gdlist[i2];
    gdlist[i2] = i0;
  }

  /* list of OBJID_OSOFT */
  osoftlist = calloc(numberof, sizeof(*osoftlist));
  my_assert(osoftlist != NULL);
  for (ipos = 0; ipos < numberof; ipos++) {
    osoftlist[ipos] = ipos;
  }
  for (ipos = 0; ipos < numberof; ipos++) {
    i1 = ZUFALL("MISC", 0, numberof - 1);
    i2 = ZUFALL("MISC", 0, numberof - 1);
    i0 = osoftlist[i1];
    osoftlist[i1] = osoftlist[i2];
    osoftlist[i2] = i0;
  }

  /* set goodies to instances */
  for (ipos = 0; ipos < numberof; ipos++) {
    vg4->object->call_data(sgame, idlist[osoftlist[ipos]], gton[gdlist[ipos]]);
  }

  free(gdlist);
  free(osoftlist);

  if (idlist != NULL) { free(idlist); }
}


/* create a goody object-instance */
void
create_new_goody(struct s_game *sgame, const char *objid, int xm, int ym)
{
  if (sgame == NULL || objid == NULL) { return; }

  if (strcmp(objid, OBJID_GD_KEY) == 0) {
    objnew_GD_KEY(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_KEYHOLE) == 0) {
    objnew_GD_KEYHOLE(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_BOMBS) == 0) {
    objnew_GD_BOMBS(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_DYN) == 0) {
    objnew_GD_DYN(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_HEART) == 0) {
    objnew_GD_HEART(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_PILL) == 0) {
    objnew_GD_PILL(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_PORTAL) == 0) {
    objnew_GD_PORTAL(sgame, xm, ym);
  } else if (strcmp(objid, OBJID_GD_GOLD) == 0) {
    objnew_GD_GOLD(sgame, xm, ym);
  }
}
