/* Copyright 1997 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   : SaveObject.c                           */
/*                                                 */
/* Purpose: Handle the Save Object dialogue        */
/*          (actual object saving is done in       */
/*          Save.c).                               */
/*                                                 */
/* Author : A.D.Hodgkinson                         */
/*                                                 */
/* History: 03-Sep-97: Created.                    */
/*                                                 */
/*          05-Sep-97: Split so bulk became the    */
/*                     SaveFile source, and the    */
/*                     small fetch saving stayed   */
/*                     in here.                    */
/***************************************************/

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

#include "swis.h"

#include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */

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

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

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

#include "Browser.h"
#include "Fetch.h"  /* (For ISLINK macro) */
#include "Protocols.h"
#include "Save.h"
#include "SaveFile.h"
#include "Windows.h"

#include "SaveObject.h"

/* Static function prototypes */

static int saveobject_drag_ended (int eventcode, ToolboxEvent * event, IdBlock * idb, browser_data * handle);
static int saveobject_ok         (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);
static int saveobject_cancel     (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);

/*************************************************/
/* saveobject_open_for()                         */
/*                                               */
/* Creates and opens a Save Object dialogue for  */
/* a given browser, opening near the pointer.    */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             which is the ancestor of the      */
/*             dialogue.                         */
/*************************************************/

_kernel_oserror * saveobject_open_for(browser_data * b)
{
  ObjectId id;

  /* Create and show the object */

  RetError(toolbox_create_object(0,
                                 "SaveObject",
                                 &id));

  /* Remember the ID */

  b->save_dbox = id;

  /* Show it - everything else is done when the ToBeShown */
  /* event comes in.                                      */

  RetError(toolbox_show_object(0,
                               id,
                               Toolbox_ShowObject_Centre,
                               NULL,
                               b->self_id,
                               -1));

  return NULL;
}

/*************************************************/
/* saveobject_to_be_shown()                      */
/*                                               */
/* Fills in the Save Object dialogue prior to    */
/* being shown.                                  */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

int saveobject_to_be_shown(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  char           text[Limits_OS_Pathname];
  browser_data * b;

  /* Process the writable icon text */

  ChkError(windows_process_component_text(idb->self_id, SaveObjectWrit, text, sizeof(text), 0, 1));

  /* Where did we come from? */

  ChkError(toolbox_get_client_handle(0, idb->ancestor_id, (void *) &b));

  #ifndef TRACE

    if (!is_known_browser(b)) return 0;

  #else

    if (!is_known_browser(b))
    {
      erb.errnum = 0;
      sprintf(erb.errmess,
              "Save dialogue origin of object is suspect; given browser %p is unknown, in saveobject_to_be_shown",
              b);

      show_error_ret(&erb);

      return 0;
    }

  #endif

  ChkError(savefile_set_leafname_from_url(idb->self_id, SaveObjectWrit, browser_fetch_url(b)));

  /* Set the draggable sprite */

  ChkError(savefile_set_filetype(idb->self_id, SaveObjectDrag, b->save_type, 1));

  /* Install required event handlers */

  ChkError(event_register_toolbox_handler(idb->self_id, Draggable_DragEnded, (ToolboxEventHandler *) saveobject_drag_ended, b));

  ChkError(event_register_toolbox_handler(idb->self_id, ESaveObjectOK,     saveobject_ok,     b));
  ChkError(event_register_toolbox_handler(idb->self_id, ESaveObjectCancel, saveobject_cancel, b));

  return 1;
}

/*************************************************/
/* saveobject_drag_ended()                       */
/*                                               */
/* Handle Draggable_DragEnded events from the    */
/* Save Object dialogue draggable sprite gadget. */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int saveobject_drag_ended(int eventcode, ToolboxEvent * event, IdBlock * idb, browser_data * handle)
{
  DraggableDragEndedEvent * drag = (DraggableDragEndedEvent *) event;
  WimpGetPointerInfoBlock   info;
  int                       window_handle;
  char                      path[Limits_OS_Pathname];
  char                    * leaf;

  /* If the user dragged back to the save dialogue, do nothing */

  ChkError(window_get_wimp_handle(0,
                                  idb->self_id,
                                  &window_handle));

  if (window_handle == drag->window_handle) return 1;

  /* Get the pathname from the Save Object dialogue. */

  ChkError(writablefield_get_value(0,
                                   idb->self_id,
                                   SaveObjectWrit,
                                   path,
                                   sizeof(path),
                                   NULL));

  path[sizeof(path) - 1] = 0;

  /* Point to the leafname component */

  leaf = strrchr(path, '.');
  if (!leaf) leaf = path;
  else       leaf ++;

  /* Send out the DataSave message */

  info.x             = drag->x;
  info.y             = drag->y;
  info.window_handle = drag->window_handle;
  info.icon_handle   = drag->icon_handle;

  ChkError(protocols_atats_send_data_save(handle,
                                          NULL,
                                          leaf,
                                          save_object_size(handle),
                                          handle->save_type,
                                          protocols_saving_object,
                                          &info));
  return 1;
}

/*************************************************/
/* saveobject_ok()                               */
/*                                               */
/* Handles clicks on the 'OK' button in the      */
/* Save Object dialogue.                         */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int saveobject_ok(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  char           path[Limits_OS_Pathname];
  char         * leaf;
  browser_data * b;

  /* Get the pathname from the Save Object dialogue. */

  ChkError(writablefield_get_value(0,
                                   idb->self_id,
                                   SaveObjectWrit,
                                   path,
                                   sizeof(path),
                                   NULL));

  path[sizeof(path) - 1] = 0;

  /* Is this fully specified? */

  leaf = strrchr(path, '.');

  if (!leaf)
  {
    StrNCpy0(erb.errmess,
             lookup_token("GivePath:To save, drag the file icon to a directory viewer",
                          0,
                          0));

    erb.errnum = Utils_Error_Custom_Message;

    ChkError(&erb);
  }

  /* Where did we come from? */

  ChkError(toolbox_get_client_handle(0, idb->ancestor_id, (void *) &b));

  if (!is_known_browser(b)) return 0;

  /* First, hide the Save Object dialogue */

  ChkError(saveobject_close(b));

  /* Set the paths etc. and allow the fetch to continue */

  ChkError(save_save_object(path, b));

  return 1;
}

/*************************************************/
/* saveobject_cancel()                           */
/*                                               */
/* Handles clicks on the 'Cancel' button in the  */
/* Save Object dialogue                          */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int saveobject_cancel(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  browser_data * b;

  /* We don't do anything sophisticated, like */
  /* restoring previous options here, as the  */
  /* dialogue is too simple for it to be      */
  /* worthwhile.                              */

  ChkError(toolbox_get_client_handle(0, idb->ancestor_id, (void *) &b));

  /* If we were fetching, stop the fetch */

  if (b && is_known_browser(b) && b->save_link) fetch_stop(b, 0);

  /* Close the dialogue */

  ChkError(saveobject_close(b));

  return 1;
}

/*************************************************/
/* saveobject_close()                            */
/*                                               */
/* If the Save Object dialogue is opened, this   */
/* will close it, deregistering any associated   */
/* event handlers. The dialogue is deleted.      */
/*                                               */
/* Parameters: Pointer to a browser_data struct  */
/*             relevant to the dialogue.         */
/*************************************************/

_kernel_oserror * saveobject_close(browser_data * b)
{
  _kernel_oserror * e;
  int               required;

  if (!b->save_dbox) return NULL;

  /* Record whatever pathname is in the dialogue for use in */
  /* future dialogues.                                      */

  RetError(writablefield_get_value(0,
                                   b->save_dbox,
                                   SaveObjectWrit,
                                   NULL,
                                   0,
                                   &required));

  /* Get rid of any event handlers */

  RetError(event_deregister_toolbox_handlers_for_object(b->save_dbox));

  /* Delete the dialogue */

  e = toolbox_delete_object(0, b->save_dbox);
  b->save_dbox = 0;

  return e;
}