/** 
 *  Yudit Unicode Editor Source File
 *
 *  GNU Copyright (C) 1997-2023  Gaspar Sinai <gaspar@yudit.org>  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "stoolkit/SString.h"
#include "stoolkit/STypes.h" 
#include "swindow/SPrinter.h"
#include "swidget/STextView.h"
#include "swidget/SUniPrint.h"


/**
 * This is a stoolkit printer.
 * Currently it only prints on A4 portrait.
 */
SUniPrint::SUniPrint (const SPrinter& _printer, 
           const SString& headerFontName,  double headerFontSize,
           const SString& bodyFontName,  double bodyFontSize) :
    printer (_printer),
    body(false),
    headerLeft(false),
    headerCenter(false),
    headerRight(false)
{
  pageCount = 0;
  printheader = (headerFontSize > 1.0);
  SLocation l = SLocation (printer.getX(), printer.getY());
  SDimension d = SDimension (printer.getWidth(), printer.getHeight());
  headerLeft.setFont (headerFontName, headerFontSize);
  headerCenter.setFont (headerFontName, headerFontSize);
  headerRight.setFont (headerFontName, headerFontSize);
  int headerHeight = (int)headerCenter.lineHeight;

  int gap0 = 20; // Between top and header.
  int gap1 = 10; // between header and body
  int gap2 = 20; // between bottom and body end.

  body.setFont (bodyFontName, bodyFontSize);

  SLocation hl = SLocation (l.x, l.y + gap0);
  SDimension hd (d.width, headerHeight);
  
  /* we will move and resize them again later. now they are max wide.*/
  headerLeft.resize(hd); headerLeft.move (hl);
  headerLeft.setMultiline (false);
  headerCenter.resize(hd); headerCenter.move (hl);
  headerCenter.setMultiline (false);
  headerRight.resize(hd); headerRight.move (hl);
  headerRight.setMultiline (false);

  SLocation bl = SLocation (hl.x,  hl.y + (int) hd.height + gap1);
  int bodyHeight = (int) d.height-bl.y-gap2;
  if (bodyHeight < (int)body.lineHeight)
  {
    fprintf (stderr, "Too large font.\n");
    pageHeight = body.lineHeight;
  }
  else /* should be multiples of lineheight. */
  {
    pageHeight = body.lineHeight * (bodyHeight/body.lineHeight+1);
    
  }
  if (pageHeight<2) pageHeight=2;
  body.move (bl);
  // This -1 should be in sync with STextView.cpp. This is all because
  // we have an extra line if our sizes are exact.
  SDimension bd (d.width, pageHeight-1);
  body.resize (bd);
  body.setPrinterPageSize (pageHeight);
}

SUniPrint::~SUniPrint()
{
}

unsigned int
SUniPrint::getPageCount () const
{
  return pageCount;
}

/**
 * print.
 * @param header will be displayed on thee header
 * @param buffer will be the data to print
 * @param evt true = handle events
 */
bool
SUniPrint::print (const SString& header, const SString& buffer, bool evt)
{
  pageCount = 0;
  if (!printer.open(evt)) return false;

  SString dt = printer.getCreationDate ();
  //fprintf (stderr, "DATE=%*.*s\n", SSARGS(dt));
  headerLeft.setText(dt);
  body.setText (buffer);

  /* FIXME: break it into pages, and set the viewport */
  /* first print to cache. */

  /* cache the top line */
  SLocation l (body.getLocation().x, body.getLocation().y);
  SDimension d = body.getSize();

  if (!printer.beginImage (l.x, l.y,  "UPPERLINE", SColor("white")))
  {
    printer.newpath ();
    printer.moveto (l.x, l.y-9);
    printer.lineto (l.x + (int)d.width, l.y-9);
    printer.lineto (l.x + (int)d.width, l.y-8);
    printer.lineto (l.x, l.y-8 );
    printer.closepath ();
    printer.fill ();
  }
  printer.endImage ();

  SDimension ld = headerLeft.getPreferredSize ();
  headerLeft.resize (ld);

  /* left can be drawn already */
  if (printheader)
  {
    headerLeft.redraw (&printer,
      headerLeft.getLocation().x, headerLeft.getLocation().y, 
      headerLeft.getSize().width, headerLeft.getSize().height); 
  }

  unsigned int pmaMax = 1;

  /**
   * go through body and right 
   */
  unsigned int heightCount = 0;  
  while (heightCount <  body.getDocumentHeight())
  {
    printer.newPage();
    body.redraw (&printer, 
       body.getLocation().x, body.getLocation().y, 
       body.getSize().width, body.getSize().height); 

    pageCount++;

    char a[64];
    /* we are not much off using current page */
    snprintf (a, 64, "Page %u of %u", pageCount, pageCount);
    headerRight.setText (a);
    SDimension rd = headerRight.getPreferredSize ();
    headerRight.resize (rd);

    if (printheader)
    {
      headerRight.redraw (&printer, 
         headerRight.getLocation().x, headerRight.getLocation().y, 
         headerRight.getSize().width, headerRight.getSize().height); 
    }

    if (rd.width > pmaMax) pmaMax = rd.width;

    heightCount += pageHeight;
    body.setViewPort (SLocation (0, -(int) heightCount));

  }
  /* nove we have the maximum size of right header */
  headerRight.resize (SDimension 
        ((unsigned int) pmaMax, headerRight.getSize().height));

  /* now lets see how much is left for the center guy */
  int full = (int) body.getSize().width;


  int center = full - (int) pmaMax - (int)ld.width;
  if (center < 0) center = 1;
  
  if (printheader && header.size())
  {
    SString testBegin = "file:";
    SString testEnd = header;
    testBegin.append (testEnd);
    headerCenter.setText (testBegin);
    SDimension cd = headerCenter.getPreferredSize();
    /* reduce it */
   
    if ((int)cd.width > center)
    {
      testEnd.insert (0, "...");
    }
    /* remove glyphs till it fits. */
    while ((int)cd.width > center && testEnd.size()>3)
    {
      testEnd.remove (3);
      testBegin = "file:";
      testBegin.append (testEnd);
      headerCenter.setText (testBegin);
      cd = headerCenter.getPreferredSize();
    }
    headerCenter.resize (cd);
    /* poor man's centering */
//fprintf (stderr, "center=%u cd=%u\n", center, cd.width);
//fprintf (stderr, "full=%u pmamax=%u ldwidth=%u\n", full, pmaMax, ld.width);
    headerCenter.move (SLocation (
        body.getLocation().x + (int)ld.width 
         + ((int)center - (int)cd.width)/2,
         headerCenter.getLocation().y));

    if (printheader)
    {
      headerCenter.redraw (&printer, 
         headerCenter.getLocation().x, headerCenter.getLocation().y, 
         headerCenter.getSize().width, headerCenter.getSize().height); 
    }
  }

  /*-----  print  - really using cached images ------------ */
  printer.cacheOn (false);

  unsigned int fullPageCount = pageCount;
  pageCount = 0;
  body.setViewPort (SLocation (0, 0));
  heightCount = 0;  
  while (heightCount <  body.getDocumentHeight())
  {
    /* upper line */
    printer.newPage();
    if (printheader)
    {
      printer.beginImage (l.x, l.y,  "UPPERLINE", SColor("white"));
      printer.endImage();
    }

    /* body */
    body.redraw (&printer, 
       body.getLocation().x, body.getLocation().y, 
       body.getSize().width, body.getSize().height-1); 

    /* left */
    if (printheader)
    {
      headerLeft.redraw (&printer,
        headerLeft.getLocation().x, headerLeft.getLocation().y, 
        headerLeft.getSize().width, headerLeft.getSize().height); 
    }

    /* center */
    if (printheader && header.size())
    {
      headerCenter.redraw (&printer, 
        headerCenter.getLocation().x, headerCenter.getLocation().y, 
        headerCenter.getSize().width, headerCenter.getSize().height); 
    }
    /* right aligned header */
    pageCount++;
    char a[64];
    snprintf (a, 64, "Page %u of %u", pageCount, fullPageCount);
    headerRight.setText (a);
    SDimension rd = headerRight.getPreferredSize ();

//fprintf (stderr, "Right ps=%u %u\n", rd.width, rd.height);
    headerRight.move (
      SLocation 
      (
        full - (int)rd.width + body.getLocation().x,
        headerRight.getLocation().y
      )
    );
    headerRight.resize (SDimension (rd.width, rd.height));
    if (printheader)
    {
      headerRight.redraw (&printer, 
         headerRight.getLocation().x, headerRight.getLocation().y, 
         headerRight.getSize().width, headerRight.getSize().height); 
    }

    heightCount += pageHeight;
    body.setViewPort (SLocation (0, -(int) heightCount));
  }

  headerLeft.textData.clear();
  headerRight.textData.clear();
  headerCenter.textData.clear();
  body.textData.clear();
  //fprintf (stderr, "closing printer...\n");
  bool status =  printer.close();
  //fprintf (stderr, "closed printer...\n");
  return status;
}

void
SUniPrint::setLineEndMark (bool brk)
{
  body.setLineEndMark (brk);
}

void
SUniPrint::setWordWrap (bool brk)
{
  body.setWordWrap (brk);
}
void
SUniPrint::setDocumentEmbedding (SS_Embedding e)
{
  body.textData.setDocumentEmbedding (e);
}

bool
SUniPrint::hasNative () 
{
  return printer.hasNative();
} 

