/*
    general.m  Subprogram to cheezmud.
    Copyright (C) 1995  David Flater.

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cheezmud.h"

/*  Find something. */
id
global_find (char *name, int number)
{
  return generic_find (world, name, number);
}

int
global_number (char *name, id what)
{
  return generic_number (world, name, what);
}

/*  Support multiple cascaded finds. */
id
generic_find_creturn (id wherein, char *name, int *number)
{
  int i,m;
  BOOL flag = YES;
  id victim = NULL;

  /* Guard against underflow, or else some dork will crash the mud asking */
  /* for the -maxint sword. */
  if (*number <= 0)
    return NULL;

  for(i=0,m=[wherein size];(i<m) && flag;i++) {
    id whatever = [wherein at:i];
    if (!strcmp ([whatever mudname], name)) {
      if (!(--(*number))) {
        flag = NO;
        victim = whatever;
      }
    }
  }

  return victim;
}

/*  Find something. */
id
generic_find (id wherein, char *name, int number)
{
  return generic_find_creturn (wherein, name, &number);
}

/*  This is kind of the opposite of generic_find. */
int
generic_number (id wherein, char *name, id what)
{
  int i,m,n = 0;
  BOOL flag = YES;

  for(i=0,m=[wherein size];(i<m) && flag;i++) {
    id whatever = [wherein at:i];
    if (!strcmp ([whatever mudname], name)) {
      n++;
      if (what == whatever)
        flag = NO;
    }
  }
  if (flag == NO)
    return n;
  return 0;
}

/*  Find something, preserving the count over two separate containers. */
id
generic_find_cascade (id wherein1, id wherein2, char *name, int number)
{
  id victim = NULL;
  victim = generic_find_creturn (wherein1, name, &number);
  if (victim)
    return victim;
  return generic_find_creturn (wherein2, name, &number);
}

int
generic_number_cascade (id wherein1, id wherein2, char *name, id what)
{
  int i,m,n = 0;
  BOOL flag = YES;

  for(i=0,m=[wherein1 size];(i<m) && flag;i++) {
    id whatever = [wherein1 at:i];
    if (!strcmp ([whatever mudname], name)) {
      n++;
      if (what == whatever)
        flag = NO;
    }
  }

  if (flag == NO)
    return n;

  for(i=0,m=[wherein2 size];(i<m) && flag;i++) {
    id whatever = [wherein2 at:i];
    if (!strcmp ([whatever mudname], name)) {
      n++;
      if (what == whatever)
        flag = NO;
    }
  }

  if (flag == NO)
    return n;
  return 0;
}

/*  This assumes that t1 >= t2 and that they are not that far apart.  Return */
/*  value is in microseconds. */
long
difftimeval (struct timeval *t1, struct timeval *t2)
{
  return ((t1->tv_sec - t2->tv_sec) * 1000000 + t1->tv_usec) - t2->tv_usec;
}

/*  Return number of microseconds since last heartbeat. */
/*  As an auxilliary duty, this function stabilizes things if the system clock */
/*  takes a flying leap. */
long
timesincelastheartbeat ()
{
  struct timeval t;
  gettimeofday (&t, NULL);

  /*  Has the clock run backwards?  Is it way ahead of us (10 seconds)? */
  if (((t.tv_sec < lastheartbeat.tv_sec) ||
      (t.tv_sec == lastheartbeat.tv_sec &&
       t.tv_usec < lastheartbeat.tv_usec))      ||
      (t.tv_sec - lastheartbeat.tv_sec > 9)) {
    /*  Arrrgh!  Fix it! */
    lastheartbeat.tv_sec = t.tv_sec;
    lastheartbeat.tv_usec = t.tv_usec;
    return 0;
  }

  return difftimeval (&t, &lastheartbeat);
}

char *
capitalize (char *a)
{
  static char b[80];
  strcpy (b, a);
  if (b[0] >= 'a' && b[0] <= 'z')
    b[0] = b[0] - 'a' + 'A';
  return b;
}

id
get_random_member (id from)
{
  id r = nil;
  BOOL flag = YES;
  int i,m,c, n;

  if (!(c = [from size]))
    return NULL;
  n = random() % c;

  for(i=0,m=[from size];(i<m) && flag;i++) {
    id whatever = [from at:i];
    if (!(n--)) {
      flag = NO;
      r = whatever;
    }
  }
  return r;
}

/*  This is preferable to cat_text_file since it will work for non-players. */
/*  However, lines will be cut off at 1000 chars. */
void
echo_text_file (id who, char *fname)
{
  FILE *fp;
  if ((fp = fopen (fname, "r")))
  {
    char buf[1000];
    while (fgets (buf, 1000, fp))
      [who echo: noeol (buf)];
    fclose (fp);
  }
}

/*  Save all players immediately. */
void
checkpoint ()
{
  int i,m;
  for(i=0,m=[world size];i<m;i++) {
    id whatever = [world at:i];
    if ([whatever isKindOf: [Player class]])
      [whatever save];
  }
}