/**********************************************/
/* Miscellaneous routines and settings        */
/* Evert Glebbeek 2002                        */
/* eglebbk@phys.uva.nl                        */
/**********************************************/
#include <allegro.h>
#include <string.h>
#include <stdio.h>
#include "global.h"
#if (ALLEGRO_VERSION == 4) || ((ALLEGRO_VERSION == 3)&&(ALLEGRO_SUB_VERSION==9)&&(ALLEGRO_WIP_VERSION==40))
   #include <allegro/internal/aintern.h>
#else
   #include <aintern.h>
#endif

INT_SETTINGS settings = {
   16, 800, 600, 800, 1800,
   WINDOWED_MODE + DOUBLE_BUFFER + MUSIC_MIDI + SFX_DIGI,
   16,
   0,0,0,0,0,0,0,

   0,
   
   15
};

int close_button_pressed = 0;

/* Message window strings; up to 6 */
static char *msg_str[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
static int msg_timer = 0;

/* Game working directory and scratch buffer for expanding file names */
static char game_directory[4096] = "./";
static char game_filepath[4096] = "";

/* game messages */
static char **global_msg = NULL;
static size_t num_global_msg = 0;

/* Clip a number between two values */
int clip_num(const int x, const int min, const int max)
{
   /*
   int n;
   n = ~min;
   n &= (~n)>>31;
   n+=min;
   n-=max;
   n&=n>>31;
   n+=max;
   return n;
   */
   return (x<=min)?min:((x>=max)?max:x);
}

/* Get the sign of x */
int sgn(int x)
{
   if (x > 0)
      return 1;
   else if (x < 0)
      return -1;
   else
      return 0;
}

/* Returns true if n is a power of 2 */
int is_power_of_two(const int n)
{
   return !(n & (n-1));
}

/* Return pointer to message window */
char *get_msg_str(unsigned int line)
{
   if (line > 5)
      return NULL;
   return msg_str[line];
}

/* Frees one line in the message window. */
void clr_msg_str(unsigned int line)
{
   if (line > 5)
      return;
   if (msg_str[line]) {
      free(msg_str[line]);
      msg_str[line] = NULL;
   }
}

/* Frees the message window. */
void clr_msg_win(void)
{
   int c;

   for (c = 0; c < 6; c++)
      clr_msg_str(c);
}

/* Scrolls the message window up one line */
void scroll_msg_win(void)
{
   int c;

   clr_msg_str(0);
   for (c = 0; c < 5; c++) {
      msg_str[c] = msg_str[c + 1];
   }
   msg_str[5] = NULL;
}

/* Set one line in the message window */
void set_msg_str(unsigned int line, char *s)
{
   if (line <= 5) {
      clr_msg_str(line);
      msg_str[line] = strdup(s);
      msg_timer += 80;
   }
}

/* Pushes message string in the first free line, scrolls if nescessary */
void push_msg(char *msg, ...)
{
   int c;
   char *s = malloc(512);

   va_list ap;

   va_start(ap, msg);
   uvsprintf(s, msg, ap);
   va_end(ap);

   for (c = 0; c < 6; c++)
      if (!msg_str[c]) {
         set_msg_str(c, s);
         free(s);
         return;
      }
   /* Scroll one up */
   scroll_msg_win();
   set_msg_str(5, s);
   free(s);
}

void set_msg_timer(unsigned int value)
{
   msg_timer = value;
}

int get_msg_timer(void)
{
   return msg_timer;
}

int dec_msg_timer(void)
{
   if (msg_timer)
      msg_timer--;
   return msg_timer;
}

/* Global game messages; like conversations */
void clear_global_msg(void)
{
   int c;

   if (!num_global_msg)
      return;
   for (c = 0; c < num_global_msg; c++)
      free(global_msg[c]);
   free(global_msg);
   num_global_msg = 0;
}

/* Add a copy of s to the end of the list */
void push_global_msg(char *s)
{
   global_msg = realloc(global_msg, (num_global_msg + 1) * sizeof(char *));
   global_msg[num_global_msg] = strdup(s);
   num_global_msg++;
}

/* Add a copy of s to the list, unless it already exists. Returns the */
/*  index number for s */
int add_global_msg(char *s)
{
   int c;

   for (c = 0; c < num_global_msg; c++)
      if (!strcmp(global_msg[c], s))
         return c;
   /* Message didn't exist yet */
   push_global_msg(s);
   return num_global_msg - 1;
}

char *get_global_msg(unsigned int num)
{
   if (num >= num_global_msg)
      return NULL;
   return global_msg[num];
}

/* Returns TRUE if (x, y) falls within the rectangle (rx,ry)-(rx+rw,rx+rh) */
/* Point on the edge are supposed to belong to the rectangle */
/* The split up of the if statement results in slightly faster code (gprof) */
int in_rect(int x, int y, int rx, int ry, int rw, int rh)
{
   if (x < rx)
      return FALSE;
   if (y < ry)
      return FALSE;
   if (x > rx + rw)
      return FALSE;
   if (y > ry + rh)
      return FALSE;

   return TRUE;

/*
   if (x >= rx && x <= rx + rw && y >= ry && y <= ry + rh)
      return TRUE;
   else
      return FALSE;
*/
}

/* Returns TRUE if the first rectangle lies within the second */
int rect_contains(int rx1, int ry1, int rw1, int rh1,
                  int rx2, int ry2, int rw2, int rh2)
{
   if (rx1 >= rx2 && ((rx1 + rw1) <= (rx2 + rw2)) &&
       ry1 >= ry2 && ((ry1 + rh1) <= (ry2 + rh2)))
      return TRUE;
   else
      return FALSE;
}

/* Returns TRUE if the two rectangles overlap */
int rect_overlap(int rx1, int ry1, int rw1, int rh1, int rx2, int ry2,
                 int rw2, int rh2)
{
   return (in_rect(rx1, ry1, rx2, ry2, rw2, rh2) ||
           in_rect(rx1 + rw1, ry1, rx2, ry2, rw2, rh2) ||
           in_rect(rx1, ry1 + rh1, rx2, ry2, rw2, rh2) ||
           in_rect(rx1 + rw1, ry1 + rh1, rx2, ry2, rw2, rh2) ||
           in_rect(rx2, ry2, rx1, ry1, rw1, rh1) ||
           in_rect(rx2 + rw2, ry2, rx1, ry1, rw1, rh1) ||
           in_rect(rx2, ry2 + rh2, rx1, ry1, rw1, rh1) ||
           in_rect(rx2 + rw2, ry2 + rh2, rx1, ry1, rw1, rh1));
}

/* Returns the distance (squared) between points (x1, y1) and (x2, y2) */
int distsqr(int x1, int y1, int x2, int y2)
{
   return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}

/* Get status of the n-th game switch */
int get_switch(int n)
{
   return 0;
}

void set_switch(int n)
{
   return;
}

void clear_switch(int n)
{
   return;
}

/* Get the current directory (and drive) */
void get_current_dir(char *dir, int len)
{
#if (DEVICE_SEPARATOR != 0) && (DEVICE_SEPARATOR != '\0')
   int drive = _al_getdrive();
#else
   int drive = 0;
#endif

   _al_getdcwd(drive, dir, len - ucwidth(OTHER_PATH_SEPARATOR));
}

/* Set the path to the game datafiles */
void set_game_directory(const char *dir)
{
   sprintf(game_directory, dir);
   put_backslash(game_directory);
}

/* Get the absolute path of a file within the game directory */
char *get_game_path(const char *filename)
{
   #if defined ALLEGRO_UNIX
   if (filename[0] == '/')
      sprintf(game_filepath, "%s", filename);
   else
   #elif defined ALLEGRO_WINDOWS || defined ALLEGRO_DOS
   if (filename[1] == ':')
      sprintf(game_filepath, "%s", filename);
   else
   #endif
   sprintf(game_filepath, "%s%s", game_directory, filename);
   return game_filepath;
}

/* returns TRUE if a joystick button is being held down */
int joystick_button(void)
{
   int c;
   int n;

   if (num_joysticks) {
      poll_joystick();
      for (n=0; n<num_joysticks; n++) {
         for (c=0; c<joy[n].num_buttons; c++) {
            if (joy[n].button[c].b) {
               return TRUE;
            }
         }
      }
   }
   return FALSE;
}
