/* object OBJID_EXIT */

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

unsigned int objnew_EXIT(void *);

static void f_free(void *, void *);
static void f_draw(void *, struct VG_Object *);
static int f_data(void *, struct VG_Object *, void *);
static void f_signal(void *, struct VG_Object *, int);


/* export-function to create a new object-instance of OBJID_EXIT
 * @param vgame   private structure of the game
 * @return  instance-ID or 0 = error
 */
unsigned int
objnew_EXIT(void *vgame)
{
  const int coll_percent = 20;
  struct s_game *sgame = (struct s_game *)vgame;
  struct VG_Object *objp;
  struct sobj_exit *objvars;

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

  /* create private struct */

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

  /* load images and sprites */
  objvars->images.imgp_closed = vg4->image->load("files/images/exit/exit-closed.bmp");
  if (objvars->images.imgp_closed == NULL) { f_free(vgame, objvars); return 0; }
  objvars->images.imgp_opened = vg4->image->load("files/images/exit/exit-opened.bmp");
  if (objvars->images.imgp_opened == NULL) { f_free(vgame, objvars); return 0; }
  objvars->images.sprite_begin = vg4->sprite->load("files/images/exit/exit-begin.sprite");
  if (objvars->images.sprite_begin == NULL) { f_free(vgame, objvars); return 0; }
  objvars->images.sprite_end = vg4->sprite->load("files/images/exit/exit-end.sprite");
  if (objvars->images.sprite_end == NULL) { f_free(vgame, objvars); return 0; }

  vg4->image->getsize(objvars->images.imgp_closed, NULL, &objvars->rect.w, &objvars->rect.h);

  { struct VG_Point *pntp;
    pntp = (struct VG_Point *)vg4->hash->get(sgame->nodes.hnode, "1/1", NULL);
    my_assert(pntp != NULL);
    objvars->rect.x = pntp->x - objvars->rect.w / 2;
    objvars->rect.y = pntp->y - objvars->rect.h / 2;
  }

  /* create object-instance */
  objp = vg4->object->create(OBJID_EXIT, 0, 0, 2, objvars);
  objp->f_free = f_free;
  objp->f_draw = f_draw;
  objp->f_data = f_data;
  objp->f_signal = f_signal;

  /* set status */
  objvars->status = SOBJ_EXIT_BEGIN_1;

  /* 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_exit *objvars = (struct sobj_exit *)opriv;

  (void)vgame;

  /* free private struct */
  if (objvars->images.imgp_closed != NULL) { vg4->image->destroy(objvars->images.imgp_closed); }
  if (objvars->images.imgp_opened != NULL) { vg4->image->destroy(objvars->images.imgp_opened); }
  if (objvars->images.sprite_begin != NULL) { vg4->sprite->destroy(objvars->images.sprite_begin); }
  if (objvars->images.sprite_end != NULL) { vg4->sprite->destroy(objvars->images.sprite_end); }
  free(objvars);
}


/* 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_exit *objvars = (struct sobj_exit *)objp->opriv;
  struct VG_Image *imgp;
  struct VG_ImagecopyAttr iattr; 
  struct VG_Rect rect;

  if (sgame == NULL) { return; }

  imgp = NULL;
  VG_IMAGECOPY_ATTR_DEFAULT(&iattr);

  if (objvars->status == SOBJ_EXIT_BEGIN_1 || objvars->status == SOBJ_EXIT_END_1) {
    /* wait for background moved to exit-door */
    if (!sgame->suspend) {
      sgame->instanceid.focus = objp->instanceid;
      sgame->suspend = VG_TRUE;
    }
    vg4->object->call_data(sgame, sgame->instanceid.focus, &rect);
    if (vg4->misc->bgposition_reached(&rect)) { objvars->status++; }
  }

  if (objvars->status == SOBJ_EXIT_BEGIN_2 || objvars->status == SOBJ_EXIT_END_2) {
    /* show sprite for opening exit-door */
    if (!vg4->sprite->next((objvars->status == SOBJ_EXIT_BEGIN_2 ? objvars->images.sprite_begin : objvars->images.sprite_end), &imgp, &iattr)) {
      objvars->status++;
      sgame->instanceid.focus = 0;
    }
  }

  if (objvars->status == SOBJ_EXIT_BEGIN_3 || objvars->status == SOBJ_EXIT_END_3) {
    /* wait for background moved to player */
    vg4->object->call_data(sgame, sgame->instanceid.player, &rect);
    if (vg4->misc->bgposition_reached(&rect)) { sgame->suspend = VG_FALSE; objvars->status++; }
  }

  if (imgp == NULL) {
    if (objvars->status == SOBJ_EXIT_END_1) {
      imgp = objvars->images.imgp_closed;
    } else if (objvars->status == SOBJ_EXIT_END_3) {
      imgp = objvars->images.imgp_opened;
    } else if (objvars->status == SOBJ_EXIT_BEGIN_3) {
      imgp = objvars->images.imgp_closed;
    } else if (objvars->status == SOBJ_EXIT_CLOSED) {
      imgp = objvars->images.imgp_closed;
    } else if (objvars->status == SOBJ_EXIT_OPENED) {
      imgp = objvars->images.imgp_opened;
    }
  }

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


/* get/set data from/for object-instance, called from vg4->object->call_data() */
static int
f_data(void *vgame, struct VG_Object *objp, void *vptr)
{
  struct s_game *sgame = (struct s_game *)vgame;
  struct sobj_exit *objvars = (struct sobj_exit *)objp->opriv;
  struct VG_Rect *rect = (struct VG_Rect *)vptr;

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

  /* return position */
  *rect = objvars->rect;

  return 1;
}


/* receive signal, called from vg4->object->call_signal*() */
static void
f_signal(void *vgame, struct VG_Object *objp, int signo)
{
  struct s_game *sgame = (struct s_game *)vgame;
  struct sobj_exit *objvars = (struct sobj_exit *)objp->opriv;

  (void)sgame;

  if (signo == SIGNO_ACTIVE) {  /* set door open */
    objvars->status = SOBJ_EXIT_END_1;
  }
}
