/* Type 2 client of SaveAs Object Class Module
 *
 * Type2 clients always save the data to disc. The SaveAs module deals
 * with other details.
 *
 */

/* Include relevant ANSI C headers. */

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

/* Include Acorn specific headers. */

#include "kernel.h"
#include "swis.h"

/* Include eventlib and relevant toolboxlib headers. */

#include "event.h"

#include "toolbox.h"
#include "iconbar.h"
#include "menu.h"
#include "saveas.h"

/* Preprocessor definitions */

#define FILESIZE      0x1000
#define QUITENTRY          2
#define SAVEASENTRY        0

/* Globals (to types 2 and 3) */

void *type2n3_buffer;
int   type2n3_size;

int message_list [] = {0};
int event_list   [] = {0};

MessagesFD    mfd;

IdBlock       id_blk;
WimpPollBlock poll_block;

ObjectId saveas_id, menu_id;

/* prototypes */

static void initialise (void);
int menu_selection (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h);
void register_handlers (void);
int find_id (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h);
int save_to_file (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h);
int setup_values (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h);
void quit (void);
int wimp_quit (WimpMessage *message, void *h);
void wimp_lookup_error (int num, char *token);
int error_handler (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h);
void messages_lookup (MessagesFD messages_fd, char *token, char *buffer, int buffer_size, char *par1, char *par2, char *par3, char *par4, char **new_buffer, int *new_buffer_size);
void load_text (void **buffer, int *size);
void raise_error (_kernel_oserror *e);


/* main routine */

int main (void) {

   int event_code;

   initialise ();

   /* Poll loop - never catches anything because we rely on registered handlers */

   while (1)
      event_poll (&event_code, &poll_block, NULL);
}

/* subsidiary routines */

static void initialise (void) {

   /* Initialise toolbox resources */

   _kernel_oserror *e;

   if ((e = toolbox_initialise (0, 310, message_list, event_list, "<SaveAsEx$Dir>", &mfd, &id_blk, NULL, NULL, NULL)) != NULL) {
      raise_error (e);
      exit (1); /* Fatal */
   }

   /* This is our ID block */

   event_initialise (&id_blk);

   event_set_mask (1+256);

   register_handlers ();
}

int menu_selection (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h) {

   /* This handles selections on the iconbar menu */

   if (id_blk->self_component == QUITENTRY)
      quit ();

   return 1;
}

void register_handlers (void) {

   /* register event handlers */

   event_register_toolbox_handler (-1,        SaveAs_AboutToBeShown,     setup_values,   NULL);
   event_register_toolbox_handler (-1,        Menu_Selection,            menu_selection, NULL);
   event_register_toolbox_handler (-1,        Toolbox_ObjectAutoCreated, find_id,        NULL);
   event_register_toolbox_handler (-1,        Toolbox_Error,             error_handler,  NULL);
   event_register_message_handler (           Wimp_MQuit,                wimp_quit,      NULL);

   /* type 2 & 3 specific */

   event_register_toolbox_handler (-1,        SaveAs_SaveToFile,         save_to_file,   NULL);
}

int find_id (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h) {

   /* This is called when an object is auto-created with the template name stored
    * in the toolbox event block.
    */

   if (!strcmp (event_block->data.bytes, "Menu")) {
      _kernel_oserror *e;

      menu_id = id_blk->self_id;

      /* delete the menu entries we don't want */

      if (((e = toolbox_create_object  (0, "SaveAs2", &saveas_id)) != NULL)
       || ((e = menu_set_click_show    (0, menu_id, SAVEASENTRY, saveas_id, 0)) != NULL)
       || ((e = menu_set_sub_menu_show (0, menu_id, SAVEASENTRY, saveas_id)) != NULL)) {
          raise_error (e);
          exit (1); /* Fatal */
       }
   }
   return 1;
}

/* Some code common to application type 2 and 3 */

int save_to_file (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h) {

   /* This takes a block of memory and stores it out to the filename given in the
      toolbox event block */

   _kernel_oserror  *e;
   _kernel_swi_regs  regs;
   SaveAsSaveToFileEvent
                    *save_to_file_block = (SaveAsSaveToFileEvent *) event_block;
   void             *buffer;
   int               size;

   buffer = type2n3_buffer;
   size   = type2n3_size;

   if (save_to_file_block->hdr.flags & 1) { /* If this is a selection */
      buffer = (char *) buffer + size/4;
      size  /= 2;
   }
   /* OS_File 10 (~= *SAVE) */

   regs.r[0] =       10;
   regs.r[1] = (int) save_to_file_block->filename;
   regs.r[2] =       0xfff; /* Text */
   regs.r[4] = (int) buffer;
   regs.r[5] = (int) ((char *) buffer+size);

   if ((e = _kernel_swi (OS_File, &regs, &regs)) != NULL) {
      raise_error (e);
   }
   if ((e = saveas_file_save_completed (e?0:1, saveas_id, save_to_file_block->filename)) != NULL) {
      raise_error (e);
   }
   return 1;
}

int setup_values (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h) {

   /* Although this function sets up values for the SaveAs dialogue box, it is
    * expected that the following code would normally be put in ther handler for
    * Toolbox_ObjectAutoCreated or after the client application creates the object,
    * so that it is set up as soon as the object comes into being.
    */

   void            *buffer;
   int              size;

   load_text (&buffer, &size);

   saveas_set_file_size (0, saveas_id, size);

   type2n3_buffer = buffer;
   type2n3_size   = size;

   return 0;
}

void quit (void) {

   /* At the moment this merely calls exit, but it could include some
      cleaning up */

   exit (0); /* WTGROMT */
}

int wimp_quit (WimpMessage *message, void *h) {

   /* Quit */

   quit();

   return 1;
}

void wimp_lookup_error (int num, char *token) {

   /* Looks up error from error token */

   _kernel_oserror   e;
   _kernel_swi_regs  regs;

   e.errnum = num;
   strcpy (e.errmess, token);

   regs.r[0] = (int) &e;
   regs.r[1] = (int) &mfd;
   regs.r[2] = 0;

   raise_error (_kernel_swi (MessageTrans_ErrorLookup, &regs, &regs));
}

int error_handler (int event_code, ToolboxEvent *event_block, IdBlock *id_blk, void *h) {

   /* Handles an error by raising it */

   raise_error ((_kernel_oserror *)event_block->data.bytes);
   return 1;
}

void messages_lookup (MessagesFD messages_fd, char *token, char *buffer, int buffer_size, char *par1, char *par2, char *par3, char *par4, char **new_buffer, int *new_buffer_size) {

   /* Looks up token and passes back appropriate message */

   _kernel_oserror  *e;
   _kernel_swi_regs  regs;

   regs.r[0] = (int)  &messages_fd;
   regs.r[1] = (int)  token;
   regs.r[2] = (int)  buffer;
   regs.r[3] =        buffer_size;
   regs.r[4] = (int)  par1;
   regs.r[5] = (int)  par2;
   regs.r[6] = (int)  par3;
   regs.r[7] = (int)  par4;

   if ((e = _kernel_swi (MessageTrans_Lookup, &regs, &regs)) != NULL)
      raise_error (e);

   if (new_buffer) {
      *new_buffer      = (char *) regs.r[2];
   }
   if (new_buffer_size) {
      *new_buffer_size = regs.r[3];
   }
}

void load_text (void **buffer, int *size) {

   /* Loads in data for test transfer */


   FILE            *file_handle;

   saveas_selection_available (0, saveas_id, 1);

   /* load in textual data */

   if ((file_handle = fopen ("<SaveAsEx$Dir>.Messages","r")) == NULL) {
      wimp_lookup_error (0x12345678, "WontOpen");
      exit (1); /* Fatal */
   }
   /* Allocate space */

   if ((*buffer = malloc (FILESIZE)) == NULL) {
      wimp_lookup_error (0x12345678, "MemGone");
      exit (1); /* Fatal */
   }

   /* Read in data */

   *size = fread (*buffer, sizeof(char), FILESIZE, file_handle);

   fclose (file_handle);
}

void raise_error (_kernel_oserror *e) {

   /* Given an error block, raise the error */

   _kernel_swi_regs regs;
   char *strng;

   messages_lookup (mfd, "_TaskName", NULL, 0, NULL, NULL, NULL, NULL, &strng, NULL);

   regs.r[0] = (int) e;
   regs.r[1] =       16;
   regs.r[2] = (int) strng;

   _kernel_swi (Wimp_ReportError, &regs, &regs);
}


