/** 
 *  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/SUniMap.h>
#include <stoolkit/SEncoder.h>
#include <stoolkit/SExcept.h>
#include <stoolkit/SString.h>
#include <stoolkit/SStringVector.h>
#include <stoolkit/SIO.h>
#include <stoolkit/SIOStream.h>
#include <stoolkit/SEncoder.h>
#include <stoolkit/SUtil.h>
#include <stoolkit/STypes.h>
#include <swindow/SFont.h>
#include <swindow/SFontImpl.h>
#include <swindow/SScriptProcessor.h>
#include <swindow/SPrinter.h>
#include <swidget/SUniPrint.h>
#include <stoolkit/SIO.h>

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

#define BUFFER_SIZE 512

static const char *version="uniprint version %s GNU(C) Gaspar Sinai\n";
static void usage (const SStringVector& fonts);

#define SS_UNIX 0
#define SS_DOS 1
#define SS_MAC 2

#define DEFAULT_HEADER 10.0
#define DEFAULT_BODY 12.0

/**
 * This is a printing utility to simply and nicely print out
 * utf-8 text files.
 * FIXME:
 * ./uniprint -size 12 -font cyberbit.ttf -out aa ../doc/UTF-8-test.txt  
 * will produce bad things.
 * @author: Gaspar Sinai <gaspar@yudit.org>
 * @version: 2000-07-08
 */
int
main (int argc, char *argv[])
{
  const char* ifile = 0;
  const char* ofile = 0;
  const char* printer = 0;
  const char* command = "lpr";
  const char* iencoding ="utf-8";
  SStringVector font;
  bool shownl = false;
  bool isleft = false;
  bool isright = false;
  bool wrap = false;
  double headerSize = DEFAULT_HEADER;
  double bodySize = DEFAULT_BODY;
  bool is_usage = false;
  
  SUniMap::guessPath();
  SFontImpl::guessPath();

  SPrinter::SMedia media = SPrinter::A4;
  SPrinter::SOrientation orient = SPrinter::PORTRAIT;

  int i;

  SInputStream is;
  SOutputStream os;

  for (i=1; i<argc; i++)
  {
    if (strcmp ("-decode", argv[i])==0 && i<argc-1)
    { 
      iencoding =  argv[i+1]; i++;
    }
    else if (strcmp ("-media", argv[i])==0 && i<argc-1)
    { 
      i++;
      if (strcmp ("A3", argv[i])==0) media = SPrinter::A3;
      else if (strcmp ("A4", argv[i])==0) media = SPrinter::A4;
      else if (strcmp ("A5", argv[i])==0) media = SPrinter::A5;
      else if (strcmp ("B4", argv[i])==0) media = SPrinter::B4;
      else if (strcmp ("B5", argv[i])==0) media = SPrinter::B5;
      else if (strcmp ("Executive", argv[i])==0) media = SPrinter::Executive;
      else if (strcmp ("Folio", argv[i])==0) media = SPrinter::Folio;
      else if (strcmp ("Ledger", argv[i])==0) media = SPrinter::Ledger;
      else if (strcmp ("Legal", argv[i])==0) media = SPrinter::Legal;
      else if (strcmp ("Letter", argv[i])==0) media = SPrinter::Letter;
      else if (strcmp ("Quarto", argv[i])==0) media = SPrinter::Quarto;
      else if (strcmp ("Statement", argv[i])==0) media = SPrinter::Statement;
      else if (strcmp ("Tabloid", argv[i])==0) media = SPrinter::Tabloid;
      else media = SPrinter::A4;
    }
    else if (strcmp ("-L", argv[i])==0)
    { 
      orient = SPrinter::LANDSCAPE;
    }
    else if (strcmp ("-landscape", argv[i])==0)
    { 
      orient = SPrinter::LANDSCAPE;
    }
    else if (strcmp ("-printer", argv[i])==0 && i<argc-1)
    { 
      printer =  argv[i+1]; i++;
    }
    else if (strcmp ("-font", argv[i])==0 && i<argc-1)
    { 
      font.append (argv[i+1]); i++;
    }
    else if (strcmp ("-break", argv[i])==0)
    { 
      shownl = true;
    }
    else if (strcmp ("-us", argv[i])==0)
    { 
      SScriptProcessor::support (true);
    }
    else if (strcmp ("-nus", argv[i])==0)
    { 
      SScriptProcessor::support (false);
    }
    else if (strcmp ("-left", argv[i])==0)
    { 
      isleft = true;
    }
    else if (strcmp ("-right", argv[i])==0)
    { 
      isright = true;
    }
    else if (strcmp ("-wrap", argv[i])==0)
    { 
      wrap = true;
    }
    else if (strcmp ("-hsize", argv[i])==0 && i<argc-1)
    { 
       i++;
       if (sscanf (argv[i], "%lf", &headerSize) == 0 
             || (headerSize <= 1.0&&headerSize!=0.0) || headerSize > 100.0)
       {
         fprintf (stderr, "header size out of range[1.0-100.0]: %s", argv[i]);
         return -1;
       }
       if (headerSize==0.0) headerSize = 1.0;
    }
    else if (strcmp ("-size", argv[i])==0 && i<argc-1)
    { 
       i++;
       if (sscanf (argv[i], "%lf", &bodySize) == 0 
             || bodySize < 1.0 || bodySize > 1000.0)
       {
         fprintf (stderr, "text size out of range[1.0-1000.0]: %s", argv[i]);
         return -1;
       }
    }
    else if (strcmp ("-out", argv[i])==0 && i<argc-1)
    { 
      ofile =  argv[i+1]; i++;
      if (ofile[0] == '-')
      {
        SPipe p;
        os = p.getOutputStream();
      }
      else
      {
        SFile f (ofile);
        os = f.getOutputStream();
      }
      if (!os.isOK())
      {
        fprintf (stderr, "uniprint: can not open '%s' to write.\n", ofile);
        return 1;
      }
    }
    else if (strcmp ("-in", argv[i])==0 && i<argc-1)
    { 
      ifile =  argv[i+1]; i++;
    }
    else if (argv[i][0] == '-')
    {
      is_usage = 1;
    }
    else 
    {
      if (i+1==argc)
      {
        ifile = argv[i];
        break;
      }
      is_usage = true;
      break;
    }
  }
  if (is_usage) 
  {
    usage (font);
    return 1;
  }

  /* Sub processing */

  /* STDIN */
  if (ifile == 0) ifile = "-";

  /* LPR */
  if (ofile == 0)
  {
    ofile = command;
    SString c (command);
    if (printer)
    {
      c.append (" -P ");
      c.append (printer);
    }
    fprintf (stderr, "opening command: %*.*s\n", SSARGS(c));
    SPipe p (c);
    os = p.getOutputStream();
    if (!os.isOK())
    {
      fprintf (stderr, "uniprint: can not open '%*.*s' to write.\n", SSARGS(c));
      return 1;
    }
  }
  
  SString ifileString;
  /* open input file */
  if (ifile[0] == '-')
  {
    SPipe p;
    is = p.getInputStream();
  }
  else
  {
    SFile f (ifile);
    is = f.getInputStream();
    ifileString = SString (ifile);
  }
  if (!is.isOK())
  {
     fprintf (stderr, "uniprint: can not open '%s' to read.\n", ifile);
     return 1;
  }

  SEncoder ic(iencoding);
  if (!ic.isOK())
  {
    fprintf (stderr, "uniprint: can not find converter '%s'\n", iencoding);
    return 1;
  }
  SReader reader(is);
  SWriter writer(os);
  SString s;
  reader.read (&s);

  SV_UCS4 res = ic.decode (s);
  SV_UCS4 header;

  SPrinter prnt(writer, (SPrinter::SType) 0, media,  orient);

  /**
   * FIXME: move this to yudit config.
   */
  SString fontSet("default");
  bool isFontSet = false;
  if (font.size() == 1 && font[0].find (".") < 0) {
    isFontSet = true;
    fontSet = font[0];
  }
  if (isFontSet || font.size() == 0)
  {
    SProperties p;
    if (fontSet == "default") 
    {
        p.put(fontSet, SFont::getDefaultFontList());
    }
    else
    {
        SString fs = ("yudit.font.");
        fs.append (fontSet);
        fontSet = fs;
        loadProperties(&p);
    }
    font.clear();
    if (p.get(fontSet))
    {
      SStringVector vf (p[fontSet]);
      for (unsigned int m=0; m<vf.size(); m++)
      {
        SString f = vf[m];
        font.append (f);
      }
    }
    if (font.size() ==0)
    {
      fprintf (stderr, "FontSet %*.*s not found. Adding: yudit.ttf,OldHungarian_Full.ttf\n", SSARGS(fontSet));
      font.append ("yudit.ttf");
      font.append ("OldHungarian_Full.ttf");
    }
  }
  SFontImplVector himpl;
  SFontImplVector dimpl;
  for (unsigned int h=0; h<font.size(); h++)
  {
    SString fntfull = font[h];
    SStringVector v(fntfull, ":", false);
    SString fnt = v[0];
    SString enc = "";
    if (v.size()>1 && v[1].size()!=0) enc = v[1];
    SFontImpl impl (fnt, enc);  
    if (v.size()>2 && v[2].size()>0)
    {
         SStringVector pvect(v[2], ";");
         SProperties props;
         for (unsigned int j=0; j<pvect.size(); j++)
         {
            SStringVector vv(pvect[j], "=", true);
            if (vv.size() > 1)
            {  
               props.put (vv[0], vv[1]);
            }
            else
            {
               props.put (vv[0], "true");
            }
         }
         impl.setAttributes(props);
    }
    himpl.append (impl);
    dimpl.append (impl);
  }
  SFont::put ("Header", himpl);
  SFont::put ("Document", dimpl);

  SUniPrint uniPrint(prnt, "Header", headerSize, "Document", bodySize);

  SEncoder utf8;

  uniPrint.setLineEndMark(shownl);
  if (isright) uniPrint.setDocumentEmbedding (SS_EmbedRight);
  if (isleft) uniPrint.setDocumentEmbedding (SS_EmbedLeft);
  uniPrint.setLineEndMark(shownl);
  uniPrint.setWordWrap(wrap);

  if (!uniPrint.print (ifileString, utf8.encode (res)))
  {
    fprintf (stderr, "uniprint: can not print.\n");
    return 1;
  }
  int pagecount = uniPrint.getPageCount();
  if (pagecount > 1)
  {
    fprintf (stderr, "uniprint: printed %d pages.\n", pagecount);
  }
  else
  {
    fprintf (stderr, "uniprint: printed %d page.\n", pagecount);
  }
  return 0;
}

static void
usage (const SStringVector& font)
{
  SStringVector l = SFontImpl::getPath();
  SString pathStr = l.join (",");
  SString fontList = font.join (",");

  SString fontSet = "indivifual fonts";
  if (font.size() == 0 || (font.size() == 1 && font[0] == "default")) {
     fontList = SFont::getDefaultFontList();
     fontSet = "yudit 'default' font-set";  
  }
  if (font.size() == 1 && font[0].find (".") < 0) 
  {
       fontSet = "yudit font-set '";
       fontSet.append(font[0]);
       fontSet.append("'");
       SString fs = ("yudit.font.");
       fs.append (font[0]);
       SProperties p;
       loadProperties(&p);
       if (p.get(fs)) {
           fontList = p[fs];
       } else {
           fontList.append (" - not defined in yudit.properties");
        }
   }
   fprintf (stdout, version, SD_YUDIT_VERSION);
   fprintf (stdout,   "usage: uniprint [-out file] [-printer name] [-in file] [-decode name] \n");
   fprintf (stdout,   "[-media A4] [-break] [-right|-left] [-hsize header-font-size] [-size font-size]\n");
   fprintf (stdout,   "[-L|-landscape] [-wrap] [-font truetype.ttf | YuditFontSet]] \n\n");
   fprintf (stdout,   "uniprint [-us] using uniscribe-clone rendering (default).\n");
   fprintf (stdout,   "uniprint [-nus] not using uniscribe-clone rendering.\n");
   fprintf (stdout,   "Only one Yudit font set or multiple fonts can be spacified.\n\n");
   fprintf (stdout,   "%*.*s:\n%*.*s\n\n", SSARGS(fontSet), SSARGS(fontList));

   SStringVector fonts(fontList, ",");
   SStringVector path(pathStr, ",");
   unsigned int count = 0;
   for (unsigned int i=0; i<fonts.size(); i++) 
   {
      SString fntfull = fonts[i];
      SStringVector v(fntfull, ":", false);
      SString fnt = v[0];
      SFile file(fnt, path);
      if (file.size() > 0)
      {
        SString fname = file.getName();
        if (fname.find(" ") >= 0) 
        {
           fname = SString ("'"); 
           fname.append (file.getName());
           fname.append ("'");
        }
        fprintf (stdout,   "%*.*s: %*.*s\n", SSARGS(fnt), SSARGS(fname));
        count++;
      }
   }
   fprintf (stderr, "%d font file(s) found out of %d.\n", count, fonts.size());
   fprintf (stdout,   "fontpath settings:\n%*.*s\n", SSARGS(pathStr)); 
      
}

