/*  editunits.c routines for program UnitConv  */

/*  copyright Chris Johnson 2011  */

/* from C lib: */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>


/* from osLib: */
#include "OSLib:gadget.h"
#include "OSLib:menu.h"
#include "OSLib:osfile.h"
#include "OSLib:OSFSControl.h"
#include "OSLib:toolbox.h"
#include "OSLib:window.h"
#include "OSLib:writablefield.h"


/* from oslib support */
#include "OSLibSupport:event.h"

/* from CJLib */
#include "CJLib:tbox.h"
#include "CJLib:message.h"
#include "CJLib:etc.h"
#include "CJLib:file.h"

/* from app  */
#include "msglink.h"
#include "res.h"
#include "iconbar.h"
#include "loaddata.h"
#include "main.h"
#include "cjoslib.h"
#include "editunits.h"


/* constant definitions */
/* Res file */
#define EDITUNITS_TEMPLATE	((toolbox_id)"DataEdit")
#define EDITUNITS_GROUP         ((toolbox_c)0x02)
#define EDITUNITS_SET           ((toolbox_c)0x06)
#define EDITUNITS_UNIT_BASE     ((toolbox_c)0x0A)
#define EDITUNITS_FACTOR_BASE   ((toolbox_c)0x13)
#define EDITUNITS_GROUP_INC     ((toolbox_c)0x00)
#define EDITUNITS_GROUP_DEC     ((toolbox_c)0x01)
#define EDITUNITS_SET_INC       ((toolbox_c)0x04)
#define EDITUNITS_SET_DEC       ((toolbox_c)0x05)
#define uevent_EDITUNITS_SAVE   0x100u
#define EDITUNITSMENU_TEMPLATE	((toolbox_id)"DataEditM")
#define uevent_EDITUNITSMENU_ADDGROUP     0x101
#define uevent_EDITUNITSMENU_DELETEGROUP  0x102
#define uevent_EDITUNITSMENU_ADDSET       0x103
#define uevent_EDITUNITSMENU_DELETESET    0x104
#define uevent_EDITUNITSMENU_SAVE         0x105
#define uevent_EDITUNITSMENU_INSERTSET    0x106
#define uevent_EDITUNITSMENU_INSERTGROUP  0x107
#define uevent_EDITUNITSMENU_INSERTITEM   0x108
#define uevent_EDITUNITSMENU_DELETEITEM   0x109

#define UNITITEMS_MAX_INDEX MAX_UC_UNITITEMS - 1

#define BUF_SIZE 96
#define TBUF_SIZE 24
#define UNITNAME_LENGTH 20
#define UNITFACTOR_TABPOS UNITNAME_LENGTH + 2





/* global variables */
static toolbox_o Editunits_winid;
static wimp_w    Editunits_winhandle;
static toolbox_position Editunits_win_pos;
static toolbox_o Editunits_menuid;
static osbool    Editunits_is_open;


static unitconv_data ed_data;

/* Forward function declarations */
static void Editunits_SetupSet ( int gr, int set );
static void Editunits_SetupGroup ( int gr );

/* The Functions */


static osbool Editunits_WriteBackSet (void)
{
  conv_group *edptr ;
  int set;
  char tbuf [TBUF_SIZE];
  char tbuf2 [TBUF_SIZE];
  int len, len2;
  int items;
  int i;


  edptr = ed_data.group [ed_data.current_group];
  set = ed_data.current_set;

  /* Read Set title */
  len = writablefield_get_value ( 0, Editunits_winid,
                                  EDITUNITS_SET, tbuf, TBUF_SIZE ) ;
  if (len > 1)
  {
    strcpy ( edptr->set[set].set_name, tbuf );
  }
  else
  {
    /* Report error and exit */
    Msg_Warn ( SETNAMEBLANK);
    return FALSE;
  }
  items = 0;
  for ( i = 0; i < MAX_UC_UNITITEMS; i++)
  {
    len = writablefield_get_value ( 0, Editunits_winid,
                                    i + EDITUNITS_UNIT_BASE, tbuf, TBUF_SIZE ) ;
    len2 = writablefield_get_value ( 0, Editunits_winid,
                                     i + EDITUNITS_FACTOR_BASE, tbuf2, TBUF_SIZE ) ;
    if ((len > 1) && (len2 > 1))
    {
      strcpy ( edptr->set[set].item[items].unit_name, tbuf );
      strcpy ( edptr->set[set].item[items].factor_txt, tbuf2 );
      items++;
    }
    else
    {
      if (len > 1)
      {
        /* Second field blank */
        Msg_Warn ( NOFACTOR );
        return (FALSE);
      }
      else
      {
        if (len2 > 1)
        {
          /* first field blank */
          Msg_Warn ( NOUNITNAME );
          return (FALSE);
        }
      }
    }
  }
  edptr->set[ set ].no_of_items = items;
  return (items > 0);
}



static osbool Editunits_WriteBackGroup (void)
{
  conv_group *edptr ;
  char tbuf [TBUF_SIZE];
  int len;

  edptr = ed_data.group [ed_data.current_group];
  /* Read Group title */
  len = writablefield_get_value ( 0, Editunits_winid,
                                  EDITUNITS_GROUP, tbuf, TBUF_SIZE ) ;
  if (len > 1)
  {
    strcpy ( edptr->group_name, tbuf );
  }
  else
  {
    /* Report error and exit */
    Msg_Warn ( NOGROUPNAME );
    return FALSE;
  }
  /* Now write back the displayed set */
  return (Editunits_WriteBackSet ());
}


/* Function to construct a line of data nicely tabbed with spaces, and
   write it to file. The first argument is always a string, the second
   may be string or int. A null pointer for the second string should be
   passed in order for the int to be used. The separating character
   is passed as the last argument */

static void Editunits_WriteTabbedLine ( char *buf,
                                        char *s1,
                                        char *s2,
                                        int i1,
                                        char separator,
                                        FILE *fh )
{
  char *p;
  char *q;
  size_t len;
  char tmp[MAX_LEN_ITEMNAME + 2];
  int i;

  sprintf (tmp, "%s%c", s1, separator );
  /* The first string may conceivably have a % or \ character in it.
   * This will screw up the use of the fprintf function to write
   * the data to the file.
   * Thus we need to escape such characters
  */
  len = strlen (tmp);
  p = buf;
  q = tmp;
  while (*q)
  {
    *p = *q;
    if ((*q == '%') || ( *q == '\\' ))
    {
      p++;
      *p = *q;
    }
    p++;
    q++;
  }
  /* now we need to insert the spaces to tab to next field */
  for ( i = 0; i < (UNITFACTOR_TABPOS - (int)len); i++ )
  {
    p[0] = ' ';
    p++;
  }
  if (s2)
  {
    sprintf ( p, "%s\n", s2 );
  }
  else
  {
    sprintf ( p, "%d\n", i1 );
  }
  fprintf (fh, buf );
  return;
}




static void delete_object ( char * name )
{
  bits load, exec, filetype;
  fileswitch_attr attr;
  int size;
  fileswitch_object_type type;

  type = osfile_delete ( name, &load, &exec, &size, &attr );
  return;
}





static void Editunits_SaveConvData ( void )
{
  FILE  *outfile;
  time_t current ;
  struct tm *converted_time ;
  size_t length ;
  char buf[BUF_SIZE];
  int group;
  int set;
  int item;
  conv_group *edptr ;


  /* First ensure any changes to visible display are stored */
  if (!Editunits_WriteBackGroup ())
    return;

  /* Now deal with backup of custom data file */
  if ( CJLfile_file_exists ( CUSTOM_FILE_BACKUP ) )
  {
    /* delete the existing backup file */
    delete_object ( CUSTOM_FILE_BACKUP );
  }

  /* Now rename existing custom data file to backup name, if it exists */
  if ( CJLfile_file_exists ( CUSTOM_FILE ))
  {
    osfscontrol_rename ( CUSTOM_FILE, CUSTOM_FILE_BACKUP );
  }

  /* Now we can get on with actually saving the new data file */
  outfile = fopen (CUSTOM_FILE, "w" ) ;
  if (outfile == NULL)
  {
    /* file would not open or create */
    Msg_Warn ( CUSTOMNOWRITE ) ;
    return;
  }
  fprintf (outfile, "#UnitConv:version 1\n") ;
  /* now get the time and convert to suitable format */
  current = time (NULL) ;
  converted_time = localtime (&current) ;
  length = strftime (buf, BUF_SIZE, "# File written at %H:%M:%S on %d %b %Y",
                                        converted_time) ;
  fprintf (outfile, "%s\n\n", buf) ;
  fprintf (outfile, "total_groups:%d\n\n", ed_data.no_of_groups);
  for ( group = 0; group < ed_data.no_of_groups; group++)
  {
    fprintf (outfile, "#------------Start of group %d------------\n\n", group + 1);
    edptr = ed_data.group[group];
    Editunits_WriteTabbedLine ( buf,
                                "Group_title",
                                edptr->group_name,
                                0,
                                ':',
                                outfile );
    Editunits_WriteTabbedLine ( buf,
                                "Group_entries",
                                NULL,
                                edptr->no_of_sets,
                                ':',
                                outfile );
    fprintf (outfile, "\n");
    for ( set = 0; set < edptr->no_of_sets; set++)
    {
      fprintf (outfile, "#---------------------------------------%d\n", set + 1);
      fprintf (outfile, "group_item:\n\n");
//      fprintf (outfile, "#Set name, and number of units\n");
      Editunits_WriteTabbedLine ( buf,
                                  edptr->set[set].set_name,
                                  NULL,
                                  edptr->set[set].no_of_items,
                                  ',',
                                  outfile );
      fprintf (outfile, "\n#Units and corresponding factors\n" );
      for (item = 0; item < edptr->set[set].no_of_items; item++)
      {
        Editunits_WriteTabbedLine ( buf,
                                    edptr->set[set].item[item].unit_name,
                                    edptr->set[set].item[item].factor_txt,
                                    0,
                                    ',',
                                    outfile );
      }
      fprintf (outfile, "\n");
    }
  }
  fprintf (outfile, "#End of data\n\n");
  fclose (outfile) ;
  osfile_set_type (CUSTOM_FILE, osfile_TYPE_TEXT) ;

  Msg_Warn (RESTART);
  return;
}




static osbool Editunits_KeyPress ( wimp_event_no event,
                                   wimp_block * blk,
                                   toolbox_block * id_block,
                                   void * handle )
{
  wimp_key *wkey;

  wkey = (wimp_key*)blk;
  if (wkey->c == wimp_KEY_F1)
    IconbarShowHelp();
  else
  if (( wkey->c < 32 ) || ( wkey->c > 126 ))
    wimp_process_key (wkey->c);

  return (TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (event);
}



static osbool Editunits_MouseClickHandler (wimp_event_no event,
                                          wimp_block *blk,
                                          toolbox_block *id_block,
                                          void *handle)
{
  wimp_pointer *mouse_blk;
  toolbox_o win_id ;
  toolbox_c cmp_id ;
  conv_group *edptr ;
  int inc = 1;


  edptr = ed_data.group[ed_data.current_group];

  mouse_blk = (wimp_pointer *)blk;
  /* was it select or adjust? */
  if (( mouse_blk->buttons & wimp_CLICK_ADJUST ) == wimp_CLICK_ADJUST )
    inc = -1;
  /* Find the Toolbox component id clicked */
  window_wimp_to_toolbox ( 0,
                           Editunits_winhandle,
                           mouse_blk->i,
                           &win_id,
                           &cmp_id ) ;

  switch (cmp_id)
  {
    case EDITUNITS_GROUP_DEC:
      inc = -inc;
    case EDITUNITS_GROUP_INC:
      if (inc > 0)
      {
        if (ed_data.current_group < ( ed_data.no_of_groups - 1 ))
        {
          if (Editunits_WriteBackGroup ())
            Editunits_SetupGroup ( ed_data.current_group + 1 );
        }
      }
      else
      {
        if (ed_data.current_group > 0)
        {
          if (Editunits_WriteBackGroup ())
            Editunits_SetupGroup ( ed_data.current_group - 1 );
        }
      }
      break;

    case EDITUNITS_SET_DEC:
      inc = -inc;
    case EDITUNITS_SET_INC:
      if (inc > 0)
      {
        if (ed_data.current_set < ( edptr->no_of_sets - 1 ))
        {
          if (Editunits_WriteBackSet ())
            Editunits_SetupSet ( ed_data.current_group, ed_data.current_set + 1 );
        }
      }
      else
      {
        if (ed_data.current_set > 0)
        {
          if (Editunits_WriteBackSet ())
            Editunits_SetupSet ( ed_data.current_group, ed_data.current_set - 1 );
        }
      }
      break;

  }

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (event);
}


/*******************************************************************/
/* Functions to Insert and Delete items
   This is all done solely using the contents of the writable fields
   since there is no way of determining whether the user has already
   made some changes to some of the fields
*/
/*******************************************************************/


static void Editunits_InsertItem (void)
{
  wimp_caret cpos;
  toolbox_o wid;
  toolbox_c cmp;
  int row;
  char tbuf[TBUF_SIZE];
  int len, len2;
  int i;

  /* Get caret position */
  wimp_get_caret_position (&cpos);
  window_wimp_to_toolbox ( 0, cpos.w, cpos.i, &wid, &cmp );
  if ( wid == Editunits_winid )
  {
    if ((cmp >= EDITUNITS_UNIT_BASE) && (cmp < (EDITUNITS_FACTOR_BASE + 9)))
    {
      /* in one of the unit or factor fields */
      row = (int)cmp - EDITUNITS_UNIT_BASE;
      if (row > 8) row -= 9;
      /* Is the last row of data blank? */
      len = writablefield_get_value ( 0, Editunits_winid,
                         UNITITEMS_MAX_INDEX + EDITUNITS_UNIT_BASE, tbuf, TBUF_SIZE);
      len2 = writablefield_get_value ( 0, Editunits_winid,
                         UNITITEMS_MAX_INDEX + EDITUNITS_FACTOR_BASE, tbuf, TBUF_SIZE);
      if ((len == 1) && (len2 == 1))
      {
        /* ok to continue */
        if (row < UNITITEMS_MAX_INDEX)
        {
          /* not the last row */
          /* move items up */
          for (i = UNITITEMS_MAX_INDEX; i > row; i--)
          {
            writablefield_get_value ( 0, Editunits_winid,
                                      i - 1 + EDITUNITS_UNIT_BASE, tbuf, TBUF_SIZE );
            writablefield_set_value ( 0, Editunits_winid,
                                      i + EDITUNITS_UNIT_BASE, tbuf );
            writablefield_get_value ( 0, Editunits_winid,
                                      i - 1 + EDITUNITS_FACTOR_BASE, tbuf, TBUF_SIZE );
            writablefield_set_value ( 0, Editunits_winid,
                                      i + EDITUNITS_FACTOR_BASE, tbuf );
          }
          /* now clear the 'inserted' fields */
          writablefield_set_value (0, Editunits_winid, row + EDITUNITS_UNIT_BASE, "");
          writablefield_set_value (0, Editunits_winid, row + EDITUNITS_FACTOR_BASE, "");
        }
      }
      else
      {
        Msg_Warn (NOMOREITEMS);
      }
    }
  }
  else
  {
    Msg_Warn (CARET);
  }
  return;
}





static void Editunits_DeleteItem (void)
{
  wimp_caret cpos;
  toolbox_o wid;
  toolbox_c cmp;
  int row;
  int i;
  char tbuf[TBUF_SIZE];
  int len;

  /* Get caret position */
  wimp_get_caret_position (&cpos);
  window_wimp_to_toolbox ( 0, cpos.w, cpos.i, &wid, &cmp );
  if ( wid == Editunits_winid )
  {
    if ((cmp >= EDITUNITS_UNIT_BASE) && (cmp < (EDITUNITS_FACTOR_BASE + 9)))
    {
      /* in one of the unit or factor fields */
      row = (int)cmp - EDITUNITS_UNIT_BASE;
      if (row > 8) row -= 9;

      if (row < UNITITEMS_MAX_INDEX)
      {
        /* not the last row */
        /* move later items down */
        for (i = row; i < UNITITEMS_MAX_INDEX; i++)
        {
          writablefield_get_value ( 0, Editunits_winid,
                                    i + 1 + EDITUNITS_UNIT_BASE, tbuf, TBUF_SIZE ) ;
          writablefield_set_value ( 0, Editunits_winid,
                                    i + EDITUNITS_UNIT_BASE, tbuf );
          writablefield_get_value ( 0, Editunits_winid,
                                    i + 1 + EDITUNITS_FACTOR_BASE, tbuf, TBUF_SIZE ) ;
          writablefield_set_value ( 0, Editunits_winid,
                                    i + EDITUNITS_FACTOR_BASE, tbuf );
        }
      }
      /* now clear the last field */
      writablefield_set_value ( 0,
                                Editunits_winid,
                                UNITITEMS_MAX_INDEX + EDITUNITS_UNIT_BASE,
                                "" );
      writablefield_set_value ( 0,
                                Editunits_winid,
                                UNITITEMS_MAX_INDEX + EDITUNITS_FACTOR_BASE,
                                "" );

    }

  }
  else
  {
    Msg_Warn (CARET);
  }
  return;
}




/**********************************************/
/* Functions to Add, Insert and Delete Sets */
/**********************************************/


static void Editunits_DeleteSet (void)
{
  conv_group *edptr ;
  int s;
  conv_set *s1, *s2;

  edptr = ed_data.group[ed_data.current_group];

  if (!CJL_MsgQueryF ("Q303", NULL,
          "Do you wish to continue to delete the %s set?",
          edptr->set[ed_data.current_set].set_name))
     return;

  if ( ed_data.current_set == edptr->no_of_sets - 1 )
  {
    /* We are showing the last set. We just need to show the previous set
    ** and reduce the total sets by one */
    edptr->no_of_sets -= 1;
    Editunits_SetupSet ( ed_data.current_group, edptr->no_of_sets - 1 );
  }
  else
  {
    /* We are not at the last set - must delete the current one and copy
    ** the later ones down */
    for ( s = ed_data.current_set; s < edptr->no_of_sets - 1; s++ )
    {
      s1 = &edptr->set [s];
      s2 = &edptr->set [s+1];
      *s1 = *s2;
    }
    edptr->no_of_sets -= 1;
    Editunits_SetupSet ( ed_data.current_group, ed_data.current_set );
  }
  return;
}




/* Add a new set before the set that is being displayed */

static void Editunits_InsertSet (void)
{
  conv_group *edptr ;
  int s;
  conv_set *s1, *s2;

  if (Editunits_WriteBackSet ())
  {
    edptr = ed_data.group[ed_data.current_group];
    /* Can we add another set */
    if (edptr->no_of_sets < MAX_UC_UNITSETS)
    {
      /* First copy the current and later sets up one place */
      /* The new added top location is = no_of_sets */
      for ( s = edptr->no_of_sets; s > ed_data.current_set; s-- )
      {
        s1 = &edptr->set [s];
        s2 = &edptr->set [s-1];
        *s1 = *s2;
      }
      edptr->no_of_sets++;
      edptr->set [ed_data.current_set].no_of_items = 0;
      edptr->set [ed_data.current_set].set_name[0] = 0x00;

      Editunits_SetupSet ( ed_data.current_group, ed_data.current_set );
    }
    else
    {
      Msg_Warn (NOMORESET);
    }
  }
  return;
}




/* Add a new set to the end of the list */

static void Editunits_AddSet (void)
{
  conv_group *edptr ;

  if (Editunits_WriteBackSet ())
  {
    edptr = ed_data.group[ed_data.current_group];
    /* Can we add another set */
    if (edptr->no_of_sets < MAX_UC_UNITSETS)
    {
      edptr->no_of_sets++;
      edptr->set [ edptr->no_of_sets - 1 ].no_of_items = 0;
      Editunits_SetupSet ( ed_data.current_group, edptr->no_of_sets - 1 );
    }
    else
    {
      Msg_Warn (NOMORESET);
    }
  }
  return;
}


/**********************************************/
/* Functions to Add, Insert and Delete Groups */
/**********************************************/

/* Delete the currently displayed group */

static void Editunits_DeleteGroup (void)
{
  conv_group *grptr ;
  int g;


  if (!CJL_MsgQueryF ("Q305", NULL, "Do you wish to continue to delete this "
                             "complete group?"))
     return;

  if (Editunits_WriteBackGroup ())
  {
    /* Free the memory used for this group */
    free ( ed_data.group[ed_data.current_group] );
    /* Now move the other group data down */
    for ( g = ed_data.current_group; g < ed_data.no_of_groups - 1; g++)
    {
      ed_data.group [g] = ed_data.group [g + 1];
    }
    /* Null the top group pointer */
    ed_data.group [ed_data.no_of_groups - 1] = NULL;
    ed_data.no_of_groups--;
    Editunits_SetupGroup ( ed_data.current_group );
  }
  return;
}




/* Add a new group before the group being displayed */

static void Editunits_InsertGroup (void)
{
  conv_group *grptr ;
  int g;


  if (Editunits_WriteBackGroup ())
  {
    if ( ed_data.no_of_groups < MAX_UC_MENU_ENTRIES )
    {
      /* First allocate the new memory */
      grptr = (conv_group *)calloc (1, sizeof (struct conv_group));
      if ( grptr == NULL )
      {
        Msg_Warn (GROUPNOMEM);
        return;
      }
      /* Move the current group data up to leave a hole - just need to
      ** move the pointers, not the individual data */
      for ( g = ed_data.no_of_groups; g > ed_data.current_group; g--)
      {
        ed_data.group [g] = ed_data.group [g - 1];
      }
      /* Now copy the new pointer into the hole */
      ed_data.group[ed_data.current_group] = grptr;
      ed_data.no_of_groups++;
      grptr->no_of_sets = 1;
      grptr->set [ 0 ].no_of_items = 0;
      Editunits_SetupGroup ( ed_data.current_group );
    }
    else
    {
      Msg_Warn (NOMOREGROUP);
    }
  }
  return;
}





/* Add a new group to the end of the list */

static void Editunits_AddGroup (void)
{
  conv_group *edptr ;


  if (Editunits_WriteBackGroup ())
  {
    if ( ed_data.no_of_groups < MAX_UC_MENU_ENTRIES )
    {
      ed_data.group [ed_data.no_of_groups] =
                        (conv_group *)calloc (1, sizeof (struct conv_group));
      if ( ed_data.group [ed_data.no_of_groups] == NULL )
      {
        Msg_Warn (GROUPNOMEM);
        return;
      }
      edptr = ed_data.group[ed_data.no_of_groups];
      ed_data.no_of_groups++;
      edptr->no_of_sets = 1;
      edptr->set [ 0 ].no_of_items = 0;
      Editunits_SetupGroup ( ed_data.no_of_groups - 1 );
    }
    else
    {
      Msg_Warn (NOMOREGROUP);
    }
  }
  return;
}





static osbool Editunits_MenuMainHandler ( bits event_code,
                                          toolbox_action *action,
                                          toolbox_block *id_block,
                                          void *handle )
{
  switch (event_code)
  {
    case uevent_EDITUNITSMENU_ADDGROUP:
      Editunits_AddGroup ();
      break;

    case uevent_EDITUNITSMENU_INSERTGROUP:
      Editunits_InsertGroup ();
      break;

    case uevent_EDITUNITSMENU_DELETEGROUP:
      Editunits_DeleteGroup ();
      break;

    case uevent_EDITUNITSMENU_ADDSET:
      Editunits_AddSet ();
      break;

    case uevent_EDITUNITSMENU_INSERTSET:
      Editunits_InsertSet ();
      break;

    case uevent_EDITUNITSMENU_DELETESET:
      Editunits_DeleteSet ();
      break;

    case uevent_EDITUNITSMENU_INSERTITEM:
      Editunits_InsertItem ();
      break;

    case uevent_EDITUNITSMENU_DELETEITEM:
      Editunits_DeleteItem ();
      break;

    case uevent_EDITUNITSMENU_SAVE:
      Editunits_SaveConvData ();
      break;

    case action_MENU_DIALOGUE_COMPLETED:
      event_deregister_toolbox_handler ( Editunits_menuid,
                                         action_ANY,
                                         Editunits_MenuMainHandler,
                                         NULL);
      break;

  }

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
  IGNORE (event_code);
}






static osbool Editunits_MenuOpeningHandler ( bits event_code,
                                             toolbox_action *action,
                                             toolbox_block *id_block,
                                             void *handle )
{
  event_register_toolbox_handler ( Editunits_menuid,
                                   action_ANY,
                                   Editunits_MenuMainHandler,
                                   NULL);

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
  IGNORE (event_code);
}





static osbool Editunits_Handler ( bits event_code,
                                  toolbox_action *action,
                                  toolbox_block *id_block,
                                  void *handle )
{
  int i;


  switch (event_code)
  {
    case action_WINDOW_ABOUT_TO_BE_SHOWN:
      Editunits_is_open = TRUE;
      break;

    case uevent_EDITUNITS_SAVE:
      Editunits_SaveConvData ();
      break;

    case action_WINDOW_DIALOGUE_COMPLETED:
      /* get current position of Gases window */
      CJL_GetTopLeftWinPos ( Editunits_winhandle, &Editunits_win_pos );

      event_deregister_toolbox_handler ( Editunits_menuid,
                                         action_MENU_ABOUT_TO_BE_SHOWN,
                                         Editunits_MenuOpeningHandler,
                                         NULL);
      toolbox_delete_object (0, Editunits_menuid);
      Editunits_menuid = toolbox_NULL_OBJECT;

      event_deregister_toolbox_handler ( Editunits_winid,
                                         action_ANY,
                                         Editunits_Handler,
                                         NULL);
      event_deregister_wimp_handler ( Editunits_winid,
                                      wimp_MOUSE_CLICK,
                                      Editunits_MouseClickHandler,
                                      NULL);
      event_deregister_wimp_handler ( Editunits_winid,
                                      wimp_KEY_PRESSED,
                                      Editunits_KeyPress,
                                      NULL );
      toolbox_delete_object ( 0, Editunits_winid );
      Editunits_winid = toolbox_NULL_OBJECT;
      Editunits_is_open = FALSE;
      /* Release the memory used for the units */
      for ( i = 0; i < ed_data.no_of_groups; i++ )
      {
        if (ed_data.group[i] != NULL)
        {
          free (ed_data.group[i]);
          ed_data.group[i] = NULL;
        }
      }
      break;
  }

  return(TRUE);

  /* for compiler */
  IGNORE (handle);
  IGNORE (id_block);
  IGNORE (action);
}




static void Editunits_SetupSet ( int gr, int set )
{
  conv_group *edptr ;
  int i;

  ed_data.current_set = set;
  edptr = ed_data.group[gr];
  /* fill in the set name */
  writablefield_set_value ( 0,
                            Editunits_winid,
                            EDITUNITS_SET,
                            edptr->set[set].set_name );

  /* fill in the data */
  for (i = 0; i < edptr->set[ set ].no_of_items ; i++)
  {
    writablefield_set_value ( 0,
                              Editunits_winid,
                              i + EDITUNITS_UNIT_BASE,
                              edptr->set[set].item[i].unit_name );
    writablefield_set_value ( 0,
                              Editunits_winid,
                              i + EDITUNITS_FACTOR_BASE,
                              edptr->set[set].item[i].factor_txt );

  }
  /* ...and blank the rest */
  for ( i = edptr->set[ set ].no_of_items ; i < MAX_UC_UNITITEMS; i++)
  {
    writablefield_set_value ( 0,
                              Editunits_winid,
                              i + EDITUNITS_UNIT_BASE,
                              "" );
    writablefield_set_value ( 0,
                              Editunits_winid,
                              i + EDITUNITS_FACTOR_BASE,
                              "" );
  }
  if ( Editunits_is_open )
    gadget_set_focus ( 0, Editunits_winid, EDITUNITS_SET );
  return;
}




static void Editunits_SetupGroup ( int gr )
{
  conv_group *edptr ;


  ed_data.current_group = gr;
  edptr = ed_data.group[gr];
  /* fill in the group name */
  writablefield_set_value ( 0, Editunits_winid, EDITUNITS_GROUP, edptr->group_name );
  /* Now set up the first set data in the group */
  Editunits_SetupSet ( gr, 0 );
  if ( Editunits_is_open )
    gadget_set_focus ( 0, Editunits_winid, EDITUNITS_GROUP );
  return;
}




static void Editunits_Setup ( void )
{
  /* Read current units data
  ** claim memory to suit units data struct
  ** copy current units data into data struct
  ** display the conversion data for group 0, set 0
  */

  int i;
  conv_group *ucptr ;
  conv_group *edptr ;

  /* We do not edit the special group, therefore ignore the last
  ** special group */
  ed_data.no_of_groups = uc_data.no_of_groups - 1;

  /* Copy the data already loaded */
  for ( i = 0; i < ed_data.no_of_groups; i++ )
  {
    /* reserve some memory for each group */
    ed_data.group[i] = ( conv_group * ) malloc ( sizeof ( struct conv_group ));
    /* set the pointers */
    ucptr = uc_data.group[i];
    edptr = ed_data.group[i];
    /* copy the contents */
    *edptr = *ucptr;
  }
  /* Now set up the window with the data for the first group */
  Editunits_SetupGroup ( 0 );
  return;
}




void Editunits_Open ( void )
{
  if ( Editunits_winid == toolbox_NULL_OBJECT)
  {
    Editunits_winid = toolbox_create_object ( 0, EDITUNITS_TEMPLATE);
    Editunits_winhandle = window_get_wimp_handle (0, Editunits_winid);
    event_register_toolbox_handler ( Editunits_winid,
                                     action_ANY,
                                     Editunits_Handler,
                                     NULL);
    event_register_wimp_handler ( Editunits_winid,
                                  wimp_MOUSE_CLICK,
                                  Editunits_MouseClickHandler,
                                  NULL);
    event_register_wimp_handler ( Editunits_winid,
                                  wimp_KEY_PRESSED,
                                  Editunits_KeyPress,
                                  NULL );
    /* Also initialise the attached menu */
    if (Editunits_menuid == toolbox_NULL_OBJECT)
    {
      Editunits_menuid = toolbox_create_object ( 0, EDITUNITSMENU_TEMPLATE);
      event_register_toolbox_handler ( Editunits_menuid,
                                       action_MENU_ABOUT_TO_BE_SHOWN,
                                       Editunits_MenuOpeningHandler,
                                       NULL);
    }
    Editunits_Setup ();

  }
  if (Editunits_win_pos.top_left.x == 0)
  {
    toolbox_show_object ( 0,
                          Editunits_winid,
                          toolbox_POSITION_CENTRED,
                          0,
                          toolbox_NULL_OBJECT,
                          toolbox_NULL_COMPONENT ) ;
  }
  else
  {
    toolbox_show_object (0,
                        Editunits_winid,
                        toolbox_POSITION_TOP_LEFT,
                        &Editunits_win_pos,
                        toolbox_NULL_OBJECT,
                        toolbox_NULL_COMPONENT ) ;
  }
  return;
}

