/* object OBJID_GD_DYN */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "obj-gd_dyn.h"

unsigned int objnew_GD_DYN(void *, int, int);

static void f_free(void *, void *);
static VG_BOOL f_run(void *, struct VG_Object *);
static void f_draw(void *, struct VG_Object *);

static const int coll_percent = 100;


/* export-function to create a new object-instance of OBJID_GD_DYN
 * @param vgame  private structure of the game
 * @param xm  x-position (centered)
 * @param ym  y-position (centered)
 * @return  instance-ID or 0 = error
 */
unsigned int
objnew_GD_DYN(void *vgame, int xm, int ym)
{
  struct s_game *sgame = (struct s_game *)vgame;
  struct VG_Object *objp;
  struct sobj_gd_dyn *objvars;

  if (sgame == NULL) { return 0; }

  /* create private struct */

  objvars = calloc(1, sizeof(*objvars));
  if (objvars == NULL) { return 0; }

  /* load sprites */
  objvars->images.dyn0 = vg4->image->load("files/images/goody/dyn/dyn.bmp");
  if (objvars->images.dyn0 == NULL) { f_free(vgame, objvars); return 0; }
  objvars->images.dyn1 = vg4->sprite->load("files/images/goody/dyn/dyn.sprite");
  if (objvars->images.dyn1 == NULL) { f_free(vgame, objvars); return 0; }
  objvars->images.expl = vg4->sprite->load("files/images/bomb/expl.sprite");
  if (objvars->images.expl == NULL) { f_free(vgame, objvars); return 0; }

  vg4->image->getsize(objvars->images.dyn0, NULL, &objvars->rect.w, &objvars->rect.h);
  vg4->sprite->imagesize(objvars->images.expl, "avg", &objvars->rect_expl.w, &objvars->rect_expl.h);

  objvars->rect.x = xm - objvars->rect.w / 2;
  objvars->rect.y = ym - objvars->rect.h / 2;
  objvars->rect_expl.x = xm - objvars->rect_expl.w / 2;
  objvars->rect_expl.y = ym - objvars->rect_expl.h / 2;

  objvars->status = SOBJ_GD_DYN_INACTIVE;

  /* create object-instance */
  objp = vg4->object->create(OBJID_GD_DYN, 0, 0, 3, objvars);
  objp->f_free = f_free;
  objp->f_run = f_run;
  objp->f_draw = f_draw;

  /* insert object-instance into collision-tag */
  vg4->collision->insert(sgame->coll_tag, objp->instanceid, &objvars->rect, coll_percent);

  return objp->instanceid;
}


/* free private struct of object-instance, called from vg4->object->destroy() */
static void
f_free(void *vgame, void *opriv)
{
  struct sobj_gd_dyn *objvars = (struct sobj_gd_dyn *)opriv;

  (void)vgame;

  /* free private struct */
  if (objvars->images.dyn0 != NULL) { vg4->image->destroy(objvars->images.dyn0); }
  if (objvars->images.dyn1 != NULL) { vg4->sprite->destroy(objvars->images.dyn1); }
  if (objvars->images.expl != NULL) { vg4->sprite->destroy(objvars->images.expl); }
  free(objvars);
}


/* move object-instance, called from vg4->object->call_run() */
static VG_BOOL
f_run(void *vgame, struct VG_Object *objp)
{
  struct s_game *sgame = (struct s_game *)vgame;
  struct sobj_gd_dyn *objvars = (struct sobj_gd_dyn *)objp->opriv;

  if (sgame == NULL) { return VG_TRUE; }

  if (objvars->status == SOBJ_GD_DYN_INACTIVE) { return VG_TRUE; }

  if (objvars->status == SOBJ_GD_DYN_ACTIVE) {
    if (!vg4->sprite->next(objvars->images.dyn1, NULL, NULL)) {
      struct VG_Coll *collp;
      int canz, ianz, ipos, ierg, idir, wplus, hplus;
      struct VG_Rect rect;

      /* remove object-instance from collision-tag */
      vg4->collision->remove(sgame->coll_tag, objp->instanceid);

      /* test dynamite position */
      vg4->collision->insert(sgame->coll_tag, objp->instanceid, &objvars->rect_expl, coll_percent);
      canz = vg4->collision->setpos(sgame->coll_tag, objp->instanceid, &objvars->rect_expl, &collp);
      vg4->object->collision_call(sgame, objp->instanceid, collp, canz);
      if (collp != NULL) { free(collp); }
      vg4->collision->remove(sgame->coll_tag, objp->instanceid);

      /* test adjacent dynamite positions */
      for (idir = 0; idir < 4; idir++) {
        ierg = 0;
        for (ipos = 1; ipos <= SOBJ_GD_DYN_RANGE; ipos++) {
          rect = objvars->rect_expl;
          wplus = rect.w * 3 / 4;
          hplus = rect.h * 3 / 4;
          switch(idir) {
            case 0: rect.y -= (hplus * ipos); break;  /* northwards */
            case 1: rect.x += (wplus * ipos); break;  /* eastwards */
            case 2: rect.y += (hplus * ipos); break;  /* southwards */
            case 3: rect.x -= (wplus * ipos); break;  /* westwards */
          }
          vg4->collision->insert(sgame->coll_tag, objp->instanceid, &rect, coll_percent);
          canz = vg4->collision->setpos(sgame->coll_tag, objp->instanceid, &rect, &collp);
          for (ianz = 0; ianz < canz; ianz++) {
            if (collp[ianz].type != VG_COLL_TYPE_ENTRY) { continue; }
            if (strcmp(collp[ianz].objid, OBJID_BOUNDARY) == 0) { ierg = 2; break; }
            if (strcmp(collp[ianz].objid, OBJID_OHARD) == 0 && collp[ianz].percent >= SOBJ_GD_DYN_DESTROY_PERCENT) { ierg = 1; }
            if (strcmp(collp[ianz].objid, OBJID_OSOFT) == 0 && collp[ianz].percent >= SOBJ_GD_DYN_DESTROY_PERCENT) { ierg = 1; }
          }
          if (ierg < 2) {
            switch(idir) {
              case 0: objvars->to_north = ipos; break;  /* northwards */
              case 1: objvars->to_east = ipos; break;  /* eastwards */
              case 2: objvars->to_south = ipos; break;  /* southwards */
              case 3: objvars->to_west = ipos; break;  /* westwards */
            }
            vg4->object->collision_call(sgame, objp->instanceid, collp, canz);
          }
          if (collp != NULL) { free(collp); }
          vg4->collision->remove(sgame->coll_tag, objp->instanceid);
          if (ierg > 0) { break; }
        }
      }

      objvars->status = SOBJ_GD_DYN_EXPLODING;
    }

  } else {
    if (!vg4->sprite->next(objvars->images.expl, NULL, NULL)) { vg4->object->destroy(vgame, objp->instanceid); return VG_TRUE; }
  }

  return VG_TRUE;
}


/* draw object-instance, called from vg4->object->call_draw() */
static void
f_draw(void *vgame, struct VG_Object *objp)
{
  struct s_game *sgame = (struct s_game *)vgame;
  struct sobj_gd_dyn *objvars = (struct sobj_gd_dyn *)objp->opriv;
  struct VG_Image *imgp;
  struct VG_ImagecopyAttr iattr;
  struct VG_Position posi;

  if (sgame == NULL) { return; }

  imgp = NULL;
  VG_IMAGECOPY_ATTR_DEFAULT(&iattr);

  if (objvars->status == SOBJ_GD_DYN_INACTIVE) {
    imgp = objvars->images.dyn0;
  } else if (objvars->status == SOBJ_GD_DYN_ACTIVE) {
    vg4->sprite->current(objvars->images.dyn1, &imgp, &iattr);
  } else {
    vg4->sprite->current(objvars->images.expl, &imgp, &iattr);
  }

  if (imgp != NULL) {
    if (objvars->status == SOBJ_GD_DYN_EXPLODING) {
      vg4->misc->rect2position(&posi, &objvars->rect_expl);
    } else {
      vg4->misc->rect2position(&posi, &objvars->rect);
    }
    posi = vg4->misc->bgposition_getobj(posi);
    vg4->window->copy(imgp, &posi, &iattr);

    if (objvars->status == SOBJ_GD_DYN_EXPLODING) {
      struct VG_Rect rect;
      int ipos, dplus;

      /* north */
      for (ipos = 1; ipos <= objvars->to_north; ipos++) {
        rect = objvars->rect_expl;
        dplus = rect.h * 3 / 4;
        rect.y -= (dplus * ipos);
        vg4->misc->rect2position(&posi, &rect);
        posi = vg4->misc->bgposition_getobj(posi);
        vg4->window->copy(imgp, &posi, &iattr);
      }

      /* east */
      for (ipos = 1; ipos <= objvars->to_east; ipos++) {
        rect = objvars->rect_expl;
        dplus = rect.w * 3 / 4;
        rect.x += (dplus * ipos);
        vg4->misc->rect2position(&posi, &rect);
        posi = vg4->misc->bgposition_getobj(posi);
        vg4->window->copy(imgp, &posi, &iattr);
      }

      /* south */
      for (ipos = 1; ipos <= objvars->to_south; ipos++) {
        rect = objvars->rect_expl;
        dplus = rect.h * 3 / 4;
        rect.y += (dplus * ipos);
        vg4->misc->rect2position(&posi, &rect);
        posi = vg4->misc->bgposition_getobj(posi);
        vg4->window->copy(imgp, &posi, &iattr);
      }

      /* west */
      for (ipos = 1; ipos <= objvars->to_west; ipos++) {
        rect = objvars->rect_expl;
        dplus = rect.w * 3 / 4;
        rect.x -= (dplus * ipos);
        vg4->misc->rect2position(&posi, &rect);
        posi = vg4->misc->bgposition_getobj(posi);
        vg4->window->copy(imgp, &posi, &iattr);
      }
    }
  }
}
