/* Copyright 1998 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/***************************************************/
/* File   : SetPBoxes.c                            */
/*                                                 */
/* Purpose: Functions relating to the Set Post_In  */
/*          / Post_Out dialogue box.               */
/*                                                 */
/* Author : A.D.Hodgkinson                         */
/*                                                 */
/* History: 19-Mar-98: Created.                    */
/***************************************************/

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

#include "swis.h"

#include "wimp.h"
#include "wimplib.h"
#include "event.h"

#include "toolbox.h"
#include "window.h"

#include "svcprint.h"
#include "Global.h"
#include "Utils.h"

#include "Multiuser.h"
#include "Save.h"

#include "SetPBoxes.h"

/* This doesn't do much unless in a multiuser build... */

#ifndef SINGLE_USER

  /* Local statics */

  static ObjectId dbox = NULL_ObjectId;

  /* Static function prototypes */

  static int setpboxes_ok     (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);
  static int setpboxes_cancel (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);

  /*************************************************/
  /* setpboxes_check_boxes()                       */
  /*                                               */
  /* Find out whether !Post_In and !Post_Out, set  */
  /* in choices.post_in and choices.post_out, are  */
  /* at least readable as directories or image     */
  /* files.                                        */
  /*                                               */
  /* Parameters: Pointer to an int, in which 1 is  */
  /*             written if Post_In is readable as */
  /*             a directory or image file, else 0 */
  /*             is written;                       */
  /*                                               */
  /*             Similarly, pointer to an int for  */
  /*             Post_Out.                         */
  /*                                               */
  /* Assumes:    Either int pointer may be NULL.   */
  /*************************************************/

  void setpboxes_check_boxes(int * in, int * out)
  {
    int attr;
    int in_ok  = 0;
    int out_ok = 0;

    /* Which can't we find - Post_In, Post_Out or both? */

    _swix(OS_File,
          _INR(0,1) | _OUT(0),

          17,              /* Read catalogue info for named object */
          choices.post_in,

          &attr);

    if (attr == 2 || attr == 3) in_ok = 1; /* 2 = dir, 3 = image file (so could be dir) */

    _swix(OS_File,
          _INR(0,1) | _OUT(0),

          17,              /* Read catalogue info for named object */
          choices.post_out,

          &attr);

    if (attr == 2 || attr == 3) out_ok = 1; /* 2 = dir, 3 = image file (so could be dir) */

    /* Return the values */

    if (in)  *in  = in_ok;
    if (out) *out = out_ok;

    return;
  }

  /*************************************************/
  /* setpboxes_show_dialogue()                     */
  /*                                               */
  /* Create, fill in and show the SetPBoxes        */
  /* dialogue box.                                 */
  /*************************************************/

  _kernel_oserror * setpboxes_show_dialogue(void)
  {
    char help_panel[Limits_Help];

    int  in_ok  = 0;
    int  out_ok = 0;

    setpboxes_check_boxes(&in_ok, &out_ok);

    /* Show the 'question mark' icon bar icon */

    show_error_ret(multiuser_set_iconbar_variant("q"));

    /* Create the dialogue box */

    RetError(toolbox_create_object(0,
                                   "SetPBoxes",
                                   &dbox));

    /* Fill in the main writable. First compile the text. */

    StrNCpy0(help_panel,
             lookup_token("SPB1:The browser cannot find \"",
                          0,
                          0));

    /* We either have only Post_In, only Post_Out or neither. If */
    /* we have both, assume someone called by accident or in a   */
    /* panic, so treat as if none could be found.                */

    if (in_ok && !out_ok)
    {
      /* No Post_Out */

      if (
           strlen(help_panel) + sizeof("!Post_Out") < sizeof(help_panel)
         )
         strcat(help_panel, "!Post_Out");
    }
    else if (!in_ok && out_ok)
    {
      /* No Post_In */

      if (
           strlen(help_panel) + sizeof("!Post_In") < sizeof(help_panel)
         )
         strcat(help_panel, "!Post_In");
    }
    else
    {
      /* Neither or both (treat latter as neither, see above) */

      if (
           strlen(help_panel) + sizeof("!Post_In") < sizeof(help_panel)
         )
         strcat(help_panel, "!Post_In");

      if (
           strlen(help_panel) + strlen(lookup_token("SPB2:\" or \"",0,0)) + 1 < sizeof(help_panel)
         )
         strcat(help_panel, tokens);

      if (
           strlen(help_panel) + sizeof("!Post_Out") < sizeof(help_panel)
         )
         strcat(help_panel, "!Post_Out");
    }

    if (
         strlen(help_panel)

         + strlen(lookup_token("SPB3:\". To set the locations of either, drag them to the writable icons below or type in their filenames directly. Then click on 'Set'.",
                  0,
                  0))
         + 1

         < sizeof(help_panel)
       )
       strcat(help_panel, tokens);

    /* Now put it into the icon */

    button_set_value(0,
                     dbox,
                     SetPBoxes_Prompt,
                     help_panel);

    /* Fill in the writables. Errors on setting are ignored, but   */
    /* errors on reading are not, so these gadgets must be present */
    /* (write errors are ignored in case the path happens to be    */
    /* too long for the buffer, say, which isn't necessarily fatal */
    /* if the path is going to be reset anyway).                   */

    writablefield_set_value(0,
                            dbox,
                            SetPBoxes_InWrit,
                            choices.post_in);

    writablefield_set_value(0,
                            dbox,
                            SetPBoxes_OutWrit,
                            choices.post_out);

    /* Event handlers */

    RetError(event_register_toolbox_handler(dbox,
                                            ESetPBoxes_OK,
                                            setpboxes_ok,
                                            NULL));

    RetError(event_register_toolbox_handler(dbox,
                                            ESetPBoxes_Cancel,
                                            setpboxes_cancel,
                                            NULL));

    /* Open the dialogue */

    return toolbox_show_object(0,
                               dbox,
                               Toolbox_ShowObject_Centre,
                               NULL,
                               NULL_ObjectId,
                               NULL_ComponentId);
  }

  /*************************************************/
  /* setpboxes_check_message()                     */
  /*                                               */
  /* Check to see if a Wimp_MDataLoad is for the   */
  /* writables in the Set Post_In / Post_Out       */
  /* dialogue box or not. If so, deal with it.     */
  /*                                               */
  /* Parameters: Pointer to a WimpMessage block    */
  /*             containing a Wimp_MDataLoad.      */
  /*                                               */
  /* Returns:    1 if the message was of interest, */
  /*             else 0.                           */
  /*************************************************/

  int setpboxes_check_message(WimpMessage * m)
  {
    int          window;

    int          icon_in  [2];
    int          icon_out [2];

    const char * name = m->data.data_load.leaf_name;

    if (dbox == NULL_ObjectId) return 0;

    /* Check the window handle */

    if (
         window_get_wimp_handle(0,
                                dbox,
                                &window)
       )
       return 0;

    if (window != m->data.data_load.destination_window) return 0;

    /* We swallow the message either way now, but still need to */
    /* check which icon it was dropped over.                    */

    if (
         gadget_get_icon_list(0,
                              dbox,
                              SetPBoxes_InWrit,
                              icon_in,
                              sizeof(icon_in),
                              NULL)
       )
       return 1;

    if (
         gadget_get_icon_list(0,
                              dbox,
                              SetPBoxes_OutWrit,
                              icon_out,
                              sizeof(icon_out),
                              NULL)
       )
       return 1;

    /* Deal with a drop on the Post_In writable */

    if (icon_in[0] == m->data.data_load.destination_icon)
    {
      const char * d = strrchr(name, '.');
      const char * f = strstr(name, ".!Post_In");

      if (d == f)
      {
        show_error_ret(writablefield_set_value(0,
                                               dbox,
                                               SetPBoxes_InWrit,
                                               (char *) name));
      }
    }

    /* Deal with a drop on the Post_Out writable */

    else if (icon_out[0] == m->data.data_load.destination_icon)
    {
      const char * d = strrchr(name, '.');
      const char * f = strstr(name, ".!Post_Out");

      if (d == f)
      {
        show_error_ret(writablefield_set_value(0,
                                               dbox,
                                               SetPBoxes_OutWrit,
                                               (char *) name));
      }
    }

    /* Exit, saying we dealt with the message */

    return 1;
  }

  /*************************************************/
  /* setpboxes_ok()                                */
  /*                                               */
  /* Handle ESetPBoxes_OK events, usually from a   */
  /* click on the 'OK' / 'Set' button in the       */
  /* Set Post_In / Post_Out dialogue box.          */
  /*                                               */
  /* Parameters are as standard for a Toolbox      */
  /* event handler.                                */
  /*************************************************/

  static int setpboxes_ok(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
  {
    char path[Limits_Multi_Pathname];

    int  in_ok  = 0;
    int  out_ok = 0;

    /* Read Post_In */

    *path = 0;

    show_error_ret(writablefield_get_value(0,
                                           idb->self_id,
                                           SetPBoxes_InWrit,
                                           path,
                                           sizeof(path),
                                           NULL));

    /* Allocate memory for this in choices.post_in */

    free(choices.post_in);

    choices.post_in = malloc(strlen(path) + 1);
    if (choices.post_in) strcpy(choices.post_in, path);

    /* Read Post_Out */

    *path = 0;

    show_error_ret(writablefield_get_value(0,
                                           idb->self_id,
                                           SetPBoxes_OutWrit,
                                           path,
                                           sizeof(path),
                                           NULL));

    /* Allocate memory for this in choices.post_in */

    free(choices.post_out);

    choices.post_out = malloc(strlen(path) + 1);
    if (choices.post_out) strcpy(choices.post_out, path);

    /* If either allocation failed, complain and shut down */

    if (
         !choices.post_in  ||
         !choices.post_out
       )
    {
      show_error(make_no_memory_error(33));

      /* Just in case someone changes the behaviour above to not exit, */
      /* we should return cleanly here                                 */

      return 1;
    }

    /* If we have an invalid post_in or post_out, complain and */
    /* leave the dialogue box up.                              */

    if (
         *choices.post_in  &&
         *choices.post_out
       )
       setpboxes_check_boxes(&in_ok, &out_ok);

    if (!in_ok || !out_ok)
    {
      erb.errnum = Utils_Error_Custom_Message;

      StrNCpy0(erb.errmess,
               lookup_token("NoPBoxSet:You must set a valid location for both !Post_In and !Post_Out.",
                            0,
                            0));

      show_error_ret(&erb);

      return 1;
    }

    /* Post_In / Post_Out OK, so get rid of the dialogue box */

    event_deregister_toolbox_handlers_for_object(idb->self_id);
    toolbox_delete_object(0, idb->self_id);

    /* Save the settings */

    show_error_ret(save_save_choices(NULL));

    /* Show the log in prompt */

    show_error(multiuser_login());

    return 1;
  }

  /*************************************************/
  /* setpboxes_cancel()                            */
  /*                                               */
  /* Handle ESetPBoxes_Cancel events, usually from */
  /* a click on the 'Cancel' / 'Exit' button in    */
  /* the Set Post_In / Post_Out dialogue box.      */
  /*                                               */
  /* NB This will quit the browser through calling */
  /* exit(EXIT_SUCCESS)!                           */
  /*                                               */
  /* Parameters are as standard for a Toolbox      */
  /* event handler.                                */
  /*************************************************/

  static int setpboxes_cancel(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
  {
    /* Tidy up, in case someone later wants this code to keep */
    /* the browser alive rather than shutting it down.        */

    event_deregister_toolbox_handlers_for_object(idb->self_id);
    toolbox_delete_object(0, idb->self_id);

    /* Quit */

    exit(EXIT_SUCCESS);

    /* Keep compiler happy */

    return 1;
  }

#endif