/*************************************************
*    The PMW Music Typesetter - 3rd incarnation  *
*************************************************/

/* Copyright (c) Philip Hazel, 1991 - 2008 */

/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: September 2008 */

/* This file contains some functions for controlling printable output. */


#include "pmwhdr.h"
#include "outhdr.h"



/*************************************************
*        Initialize page list data               *
*************************************************/

/* This function is called at the start of the output phase. Its job is to set
up the number of the first page to be printed, in print_curnumber, and to set
print_curlist to point the first page selection item.

Argument:    TRUE if printing is to be in reverse order
Returns:     nothing
*/

void
print_setup_pagelist(BOOL reverse)
{
print_curlist = output_pagelist;
if (reverse)
  {
  if (print_curlist == NULL)
    print_curnumber = print_lastpage + 1;
  else
    {
    while (print_curlist->next != NULL) print_curlist = print_curlist->next;
    print_curnumber = print_curlist->last + 1;
    }
  }
else
  {
  if (print_curlist == NULL) print_curnumber = main_firstpage - 1;
    else print_curnumber = print_curlist->first - 1;
  }
}



/*************************************************
*          Get next page(s) to print             *
*************************************************/

/* Called from the PostScript output routines. First we have a local function
to get the next specified page, skipping any that do not exist. We have to
handle both backwards and forward movement.

Argument:  nothing
Returns:   pointer to a pagestr, or NULL if no more.
*/

static pagestr *
nextpage(void)
{
for (;;)
  {
  pagestr *yield = main_pageanchor;

  /* Find next page in reverse order */

  if (print_reverse)
    {
    print_curnumber--;
    if (print_curlist == NULL)
      {
      if (print_curnumber < main_firstpage) return NULL;
      }
    else if (print_curnumber < print_curlist->first)
      {
      stave_list * p= output_pagelist;
      if (print_curlist == p) return NULL;
      while (p->next != print_curlist) p = p->next;
      print_curlist = p;
      print_curnumber = print_curlist->last;
      }
    }

  /* Find next page number in given order. */

  else
    {
    print_curnumber++;
    if (print_curlist == NULL)
      {
      if (print_curnumber > print_lastpage) return NULL;
      }
    else if (print_curnumber > print_curlist->last)
      {
      if (print_curlist->next == NULL) return NULL;
      print_curlist = print_curlist->next;
      print_curnumber = print_curlist->first;
      }
    }

  /* If page exists, return it; otherwise loop. However, if we are in pamphlet
  mode with no explicit page list and the page number is past halfway and the
  mate exists, don't return the page. */

  while (yield != NULL)
    {
    if (yield->number == print_curnumber)
      {
      if (print_pamphlet &&
          print_curlist == NULL &&
          print_curnumber > print_lastpage/2)
        {
        pagestr *p = main_pageanchor;
        int mate = print_lastpage - print_curnumber + 1;
        while (p != NULL)
          {
          if (p->number == mate) goto LOOP;
          p = p->next;
          }
        }
      return yield;
      }
    yield = yield->next;
    }
  LOOP:;
  }
}



/* The external function. It returns page structures for one or two pages,
depending on the imposition. The yield is FALSE if there are no more pages.

Arguments:
  p1         where to put a pointer to the first page
  p2         where to put a pointer to the second page

Returns:     FALSE if there are no more pages
*/

BOOL
print_nextpage(pagestr **p1, pagestr **p2)
{
int n;
BOOL swap = FALSE;
*p2 = NULL;

/* Loop for skipping unwanted pages (side selection). For pamphlet printing,
side 1 contains odd-numbered pages less than half the total, and even-numbered
pages greater than half. We may get either kind of page given. */

for (;;)
  {
  if ((*p1 = nextpage()) == NULL) return FALSE;
  n = (*p1)->number;
  if (!print_pamphlet || n <= print_lastpage/2)
    {
    if ((print_side1 && (n & 1) != 0) || (print_side2 && (n & 1) == 0)) break;
    }
  else if ((print_side1 && (n & 1) == 0) || (print_side2 && (n & 1) != 0)) break;
  }

/* Handle 1-up printing: nothing more to do */

if (print_imposition != pc_a5ona4 && print_imposition != pc_a4ona3)
  return TRUE;

/* Handle 2-up printing. For non-pamphlet ordering, just get the next page and
set the order swap flag if required. */

if (!print_pamphlet)
  {
  if ((*p2 = nextpage()) == NULL) print_curnumber--;  /* To get correct display */
  swap = print_reverse;
  }

/* For pamphlet printing, find the mate of the first page, and set the swap
flag if necessary, to ensure the odd-numbered page is on the right. */

else
  {
  n = print_lastpage - n + 1;
  swap = (n & 1) == 0;
  *p2 = main_pageanchor;
  while (*p2 != NULL)
    {
    if ((*p2)->number == n) break;
    *p2 = (*p2)->next;
    }
  }

/* Swap page order if necessary */

if (swap)
  {
  pagestr *temp = *p1;
  *p1 = *p2;
  *p2 = temp;
  }

return TRUE;
}


/* End of print.c */
