/* 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/>.
 */

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

int bitfld_anz(struct vgi_bitfld *);
void bitfld_set(struct vgi_bitfld *, int);
VG_BOOL bitfld_get(struct vgi_bitfld *, int);
void bitfld_del(struct vgi_bitfld *, int);
int bitfld_next(struct vgi_bitfld *, int);
int bitfld_unused(struct vgi_bitfld *, int);


/* return number of bit-positions */
int
bitfld_anz(struct vgi_bitfld *pbf)
{
  if (pbf == NULL) { return 0; }
  return pbf->bfanz;
} /* Ende vgi_bitfld_anz */


/* set bit-position */
void
bitfld_set(struct vgi_bitfld *pbf, int bpos)
{
  int d8, m8;

  if (pbf == NULL || bpos < 0) { return; }

  d8 = bpos / 8;
  m8 = bpos % 8;

  if ((unsigned int)d8 >= pbf->bfsize) {
    if (pbf->bfeld == NULL) {
      pbf->bfeld = SML3_malloc(sizeof(*pbf->bfeld) * (d8 + 1));
    } else {
      pbf->bfeld = SML3_realloc(pbf->bfeld, sizeof(*pbf->bfeld) * (d8 + 1));
    }
    memset(pbf->bfeld + pbf->bfsize, 0, sizeof(*pbf->bfeld) * (size_t)(d8 + 1 - pbf->bfsize));
    pbf->bfsize = d8 + 1;
  }

  if (!(pbf->bfeld[d8] & (1 << m8))) {
    pbf->bfeld[d8] |= (1 << m8);
    pbf->bfanz++;
  }
} /* Ende bitfld_set */


/* check for bit-position */
VG_BOOL
bitfld_get(struct vgi_bitfld *pbf, int bpos)
{
  int d8, m8;

  if (pbf == NULL || bpos < 0) { return VG_FALSE; }

  d8 = bpos / 8;
  m8 = bpos % 8;

  if ((unsigned int)d8 >= pbf->bfsize) { return VG_FALSE; }

  return ((pbf->bfeld[d8] & (1 << m8)) ? VG_TRUE : VG_FALSE);
} /* Ende bitfld_get */


/* remove bit-position */
void
bitfld_del(struct vgi_bitfld *pbf, int bpos)
{
  int d8, m8;

  if (pbf == NULL || bpos < 0) { return; }

  d8 = bpos / 8;
  m8 = bpos % 8;

  if ((unsigned int)d8 >= pbf->bfsize) { return; }

  if (pbf->bfeld[d8] & (1 << m8)) {
    pbf->bfeld[d8] &= ~(1 << m8);
    pbf->bfanz--;
  }
} /* Ende bitfld_del */


/* iterate bit-positions */
int
bitfld_next(struct vgi_bitfld *pbf, int bpos)
{
  int d8, m8;

  if (pbf == NULL || bpos < 0) { return -1; }

  d8 = bpos / 8;
  m8 = bpos % 8;

  if ((unsigned int)d8 >= pbf->bfsize) { return -1; }

  if (pbf->bfeld[d8]) {
    while (!(pbf->bfeld[d8] & (1 << m8))) {
      if (++m8 == 8) { break; }
    }
    if (m8 < 8) { return (d8 * 8 + m8); }
  }

  for (d8++; (unsigned int)d8 < pbf->bfsize; d8++) {
    if (pbf->bfeld[d8]) { break; }
  }
  if ((unsigned int)d8 >= pbf->bfsize) { return -1; }

  m8 = 0;
  while (!(pbf->bfeld[d8] & (1 << m8))) { m8++; }

  return (d8 * 8 + m8);
} /* Ende bitfld_next */


/* search for next unused bit-position */
int
bitfld_unused(struct vgi_bitfld *pbf, int bpos)
{
  int d8, m8;

  if (pbf == NULL || bpos < 0) { return -1; }

  d8 = bpos / 8;
  m8 = bpos % 8;

  for (; (unsigned int)d8 < pbf->bfsize; d8++, m8 = 0) {
    while ((pbf->bfeld[d8] & (1 << m8))) {
      if (++m8 == 8) { break; }
    }
    if (m8 < 8) { return (d8 * 8 + m8); }
  }

  return -1;
} /* Ende bitfld_unused */
