/*
  XBubble - utils.c

  Copyright (C) 2002  Ivan Djelic <ivan@savannah.gnu.org>
  Copyright (C) 2003  Martin Quinson (mquinson::debian.org)
  
  This program 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.
  
  This program 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 this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>

#include "utils.h"
#include "gettext.h"
#include "setting.h"

#define SET_BLOCK (10)

void * xmalloc (size_t size) {
  void *value = malloc (size);
  if ( value == NULL ) {
    perror("xmalloc");
    abort();
  }
  return value;
}

void * xrealloc ( void *p, size_t size) {
  void *value = realloc ( p, size);
  if ( value == NULL ) {
    perror("xrealloc");
    abort();
  }
  return value;
}

int rnd( int range ) {
  int x =  (int) floor( 1.0*range*rand()/(RAND_MAX + 1.0));
  /* return ( x % range ) just in case rand() is broken */
  return ( x % range );
}

void fail( const char * fmt, ... ) {
  va_list ap;
  va_start( ap, fmt);
  fprintf( stderr, _("xbubble: ") );
  vfprintf( stderr, fmt, ap );
  fprintf( stderr, _("\naborting...\n") );
  va_end(ap);
  abort();
}

void warn( const char * fmt, ... ) {
  va_list ap;
  va_start( ap, fmt);
  fprintf( stderr, _("xbubble[warning]: ") );
  vfprintf( stderr, fmt, ap );
  fprintf( stderr, "\n" );
  va_end(ap);
}

Set set_new( int max_size ) {
  Set s = (Set) xmalloc( sizeof( struct _Set ));
  s->element = (void **) xmalloc( sizeof(void *) * max_size);
  s->max_size = max_size;
  s->size = 0;
  s->ref = 1;
  return s;
}

void set_free( Set s ) {
  if (s) {
     free(s->element);
     free(s);
  }
}

void set_ref(Set set) {
  set->ref++;
}

void set_unref(Set set) {
  if (!--set->ref) {
     set_free(set);
  }
}

   
void set_add( Set s, void * p ) {
  if ( s->size >= s->max_size ) {
    s->max_size += SET_BLOCK;
    s->element = (void **) xrealloc( s->element, sizeof(void *)*s->max_size );
  }
  s->element[s->size++] = p;
}

void set_remove( Set s, void * p ) {
  int i;
  for ( i = 0; i < s->size; i++ )
    if ( s->element[i] == p ) {
      s->element[i] = s->element[--s->size];
      break;
    }
}

void set_remove_at( Set s, int i ) {
  if ( i < s->size )
    s->element[i] = s->element[--s->size];
}

void set_empty( Set s ) {
  s->size = 0;
}

void set_copy( Set source, Set dest ) {
  if ( source->size > dest->max_size ) {
    dest->max_size = source->max_size;
    dest->element = (void **) xrealloc( dest->element, 
					sizeof(void *)*dest->max_size );
  }
  dest->size = source->size;
  memcpy( dest->element, source->element, sizeof(void *) * dest->size );
}

Vector vector_new( int max_size ) {
  Vector v = (Vector) xmalloc( sizeof( struct _Vector ));
  v->element = (int *) xmalloc( sizeof(int) * max_size);
  v->max_size = max_size;
  v->size = 0;
  return v;
}

void vector_increase_maxsize( Vector v, int new_max ) {
  if (new_max > v->size)  {
     v->element = xrealloc(v->element, new_max * sizeof(int));
  }
}

void vector_empty( Vector v ) {
  v->size = 0;
}

void vector_free( Vector v ) {
  free(v->element);
  free(v);
}

int vector_membership( Vector v, int p ) {
  int i;
  for ( i = 0; i < v->size; i++ )
    if ( v->element[i] == p )
      return 1;
  return 0;
}

int vector_shift( Vector v ) {
   int res=-1;
   if (v->size) {
      res=v->element[0];
      memmove(&(v->element[0]), &(v->element[1]), v->size-1 * sizeof(int*));
      v->size--;
   }
   return res;
}

void vector_unshift( Vector v, int p) {
  if ( v->size >= v->max_size ) {
    v->max_size += SET_BLOCK;
    v->element = (int *) xrealloc( v->element, sizeof(int)*v->max_size );
  }
   memmove(&(v->element[1]), &(v->element[0]), v->size * sizeof(int*));
   v->element[0] = p;
   v->size++;
}

int vector_pop( Vector v ) {
   int res=-1;
   if (v->size) {
      res=v->element[v->size-1];
      v->size--;
   }
   return res;
}
   
void vector_push( Vector v, int p) {
  if ( v->size >= v->max_size ) {
    v->max_size += SET_BLOCK;
    v->element = (int *) xrealloc( v->element, sizeof(int)*v->max_size );
  }
  v->element[v->size++] = p;
}
	 
/****[ Names of colors and states for bubbles ]****/
static const char *name_color[NB_COLORS] = \
  { "black", "white", "blue", "green", "yellow", "magenta", "red", "brown" };

const char *name_color_get( int c ) {
   if (c<0) return "<0";
   if (c>NB_COLORS) return ">NB_COLORS";
   return name_color[c];
}

static const char *name_state[NB_BUBBLE_STATES] = \
  {  "NEW" , "READY" , "LAUNCHED" , "STUCK" , "EXPLODING" , \
     "FALLING" , "RISING" , "CHAINREACTING", "RUNAWAY" , "DEAD" } ;

const char *name_state_get( int c ) {
   if (c<0) return "<0";
   if (c>NB_BUBBLE_STATES) return ">NB_BUBBLE_STATES";
   return name_state[c];
}
