/* Copyright 2022-2026 Kurt Nienhaus
 *
 * This file is part of VgaGames.
 * VgaGames is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * VgaGames is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with VgaGames.  If not, see <http://www.gnu.org/licenses/>.
 */

/* testing collisions, errors to stderr
 * gcc -W -Wall -O2 -g qtest.c `vgagames4-config --cflags --libs` -I.. -I../../extlib/sml3 -o qtest
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <vgagames4.h>
#include "quadtree.h"

#define MAX_OBJ 64
#define PERCENT 80

static struct {
  int k_quit;
} kref;

static struct s_objs {
  VG_BOOL aktiv;
  struct VG_Rect rect;
  int color;
  int xdir, ydir;
} objs[MAX_OBJ], *objsp;

static struct VG_Object vgobj[MAX_OBJ], *vgobjp;

struct s_coll {
  VG_BOOL iscoll;
  struct VG_Coll coll;
};


int main(int argc, char **argv)
{
  struct vgi_quadtree qdtr;
  int i1, i2, oanz, canz, ipos, next_random, hits;
  int winw, winh;
  struct VG_Coll *collp;
  struct VG_Rect rect1, rect2;
  struct s_coll bcoll[MAX_OBJ];
  char buf[64];
  struct VG_Image *imgp;

  if (!VG_init("test")) { exit(1); }
  if (!vg4->window->open(VG_WINDOW_SIZE_LOW, VG_WINDOW_SCALE_NONE)) { VG_dest(); exit(1); }
  vg4->window->getsize(&winw, &winh);

  quadtree_init(&qdtr, 0, NULL, 0, 0);

  memset(objs, 0, sizeof(objs));
  for (ipos = 0; ipos < MAX_OBJ; ipos++) {
    memset(&vgobj[ipos], 0, sizeof(*vgobj));
    vgobj[ipos].opriv = &objs[ipos];
    if (ipos % 3 == 0) {
      objs[ipos].rect.w = 25;
      objs[ipos].rect.h = 10;
      objs[ipos].color = VG_COLOR_RGB(0, 128, 128);
      vg4->misc->strcpy(vgobj[ipos].objid, sizeof(vgobj[0].objid), "OID1");
    } else if (ipos % 3 == 1) {
      objs[ipos].rect.w = 20;
      objs[ipos].rect.h = 20;
      objs[ipos].color = VG_COLOR_RGB(128, 0, 128);
      vg4->misc->strcpy(vgobj[ipos].objid, sizeof(vgobj[0].objid), "OID2");
    } else {
      objs[ipos].rect.w = 30;
      objs[ipos].rect.h = 30;
      objs[ipos].color = VG_COLOR_RGB(128, 128, 0);
      vg4->misc->strcpy(vgobj[ipos].objid, sizeof(vgobj[0].objid), "OID3");
    }
    vg4->object->instance_create(&vgobj[ipos]);
    objs[ipos].rect.x = winw * ipos / MAX_OBJ;
    objs[ipos].rect.y = winh / 2;
    quadtree_insert(&qdtr, vgobj[ipos].instanceid, &objs[ipos].rect, PERCENT);
    objs[ipos].aktiv = VG_TRUE;
  }

  if ((kref.k_quit = vg4->input->key_insert("Quit", VG_FALSE, VG_FALSE)) == 0) { VG_dest(); exit(1); }
  vg4->input->key_setkbd(kref.k_quit, VG_INPUT_KBDCODE_Q);

  next_random = 0;
  hits = 0;

  for (;;) {
    if (!vg4->input->update(VG_TRUE)) { fprintf(stderr, "Exit-Req\n"); break; }
    if (vg4->input->key_newpressed(kref.k_quit)) { break; }

    vg4->window->clear();

    if (next_random == 0) {
      ipos = vg4->random->get("ipos", 0, MAX_OBJ - 1);
      vgobjp = vg4->object->instance_getobj(vgobj[ipos].instanceid);
      objsp = vgobjp->opriv;
      if (objsp->aktiv) {
        quadtree_remove(&qdtr, vgobjp->instanceid);
        objsp->aktiv = VG_FALSE;
        oanz = 0; for (i1 = 0; i1 < MAX_OBJ; i1++) { if (objs[i1].aktiv) { oanz++; }; }
        printf("Remove %d => %d\n", vgobjp->instanceid, oanz);
      } else {
        objsp->xdir = objsp->ydir = 0;
        quadtree_insert(&qdtr, vgobjp->instanceid, &objsp->rect, PERCENT);
        objsp->aktiv = VG_TRUE;
        oanz = 0; for (i1 = 0; i1 < MAX_OBJ; i1++) { if (objs[i1].aktiv) { oanz++; }; }
        printf("Add %d => %d\n", vgobjp->instanceid, oanz);
      }
      next_random = vg4->random->get("next", 50, 100);
    } else {
      next_random--;
    }

    oanz = 0;
    for (ipos = 0; ipos < MAX_OBJ; ipos++) {
      vgobjp = vg4->object->instance_getobj(vgobj[ipos].instanceid);
      objsp = vgobjp->opriv;
      if (!objsp->aktiv) { continue; }
      oanz++;

      if (objsp->xdir != 0) {
        objsp->rect.x += objsp->xdir;
        if (objsp->rect.x + objsp->rect.w - 1 >= winw) {
          objsp->rect.x = winw - objsp->rect.w;
          objsp->xdir = 0;
        } else if (objsp->rect.x < 0) {
          objsp->rect.x = 0;
          objsp->xdir = 0;
        }
      } else {
        objsp->xdir = vg4->random->get("xdir", 0, 4) - 2;
      }

      if (objsp->ydir != 0) {
        objsp->rect.y += objsp->ydir;
        if (objsp->rect.y + objsp->rect.h - 1 >= winh) {
          objsp->rect.y = winh - objsp->rect.h;
          objsp->ydir = 0;
        } else if (objsp->rect.y < 0) {
          objsp->rect.y = 0;
          objsp->ydir = 0;
        }
      } else {
        objsp->ydir = vg4->random->get("ydir", 0, 4) - 2;
      }

      vg4->window->draw_rect(&objsp->rect, objsp->color, VG_TRUE);

      memset(bcoll, 0, sizeof(bcoll));
      canz = quadtree_setpos(&qdtr, vgobjp->instanceid, &objsp->rect, &collp);
      for (i1 = 0; i1 < canz; i1++) {
        for (i2 = 0; i2 < MAX_OBJ; i2++) {
          if (vgobj[i2].instanceid == collp[i1].instanceid) { break; }
        }
        if (i2 == MAX_OBJ) { fprintf(stderr, "Instance-ID %u not found\n", collp[i1].instanceid); abort(); }
        if (collp[i1].type == VG_COLL_TYPE_ENTRY || collp[i1].type == VG_COLL_TYPE_REPEAT) {
          bcoll[i2].iscoll = VG_TRUE;
          bcoll[i2].coll = collp[i1];
        }
      }
      if (collp != NULL) { free(collp); }

      rect1.w = objsp->rect.w * PERCENT / 100;
      rect1.h = objsp->rect.h * PERCENT / 100;
      rect1.x = objsp->rect.x + (objsp->rect.w - rect1.w) / 2;
      rect1.y = objsp->rect.y + (objsp->rect.h - rect1.h) / 2;
      for (i1 = 0; i1 < MAX_OBJ; i1++) {
        if (i1 == ipos) { continue; }
        if (!objs[i1].aktiv) { continue; }
        rect2.w = objs[i1].rect.w * PERCENT / 100;
        rect2.h = objs[i1].rect.h * PERCENT / 100;
        rect2.x = objs[i1].rect.x + (objs[i1].rect.w - rect2.w) / 2;
        rect2.y = objs[i1].rect.y + (objs[i1].rect.h - rect2.h) / 2;
        if (rect1.x + rect1.w - 1 >= rect2.x && rect1.x <= rect2.x + rect2.w - 1
            && rect1.y + rect1.h - 1 >= rect2.y && rect1.y <= rect2.y + rect2.h - 1) {
          if (!bcoll[i1].iscoll) {
            fprintf(stderr, "False-No-Hit: %d[%d+%d,%d+%d] -> %d[%d+%d,%d+%d]\n",
              vgobjp->instanceid, rect1.x, rect1.w, rect1.y, rect1.h,
              vgobj[i1].instanceid, rect2.x, rect2.w, rect2.y, rect2.h);
          }
          hits++;
        } else if (bcoll[i1].iscoll) {
          fprintf(stderr, "False-Hit: %d[%d+%d,%d+%d] -> %d[%d+%d,%d+%d]\n",
            vgobjp->instanceid, rect1.x, rect1.w, rect1.y, rect1.h,
            vgobj[i1].instanceid, rect2.x, rect2.w, rect2.y, rect2.h);
        }
      }
    }
    if (oanz < MAX_OBJ / 2) { next_random = 0; }

    snprintf(buf, sizeof(buf), "Hits=%d", hits);
    imgp = vg4->font->totext(buf, NULL, NULL, NULL, NULL);
    if (imgp != NULL) {
      vg4->window->copy(imgp, NULL, NULL);
      vg4->image->destroy(imgp);
    }

    quadtree_mark(&qdtr, NULL, VG_COLOR_WHITE, NULL);

    vg4->window->flush();
    vg4->misc->wait_time(50);
  }

  quadtree_dump(stdout, &qdtr);
  quadtree_dest(&qdtr);
  VG_dest();
  exit(0);
}
