#include "os.h"

#include "utils.h"
#include "structs.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "prototypes.h"

#define MAX_MSGS 50             /* Max number of messages.          */
#define SAVE_FILE "board.messages"      /* Name of file for saving messages */
#define BOARD_OBJECT  xxx       /* what are we?                     */
#define BOARD_ROOM    xxx       /* where are we?                    */
#define MAX_MESSAGE_LENGTH 4000 /* that should be enough            */

char *msgs[MAX_MSGS];
char *head[MAX_MSGS];
int msg_num;

void board_write_msg (struct char_data *ch, char *arg);
int board_display_msg (struct char_data *ch, char *arg);
int board_remove_msg (struct char_data *ch, char *arg);
void board_save_board (void);
void board_load_board (void);
void board_reset_board (void);
void error_log (char *str);
void board_fix_long_desc (int num, char *headers[MAX_MSGS]);
int board_show_board (struct char_data *ch, char *arg);

/* I have used cmd number 180-182 as the cmd numbers here. */
/* The commands would be, in order : NOTE <header>         */
/* READ <message number>, REMOVE <message number>          */
/* LOOK AT BOARD should give the long desc of the board    */
/* and that should equal a list of message numbers and     */
/* headers. This is done by calling a function that sets   */
/* the long desc in the board object. This function is     */
/* called when someone does a REMOVE or NOTE command.      */
/* I have named the function board_fix_long_desc(). In the */
/* board_write_msg() function there is a part that should  */
/* be replaced with a call to some dreadful routine used   */
/* by the STRING command to receive player input. It is    */
/* reputed to lurk somewhere within the limits of an evil  */
/* file named act.comm.c.....*/

/* saving the board after the addition of a new messg      */
/* poses a slight problem, since the text isn't actually   */
/* entered in board_write. What I'll do is to let board()  */
/* save the first time a 'look' is issued in the room..    */
/* ugh! that's ugly - gotta think of something better.     */
/* -quinn                                                  */

/* And here is the board...correct me if I'm wrong. */


int board (struct char_data *ch, int cmd, char *arg)
{
  static int has_loaded = 0;

  if (!ch->desc)
    return (FALSE);             /* By MS or all NPC's will be trapped at the board */

  /* note: I'll let display and remove return 0 if the arg was non-board- */
  /* related. Thus, it'll be possible to read other things than the board */
  /* while you're in the room. Conceiveably, you could do this for write, */
  /* too, but I'm not in the mood for such hacking.                       */

  if (!has_loaded) {
    board_load_board ();
    has_loaded = 1;
  }

  switch (cmd) {
  case 15:                     /* look */
    return (board_show_board (ch, arg));
  case 149:                    /* write */
    board_write_msg (ch, arg);
    return 1;
  case 63:                     /* read */
    return (board_display_msg (ch, arg));
  case 66:                     /* remove */
    return (board_remove_msg (ch, arg));
  default:
    return 0;
  }
}


void board_write_msg (struct char_data *ch, char *arg)
{
  if (msg_num > MAX_MSGS - 1) {
    send_to_char ("The board is full already.\n\r", ch);
    return;
  }
  /* skip blanks */
  for (; isspace ((int)*arg); arg++);
  if (!*arg) {
    send_to_char ("We must have a headline!\n\r", ch);
    return;
  }
  head[msg_num] = (char *) malloc (strlen (arg) + strlen (GET_NAME (ch)) + 4);
  /* +4 is for a space and '()' around the character name. */
  if (!head[msg_num]) {
    error_log ("Malloc for board header failed.\n\r");
    send_to_char ("The board is malfunctioning - sorry.\n\r", ch);
    return;
  }
  strcpy (head[msg_num], arg);
  /* Is this clumsy?  - four strcat() in a row I mean.. */
  strcat (head[msg_num], " (");
  strcat (head[msg_num], GET_NAME (ch));
  strcat (head[msg_num], ")");
  msgs[msg_num] = NULL;

  send_to_char ("Write your message. Terminate with a @.\n\r\n\r", ch);
  act ("$n starts to write a message.", TRUE, ch, 0, 0, TO_ROOM);

  ch->desc->str = &msgs[msg_num];
  ch->desc->max_str = MAX_MESSAGE_LENGTH;

  msg_num++;
}


int board_remove_msg (struct char_data *ch, char *arg)
{
  int ind, msg;
  char buf[256], number[MAX_INPUT_LENGTH];

  if (GET_LEVEL (ch) < 10) {
    send_to_char ("Due to misuse of the REMOVE command, only 10th level\n\r",
      ch);
    send_to_char ("and above can remove messages.\n\r", ch);
    return (0);
  }

  one_argument (arg, number);

  if (!*number || !isdigit ((int)*number))
    return (0);
  if (!(msg = atoi (number)))
    return (0);
  if (!msg_num) {
    send_to_char ("The board is empty!\n\r", ch);
    return (1);
  }
  if (msg < 1 || msg > msg_num) {
    send_to_char ("That message exists only in your imagination..\n\r", ch);
    return (1);
  }

  ind = msg;
  free (head[--ind]);
  if (msgs[ind])
    free (msgs[ind]);
  for (; ind < msg_num - 1; ind++) {
    head[ind] = head[ind + 1];
    msgs[ind] = msgs[ind + 1];
  }
  msg_num--;
  send_to_char ("Message removed.\n\r", ch);
  sprintf (buf, "$n just removed message %d.", ind + 1);
  act (buf, FALSE, ch, 0, 0, TO_ROOM);
  board_save_board ();

  return (1);
}

void board_save_board (void)
{
  FILE *the_file;
  int ind, len;
  if (!msg_num) {
    error_log ("No messages to save.\n\r");
    return;
  }
  the_file = fopen (SAVE_FILE, "wb");
  if (!the_file) {
    error_log ("Unable to open/create savefile..\n\r");
    return;
  }
  fwrite (&msg_num, sizeof (int), 1, the_file);
  for (ind = 0; ind < msg_num; ind++) {
    len = strlen (head[ind]) + 1;
    fwrite (&len, sizeof (int), 1, the_file);
    fwrite (head[ind], sizeof (char), len, the_file);
    len = strlen (msgs[ind]) + 1;
    fwrite (&len, sizeof (int), 1, the_file);
    fwrite (msgs[ind], sizeof (char), len, the_file);
  }
  fclose (the_file);
  board_fix_long_desc (msg_num, head);
  return;
}

void board_load_board (void)
{
  FILE *the_file;
  int ind, len = 0;

  board_reset_board ();
  the_file = fopen (SAVE_FILE, "rb");
  if (!the_file) {
    error_log ("Can't open message file. Board will be empty.\n\r");
    return;
  }
  fread (&msg_num, sizeof (int), 1, the_file);

  if (msg_num < 1 || msg_num > MAX_MSGS || feof (the_file)) {
    error_log ("Board-message file corrupt or nonexistent.\n\r");
    fclose (the_file);
    return;
  }
  for (ind = 0; ind < msg_num; ind++) {
    fread (&len, sizeof (int), 1, the_file);
    head[ind] = (char *) malloc (len + 1);
    if (!head[ind]) {
      error_log ("Malloc for board header failed.\n\r");
      board_reset_board ();
      fclose (the_file);
      return;
    }
    fread (head[ind], sizeof (char), len, the_file);
    fread (&len, sizeof (int), 1, the_file);
    msgs[ind] = (char *) malloc (len + 1);
    if (!msgs[ind]) {
      error_log ("Malloc for board msg failed..\n\r");
      board_reset_board ();
      fclose (the_file);
      return;
    }
    fread (msgs[ind], sizeof (char), len, the_file);
  }
  fclose (the_file);
  board_fix_long_desc (msg_num, head);
  return;
}

void board_reset_board (void)
{
  int ind;
  for (ind = 0; ind < MAX_MSGS; ind++) {
    free (head[ind]);
    free (msgs[ind]);
  }
  msg_num = 0;
  board_fix_long_desc (0, 0);
  return;
}

void error_log (char *str)
{                               /* The original error-handling was MUCH */
  fputs ("Board : ", stderr);   /* more competent than the current but  */
  fputs (str, stderr);          /* I got the advice to cut it out..;)   */
  return;
}

int board_display_msg (struct char_data *ch, char *arg)
{
  char buf[512], number[MAX_INPUT_LENGTH], buffer[MAX_STRING_LENGTH];
  int msg;
  one_argument (arg, number);
  if (!*number || !isdigit ((int)*number))
    return (0);
  if (!(msg = atoi (number)))
    return (0);
  if (!msg_num) {
    send_to_char ("The board is empty!\n\r", ch);
    return (1);
  }
  if (msg < 1 || msg > msg_num) {
    send_to_char ("That message exists only in your imagination..\n\r", ch);
    return (1);
  }

  /*  sprintf(buf, "$n reads message %d titled : %s.",
     msg, head[msg - 1]);
     act(buf, TRUE, ch, 0, 0, TO_ROOM);    */

  /* Can PERFORM() handle this...?  no. Sorry */
  /* sprintf(ch, "Message %d  : %s\n\r%s", msg, head[msg - 1], msgs[msg - 1]); */
  /* Bad news */

  sprintf (buffer, "Message %d : %s\n\r\n\r%s", msg, head[msg - 1],
    msgs[msg - 1]);
  page_string (ch->desc, buffer, 1);
  return (1);
}



void board_fix_long_desc (int num, char *headers[MAX_MSGS])
{

  struct obj_data *ob;




  /**** Assign the right value to this pointer..how? ****/
  /**** It should point to the bulletin board object ****/
  /**** Then make ob.description point to a malloced ****/
  /**** space containing itoa(msg_num) and all the   ****/
  /**** headers. In the format :
  This is a bulletin board. Usage : READ/REMOVE <message #>, NOTE <header>
  There are 12 messages on the board.
  1 : Re : Whatever and something else too.
  2 : I don't agree with Rainbird.
  3 : Me neither.
  4   : Groo got hungry again - bug or sabotage?

  Well...something like that..;)         ****/

  /**** It is always to contain the first line and   ****/
  /**** the second line will vary in how many notes  ****/
  /**** the board has. Then the headers and message  ****/
  /**** numbers will be listed.          ****/
  return;
}




int board_show_board (struct char_data *ch, char *arg)
{
  int i;
  char buf[MAX_STRING_LENGTH], tmp[MAX_INPUT_LENGTH];

  one_argument (arg, tmp);

  if (!*tmp || !isname (tmp, "board bulletin"))
    return (0);

  act ("$n studies the board.", TRUE, ch, 0, 0, TO_ROOM);

  strcpy (buf,
    "This is a bulletin board. Usage: READ/REMOVE <messg #>, WRITE <header>\n\r");
  if (!msg_num)
    strcat (buf, "The board is empty.\n\r");
  else {
    sprintf (buf + strlen (buf), "There are %d messages on the board.\n\r",
      msg_num);
    for (i = 0; i < msg_num; i++)
      sprintf (buf + strlen (buf), "%-2d : %s\n\r", i + 1, head[i]);
  }
  page_string (ch->desc, buf, 1);

  return (1);
}