/************************************************************
**
** Application: SyncDiscs
**
** Title:       c.progress
**
*************************************************************/

/*
*
* Copyright (c) 2017, David Pilling and Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/* Include files */
/* from standard clib */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <locale.h>
#include <time.h>

#include "Tasklib:h.os"
#include "Tasklib:h.wimp"
#include "Tasklib:h.werr"
#include "Tasklib:h.wos"
#include "Tasklib:h.err"
#include "Tasklib:h.poll"
#include "Tasklib:h.temp"
#include "Tasklib:h.etc"
#include "Tasklib:h.pane"
#include "Tasklib:h.akbd"

/* from application */
#include "h.reslink"
#include "h.dbox"
#include "h.syncdiscs"
#include "h.progress"


/************************************************************/

/* Local defines */

/* icon ids in progress window */
#define PROGRESS_STATUS 1
#define PROGRESS_FROM 2
#define PROGRESS_ABORT 4
#define PROGRESS_PAUSECONT 5
#define PROGRESS_CLOSE 6
#define PROGRESS_PRIMARY 8
#define PROGRESS_SECONDARY 15
#define PROGRESS_JOB_COUNT 10
#define PROGRESS_FA_COUNT 12

/* lengths here are 1 less than template value to allow for terminator null
 */
#define PROGRESS_STATUS_LENGTH 63
#define PROGRESS_PATH_LENGTH 63
#define PROGRESS_FROM_LENGTH 48
#define PROGRESS_JOB_COUNT_LENGTH 4
#define PROGRESS_FA_COUNT_LENGTH 4

int         progress_handle = 0;
static win_position prog_pos;

/* Function prototypes */
static os_error *progress_set_icon_text (int win, int ic, char *text);


/************************************************************/

static os_error *progress_click (int handle, int userhandle, wimp_mousestr * m)
{
  os_error   *err;

  err = NULL;

  switch (m->i)
  {
  case PROGRESS_ABORT:
    /***********************************************************************
     * User has stopped the sync. Set the stop flag and also ensure the    *
     * pause flag is unset, otherwise the zeroevent handler will be        *
     * removed on further polling, making the stop slow to take effect     *
     ***********************************************************************/
    sync_stop = 1;
    sync_pause = 0;
    /* Shade the buttons since pressing again should have no effect */
    progress_shade_buttons ();
    break;

  case PROGRESS_PAUSECONT:
    sync_pause ^= 1;
    if (sync_pause)
    {
      progress_set_icon_text (progress_handle, PROGRESS_PAUSECONT, "Continue");
      progress_update_status_field ("Scan paused - click Continue");
    }
    else
    {
      progress_set_icon_text (progress_handle, PROGRESS_PAUSECONT, "Pause");
    }
    break;

  case PROGRESS_CLOSE:
    progress_close (0, 0);
    break;

  }

  return (err);

  USE (userhandle);
  USE (handle);
}




/************************************************************/

os_error   *progress_open (void)
{
  os_error   *err;

  if (progress_handle)
  {
    err = forward (progress_handle, 0, NULL);
  }
  else
  {
    err = createwindow (TPROGRESS, &progress_handle);
    if (!err)
    {
      addcloseevent (progress_close, progress_handle, 0);
      addclickevent (progress_click, progress_handle, 0);
      /* A drag of syncjob */
      adddataload (progress_handle, 0, jobload);
      adddataloadtype (progress_handle, 0, jobloadtype);
      addhelpevent (NULL, progress_handle, TPROGRESS);
      progress_unshade_buttons ();
      if (sync_pause)
	progress_set_icon_text (progress_handle, PROGRESS_PAUSECONT, "Continue");
      else
	progress_set_icon_text (progress_handle, PROGRESS_PAUSECONT, "Pause");
      if (prog_pos.first_time)
      {
	popup (progress_handle, 0);
	prog_pos.first_time = 0;
      }
      else
      {
	open (progress_handle, prog_pos.x0, prog_pos.y0,
	      prog_pos.x1, prog_pos.y1, 0, 0, -1);
      }
      progress_update_job_count_field ();
      progress_update_fa_count_field ();
    }
  }
  return (err);
}







/************************************************************/

os_error   *progress_close (int w, int userhandle)
{
  os_error   *err;
  mousestr    mouse;
  BOOL close_progress_dbox = TRUE;


  err = getpointer (&mouse);
  if (mouse.buttons == 1)
  {
    /* If adjust used to close window, open syncdisc window */
    if (akbd_pollsh() && sync_running)
    {
      /* We want to reopen the syncdiscs window without closing the
         progress window */
      close_progress_dbox = FALSE;
    }
    opensyncdiscs ();
  }


  if (close_progress_dbox)
  {
    wos_savewindposition (progress_handle, &prog_pos);
    remclickevent (progress_click, progress_handle, 0);
    remcloseevent (progress_close, progress_handle, 0);
    remdataload (progress_handle, 0, jobload);
    remdataloadtype (progress_handle, 0, jobloadtype);
    remhelpevent (NULL, progress_handle, TPROGRESS);

    err = closedown (&progress_handle);
  }


  return (err);

  USE (userhandle);
  USE (w);
}


/*****************************************************************************
 *                                                                           *
 * When an icon with a border is being updated very rapidly the icon border  *
 * tends to flicker as the icon is continually redrawn. The following        *
 * function modifies the more normal whole icon update to redraw only the    *
 * icon 'contents' and not the border by leaving an edge all around the      *
 * icon which is not redrawn                                                 *
 *                                                                           *
 *****************************************************************************/

#define EDGE 4

static os_error *progress_refreshicon_contents (int win,
						wimp_icon * iconinfo)
{
  os_error   *err;
  wimp_redrawstr rblock;
  int         more;


  rblock.w = win;
  rblock.box.x0 = iconinfo->box.x0 + EDGE;
  rblock.box.y0 = iconinfo->box.y0 + EDGE;
  rblock.box.x1 = iconinfo->box.x1 - EDGE;
  rblock.box.y1 = iconinfo->box.y1 - EDGE;

  err = wimp_update_wind (&rblock, &more);
  if (!err)
  {
    while (more)
    {
      if ((err = wimp_get_rectangle (&rblock, &more)) != NULL)
	break;
    }
  }
  return (err);
}




/************************************************************/

static os_error *progress_set_icon_text (int win, int ic, char *text)
{
  os_error   *err;
  wimp_icon   iconinfo;

  err = wimp_get_icon_info (win, ic, &iconinfo);

  if (!err)
  {
    if (iconinfo.flags & wimp_INDIRECT)
    {
      /* len = strlen(text); if ( len >= iconinfo.data.indirecttext.bufflen
       * ) { text[iconinfo.data.indirecttext.bufflen - 1]='\0'; } */

      /* Only write the new text if it differs from the existing text */
      if (strcmp (iconinfo.data.indirecttext.buffer, text))
      {
	strcpy (iconinfo.data.indirecttext.buffer, text);

	err = progress_refreshicon_contents (win, &iconinfo);
      }
    }
  }

  return (err);
}


/************************************************************/

static os_error *progress_update_field (char *text, int ic_no, int max_len)
{
  int         len;
  char        local[256];
  char       *p;

  /* take a local copy */
  strcpy (local, text);
  /* check length of string */
  len = strlen (local);
  p = local;
  if (len >= max_len)
  {
    p += len - max_len;
    /* Overwrite first 3 chars with ... */
    strncpy (p, "...", 3);
  }
  /* now update the icon */

  return (progress_set_icon_text (progress_handle, ic_no, p));
}




/************************************************************/

os_error * progress_update_job_count_field (void)
{
  os_error   *err;
  char str[5];
  int n;

  if (!progress_handle)
    return (NULL);

  /* number of jobs waiting in the queue is one less than jobs.number */
  n = jobs.number;
  if (n > 0) n--;
  sprintf (str, "%d", n);
  err = progress_update_field (str, PROGRESS_JOB_COUNT, PROGRESS_JOB_COUNT_LENGTH);

  return (err);
}





/************************************************************/

os_error * progress_update_fa_count_field (void)
{
  os_error   *err;
  char str[5];
  int n;

  if (!progress_handle)
    return (NULL);

  sprintf (str, "%d", farunning.count);
  err = progress_update_field (str, PROGRESS_FA_COUNT, PROGRESS_FA_COUNT_LENGTH);

  return (err);
}





/************************************************************/

os_error   *progress_update_primary_field (char *str)
{
  os_error   *err;

  if (!progress_handle)
    return (NULL);

  err = progress_update_field (str, PROGRESS_PRIMARY, PROGRESS_PATH_LENGTH);

  return (err);
}



/************************************************************/

os_error   *progress_update_secondary_field (char *str)
{
  os_error   *err;

  if (!progress_handle)
    return (NULL);

  err = progress_update_field (str, PROGRESS_SECONDARY, PROGRESS_PATH_LENGTH);

  return (err);
}



/************************************************************/

os_error   *progress_update_status_field (char *status)
{
  os_error   *err;

  if (!progress_handle)
    return (NULL);

  err = progress_update_field (status, PROGRESS_STATUS, PROGRESS_STATUS_LENGTH);

  return (err);
}



/************************************************************/

os_error   *progress_update_file_field (char *from)
{
  os_error   *err;

  if (!progress_handle)
    return (NULL);

  err = progress_update_field (from, PROGRESS_FROM, PROGRESS_FROM_LENGTH);

  return (err);
}



/************************************************************/

os_error   *progress_update (char *status, char *from)
{
  os_error   *err;


  if (!progress_handle)
    return (NULL);

  err = progress_update_field (status, PROGRESS_STATUS, PROGRESS_STATUS_LENGTH);
  if (!err)
  {
    err = progress_update_field (from, PROGRESS_FROM, PROGRESS_FROM_LENGTH);
  }
  return (err);
}


/************************************************************/

os_error   *progress_init (void)
{
  prog_pos.first_time = 1;
  return (NULL);
}



/************************************************************/

void progress_shade_buttons (void)
{
  if (progress_handle)
  {
    report (shadeicon (progress_handle, PROGRESS_ABORT));
    report (shadeicon (progress_handle, PROGRESS_PAUSECONT));
  }
  return;
}



/************************************************************/

void progress_unshade_buttons (void)
{
  report (unshadeicon (progress_handle, PROGRESS_ABORT));
  report (unshadeicon (progress_handle, PROGRESS_PAUSECONT));
  return;
}






/*************  End of c.progress  ***********************/



