/* 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   : PrintStyle.c                           */
/*                                                 */
/* Purpose: Change print style options with the    */
/*          PrintStyle dialogue.                   */
/*                                                 */
/*          This source is fairly closely tied to  */
/*          Print.c, as the Print Style dialogue   */
/*          is typically opened from the Print     */
/*          dialogue.                              */
/*                                                 */
/* Author : A.D.Hodgkinson                         */
/*                                                 */
/* History: 24-Aug-97: Created.                    */
/***************************************************/

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

#include "swis.h"

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

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

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

#include "Browser.h"
#include "Menus.h"
#include "Printing.h"

#include "PrintStyle.h"

/* Local structures and supporting definitions */

#define Background_Show_Type_None   0
#define Background_Show_Type_Tables 1
#define Background_Show_Type_All    2

/* Holds info on the Print Style dialogue's contents; small enough */
/* to hold as a static, as the code to dynamically allocate it     */
/* would occupy more room than the structure itself.               */

typedef struct printstyle_contents
{
  unsigned int underline_links      :1;
  unsigned int use_source_cols      :1;
  unsigned int show_foreground      :1;
  unsigned int show_background      :1;

  unsigned int background_show_type :2; /* 0 = none, 1 = in tables, 2 = all */
  unsigned int black_no_background  :1;
  unsigned int always_use_black     :1;

} printstyle_contents;

/* Local statics */

static printstyle_contents contents;         /* Remember the old dialogue contents so the Cancel button can work, and */
                                             /* other functions can inquire about the state of the contents without   */
                                             /* needing this end to start calling toolbox routines to find out.       */

static ObjectId            window_id    = 0; /* Remember the ID in case it needs closing 'out of the blue'. */
static ObjectId            ancestor_id  = 0; /* Remember then ancestor ID in case the ancestor closes. */

static int                 defaults_set = 0;

/* Static function prototypes */

static _kernel_oserror * printstyle_read_contents    (ObjectId dialogue, printstyle_contents * contents);
static _kernel_oserror * printstyle_set_contents     (ObjectId dialogue, printstyle_contents * contents);

static int               printstyle_cancel           (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);
static int               printstyle_option_group_one (int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle);

/*************************************************/
/* printstyle_read_contents()                    */
/*                                               */
/* Reads the contents of the Print Style         */
/* dialogue into a printstyle_contents struct.   */
/*                                               */
/* Parameters: Object ID of the dialogue;        */
/*                                               */
/*             Pointer to the structure to write */
/*             to.                               */
/*************************************************/

static _kernel_oserror * printstyle_read_contents(ObjectId dialogue, printstyle_contents * contents)
{
  int state;

  /* Read the four basic display options */

  RetError(optionbutton_get_state(0, dialogue, PSUnderlineLinks,       &state)); contents->underline_links = !!state;
  RetError(optionbutton_get_state(0, dialogue, PSUseDocumentColours,   &state)); contents->use_source_cols = !!state;
  RetError(optionbutton_get_state(0, dialogue, PSShowForegroundImages, &state)); contents->show_foreground = !!state;
  RetError(optionbutton_get_state(0, dialogue, PSShowBackgroundImages, &state)); contents->show_background = !!state;

  /* Read the background show type */

  RetError(radiobutton_get_state(0, dialogue, PSAllBackgrounds, NULL, &state));

  switch (state)
  {
    default:
    case PSNoBackgrounds:  contents->background_show_type = Background_Show_Type_None;
    break;

    case PSTablesOnly:     contents->background_show_type = Background_Show_Type_Tables;
    break;

    case PSAllBackgrounds: contents->background_show_type = Background_Show_Type_All;
    break;
  }

  /* Finally, read the 'print text in black' options */

  RetError(optionbutton_get_state(0, dialogue, PSBlackIfNoBackground,  &state));
  contents->black_no_background = !!state;

  RetError(optionbutton_get_state(0, dialogue, PSAlwaysUseBlack, &state));
  contents->always_use_black = !!state;


  return NULL;
}

/*************************************************/
/* printstyle_set_contents()                     */
/*                                               */
/* Sets the contents of the Print Style dialogue */
/* from a printstyle_contents structure.         */
/*                                               */
/* Parameters: Object ID of the dialogue;        */
/*                                               */
/*             Pointer to the structure to read  */
/*             from.                             */
/*************************************************/

static _kernel_oserror * printstyle_set_contents(ObjectId dialogue, printstyle_contents * contents)
{
  /* Set the four basic display options */

  RetError(optionbutton_set_state(0, dialogue, PSUnderlineLinks,       contents->underline_links));
  RetError(optionbutton_set_state(0, dialogue, PSUseDocumentColours,   contents->use_source_cols));
  RetError(optionbutton_set_state(0, dialogue, PSShowForegroundImages, contents->show_foreground));
  RetError(optionbutton_set_state(0, dialogue, PSShowBackgroundImages, contents->show_background));

  /* Ensure the browser (if any) is up to date with this */

  printstyle_option_group_one(0, NULL, NULL, NULL);

  /* Set the background show type */

  switch (contents->background_show_type)
  {
    default:
    case Background_Show_Type_None:   RetError(radiobutton_set_state(0, dialogue, PSNoBackgrounds, 1));
    break;

    case Background_Show_Type_Tables: RetError(radiobutton_set_state(0, dialogue, PSTablesOnly, 1));
    break;

    case Background_Show_Type_All:    RetError(radiobutton_set_state(0, dialogue, PSAllBackgrounds, 1));
  }

  /* Finally, set the 'print text in black' options */

  RetError(optionbutton_set_state(0, dialogue, PSBlackIfNoBackground, contents->black_no_background));

  return optionbutton_set_state(0, dialogue, PSAlwaysUseBlack, contents->always_use_black);
}

/*************************************************/
/* printstyle_set_defaults()                     */
/*                                               */
/* Fills in the local printstyle_contents        */
/* structure with the default values to put in   */
/* a Print Style dialogue, if they have not      */
/* already been filled in.                       */
/*                                               */
/* If the dialogue is open, the contents are     */
/* updated.                                      */
/*                                               */
/* Returns:    1 if the structure was filled in, */
/*             else 0.                           */
/*************************************************/

int printstyle_set_defaults(void)
{
  if (!defaults_set)
  {
    /* Read the defaults from the Choices file */

    if      (!strcmp(lookup_choice("PrintBack:tables", 0, 0),"none"))  contents.background_show_type = Background_Show_Type_None;
    else if (!strcmp(lookup_choice("PrintBack:tables", 0, 0),"all"))   contents.background_show_type = Background_Show_Type_All;
    else                                                               contents.background_show_type = Background_Show_Type_Tables;

    if      (!strcmp(lookup_choice("PrintBlack:bg", 0, 0), "always"))  contents.always_use_black = 1, contents.black_no_background = 0;
    else if (!strcmp(lookup_choice("PrintBlack:bg", 0, 0), "never"))   contents.always_use_black = 0, contents.black_no_background = 0;
    else                                                               contents.always_use_black = 0, contents.black_no_background = 1;

    defaults_set = 1;

    if (window_id) printstyle_set_contents(window_id, &contents);

    return 1;
  }

  return 0;
}

/*************************************************/
/* printstyle_to_be_shown()                      */
/*                                               */
/* Called when the EPSToBeShown event is         */
/* generated, typically when the Print Style     */
/* dialogue is about to be shown. Registers      */
/* event handlers for the dialogue, reads and    */
/* sets options in it, etc.                      */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event hander, though only the self_id and     */
/* ancestor_id fields of the ID block are of     */
/* interest.                                     */
/*************************************************/

int printstyle_to_be_shown(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  browser_data * ancestor = NULL;

  /* If the stored dialogue ID is non-zero on entry, the dialogue */
  /* was reopened without closing - so get rid of the various     */
  /* event handlers before we reregister them.                    */

  if (window_id) printstyle_close(0, 0);

  /* Right, record the ID as given in the ID block */

  window_id = idb->self_id;

  /* Sigh. Blimmin' Toolbox. The Setup button in the Print */
  /* dialogue, when used to open Print Style, does not     */
  /* transmit the ancestor ID information - aargh!         */
  /*                                                       */
  /* This appears to be because the underlying window ID   */
  /* is given as this object's parent, rather than the     */
  /* print dialogue, and it doesn't have an ancestor (bug, */
  /* I'd say). Maybe because it's an alternative window,   */
  /* rather than a standard print dialogue? In any case,   */
  /* we must assume that the setup window did come from    */
  /* the print dialogue (and not, say, the choices) if     */
  /* there's no ancestor window, and ask the print         */
  /* routines what window it was for.                      */

  ancestor_id = idb->ancestor_id;

  if (ancestor_id)
  {
    ChkError(toolbox_get_ancestor(0, ancestor_id, &ancestor_id, NULL));
  }
  else
  {
    print_return_dialogue_info(NULL, NULL, &ancestor_id, &ancestor);
  }

  /* Attach event handlers - OK and Cancel functions */

  ChkError(event_register_toolbox_handler(idb->self_id, EPSOK,     printstyle_ok,     NULL));
  ChkError(event_register_toolbox_handler(idb->self_id, EPSCancel, printstyle_cancel, NULL));

  /* If defaults have never been set before, set them now */

  printstyle_set_defaults();

  /* Set up the basic display options to match the ancestor browser, */
  /* if there is one. Do this before registering handlers for the    */
  /* basic display options.                                          */

  if (ancestor)
  {
    contents.underline_links = ancestor->underline_links;
    contents.use_source_cols = ancestor->use_source_cols;
    contents.show_foreground = ancestor->show_foreground;
    contents.show_background = ancestor->show_background;

    ChkError(printstyle_set_contents(idb->self_id, &contents));
  }

  /* Changing basic display type options (so that the browser window */
  /* can be updated to reflect the new settings)                     */

  ChkError(event_register_toolbox_handler(idb->self_id,
                                          EPSOG1,
                                          printstyle_option_group_one,
                                          NULL));

  /* Finished */

  return 1;
}

/*************************************************/
/* printstyle_ok()                               */
/*                                               */
/* Handles clicks on the 'OK' (or 'Use', etc.)   */
/* button in the Print Style dialogue.           */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler (though none are actually       */
/* used).                                        */
/*************************************************/

int printstyle_ok(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  if (!window_id) return 0;

  /* As with the Print dialogue, because this routine takes no */
  /* direct action, other functions are called independently   */
  /* and must act on the 'contents' printstyle_contents struct */
  /* - we can't use a local one here to allow Adjust-clicks.   */

  ChkError(printstyle_read_contents(window_id, &contents));
  ChkError(printstyle_close(0, 0));

  /* No other actual direct action to take; that's done by the Print dialogue */

  return 1;
}

/*************************************************/
/* printstyle_cancel()                           */
/*                                               */
/* Handles clicks on the 'Cancel' button in the  */
/* Print Style dialogue.                         */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler.                                */
/*************************************************/

static int printstyle_cancel(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  WimpGetPointerInfoBlock info;

  /* Restore the old contents */

  ChkError(printstyle_set_contents(window_id, &contents));

  /* If Select was pressed, the dialogue should close. */
  /* (No button => Escape was pressed).                */

  ChkError(wimp_get_pointer_info(&info));

  if ((info.button_state & Wimp_MouseButtonSelect) || !info.button_state)
  {
    ChkError(printstyle_close(0, 0));
  }

  return 1;
}

/*************************************************/
/* printstyle_close()                            */
/*                                               */
/* If the Print Style dialogue is opened, this   */
/* will close it, deregistering any associated   */
/* event handlers.                               */
/*                                               */
/* Parameters: An object ID, or 0. If not zero,  */
/*             the ID must match the ancestor    */
/*             recorded when the dialogue was    */
/*             opened or no action is taken;     */
/*                                               */
/*             0 to close the dialogue, 1 to do  */
/*             everything except that.           */
/*************************************************/

_kernel_oserror * printstyle_close(ObjectId ancestor, int do_not_close)
{
  _kernel_oserror * e = NULL;

  if (ancestor && ancestor != ancestor_id) return NULL;

  if (window_id)
  {
    /* Deregister associated event handlers */

    e = event_deregister_toolbox_handlers_for_object(window_id);
    if (e) goto printstyle_close_exit;

    /* Restore the old contents */

    e = printstyle_set_contents(window_id, &contents);
    if (e) goto printstyle_close_exit;

    /* Close the dialogue */

    if (!do_not_close)
    {
      /* Restore input focus to the Print dialogue, */
      /* if the Print Style dialogue still has it.  */

      utils_restore_caret(window_id);

      /* Now hide the Print Style dialogue */

      e = toolbox_hide_object(0, window_id);
    }
  }

printstyle_close_exit:

  window_id = ancestor_id = 0;
  return e;
}

/*************************************************/
/* printstyle_option_group_one()                 */
/*                                               */
/* Handles clicks on the group of four option    */
/* buttons controlling basic page display.       */
/*                                               */
/* Parameters are as standard for a Toolbox      */
/* event handler (though none are used!).        */
/*************************************************/

static int printstyle_option_group_one(int eventcode, ToolboxEvent * event, IdBlock * idb, void * handle)
{
  browser_data * b;
  int            ul, dc, sf, sb;

  /* What browser is the Print dialogue for, if any? */

  print_return_dialogue_info(NULL, NULL, NULL, &b);

  if (b)
  {
    /* Read the option states */

    ChkError(optionbutton_get_state(0, window_id, PSUnderlineLinks,       &ul));
    ChkError(optionbutton_get_state(0, window_id, PSUseDocumentColours,   &dc));
    ChkError(optionbutton_get_state(0, window_id, PSShowForegroundImages, &sf));
    ChkError(optionbutton_get_state(0, window_id, PSShowBackgroundImages, &sb));

    /* Update the browser to reflect the changes */

    ChkError(browser_set_look(b, window_id, ul, dc, sf, sb));
  }

  return 1;
}

/*************************************************/
/* printstyle_set_look()                         */
/*                                               */
/* If the Print Style dialogue is open for the   */
/* given browser, update option group one with   */
/* the values specified.                         */
/*                                               */
/* If the object changing the look is not the    */
/* Print Style window itself, the changes are    */
/* stored inside the local printstyle_contents   */
/* struct; Cancel will thus not restore them.    */
/* This is because it is assumed that if another */
/* object sets the look (e.g. via. the           */
/* browser_set_look function), this is meant to  */
/* be a change controlled by that object, and it */
/* shouldn't be cancelled if the Print or Print  */
/* Style dialogues go.                           */
/*                                               */
/* Parameters: Object ID of the object that is   */
/*             changing the look of the browser, */
/*             e.g. a menu or even the Print     */
/*             Style dialogue itself, or 0 to    */
/*             have the same effect as the Print */
/*             Style dialogue object ID (see     */
/*             comments above);                  */
/*                                               */
/*             Object ID of the browser that the */
/*             Print Style dialogue should be    */
/*             open for;                         */
/*                                               */
/*             1 to underline links, 0 not to,   */
/*             -1 to not change this state;      */
/*                                               */
/*             1 to use document colours, 0 to   */
/*             use defaults, -1 to not change    */
/*             this state;                       */
/*                                               */
/*             1 to show images, 0 not to (any   */
/*             pending image fetches are started */
/*             up again if 1 is given), or -1 to */
/*             not change this state;            */
/*                                               */
/*             1 to display plain backgrounds, 0 */
/*             to allow background images (and   */
/*             here too, any pending image       */
/*             fetches for background images are */
/*             restarted if 0 is given), or -1   */
/*             to not change this state.         */
/*************************************************/

_kernel_oserror * printstyle_set_look(ObjectId source, ObjectId browser, int underline_links,
                                      int use_source_cols, int show_foreground, int show_background)
{
  int state;

  if (ancestor_id == browser)
  {
    /* Not much to say here - just go through each option in turn */

    if (underline_links >= 0)
    {
      /* Get the option state */

      RetError(optionbutton_get_state(0, window_id, PSUnderlineLinks, &state));

      /* If the requested state is different, set the new state */

      if (state != underline_links) RetError(optionbutton_set_state(0, window_id, PSUnderlineLinks, underline_links));

      /* If we've been given a source ID and it isn't the Print Style   */
      /* dialogue itself, set the new value so Cancel won't destroy it. */

      if (source && source != window_id) contents.underline_links = underline_links;
    }

    if (use_source_cols >= 0)
    {
      RetError(optionbutton_get_state(0, window_id, PSUseDocumentColours, &state));

      if (state != use_source_cols) RetError(optionbutton_set_state(0, window_id, PSUseDocumentColours, use_source_cols));

      if (source && source != window_id) contents.use_source_cols = use_source_cols;
    }

    if (show_foreground >= 0)
    {
      RetError(optionbutton_get_state(0, window_id, PSShowForegroundImages, &state));

      if (state != show_foreground) RetError(optionbutton_set_state(0, window_id, PSShowForegroundImages, show_foreground));

      if (source && source != window_id) contents.show_foreground = show_foreground;
    }

    if (show_background >= 0)
    {
      RetError(optionbutton_get_state(0, window_id, PSShowBackgroundImages, &state));

      if (state == show_background) RetError(optionbutton_set_state(0, window_id, PSShowBackgroundImages, show_background));

      if (source && source != window_id) contents.show_background = show_background;
    }
  }

  return NULL;
}

/*************************************************/
/* printstyle_show_none()                        */
/*                                               */
/* Ask if no backgrounds should be plotted.      */
/*                                               */
/* Returns:    1 if the Print Style dialogue     */
/*             specified no backgrounds, else    */
/*             0.                                */
/*************************************************/

int printstyle_show_none(void)
{
  return (contents.background_show_type == Background_Show_Type_None);
}

/*************************************************/
/* printstyle_show_in_tables_only()              */
/*                                               */
/* Ask if backgrounds should be plotted in       */
/* tables only.                                  */
/*                                               */
/* Returns:    1 if the Print Style dialogue     */
/*             specified backgrounds in tables   */
/*             only, else 0.                     */
/*************************************************/

int printstyle_show_in_tables_only(void)
{
  return (contents.background_show_type == Background_Show_Type_Tables);
}

/*************************************************/
/* printstyle_show_all()                         */
/*                                               */
/* Ask if all backgrounds should be plotted.     */
/*                                               */
/* Returns:    1 if the Print Style dialogue     */
/*             specified all backgrounds, else   */
/*             0.                                */
/*************************************************/

int printstyle_show_all(void)
{
  return (contents.background_show_type == Background_Show_Type_All);
}

/*************************************************/
/* printstyle_black_no_background()              */
/*                                               */
/* Ask if all body text should be plotted in     */
/* black.                                        */
/*                                               */
/* Returns:    1 if the Print Style dialogue     */
/*             specified black body text else 0. */
/*************************************************/

int printstyle_black_no_background(void)
{
  return contents.black_no_background;

  return 0;
}

/*************************************************/
/* printstyle_always_use_black()                 */
/*                                               */
/* Ask if all table text should be plotted in    */
/* black.                                        */
/*                                               */
/* Returns:    1 if the Print Style dialogue     */
/*             specified black table text, else  */
/*             0.                                */
/*************************************************/

int printstyle_always_use_black(void)
{
  return contents.always_use_black;

  return 0;
}

/*************************************************/
/* printstyle_return_dialogue_info()             */
/*                                               */
/* Returns information on the Print Style        */
/* dialogue, and its ancestor.                   */
/*                                               */
/* Parameters: Pointer to an ObjectId, in which  */
/*             the ID of the dialogue is placed; */
/*                                               */
/*             Pointer to an ObjectId, in which  */
/*             the ID of the ancestor window is  */
/*             placed.                           */
/*                                               */
/* Returns:    See parameters list, and note     */
/*             that the returned values will be  */
/*             0, and 0 if the Print Style       */
/*             dialogue is closed.               */
/*                                               */
/* Assumes:    Either pointer may be NULL.       */
/*************************************************/

void printstyle_return_dialogue_info(ObjectId * window, ObjectId * ancestor)
{
  if (window)   *window   = window_id;
  if (ancestor) *ancestor = ancestor_id;
}