
// ---------------------------------------------------------------------
// General declarations.
// ---------------------------------------------------------------------

#include <string>
#include <iostream>
#include <errno.h>
#include <error.h>
#include <argp.h>
#include <stdlib.h>
#include "def.h"
#include "Util/roman_numeral.h"
#include "Util/TeX_atom.h"
#include "Page_no/Page_number.h"
#include "TOC/Table.h"
#include "PDF/PDF.h"
#include "PDF/updator.h"

#define PROGNAME "complete-pdf"
#define DESC_ONE_LINE \
  "fix PDF page numbers and add a table of contents"
#define ARGP_ARGS_DOC "PDF PS TOC {TITLE}"
#define ARGP_DOC_TAIL \
  "The " PROGNAME "(1) command demands as arguments three filenames\n" \
  "plus an optional string:\n" \
  "\n" \
  "    PDF   - the name of the PDF file;\n" \
  "    PS    - the name of the PostScript file from which gs(1),\n" \
  "            ps2pdf(1) or the like made the PDF;\n" \
  "    TOC   - the name of the *.toc table-of-contents file LaTeX\n" \
  "            wrote while compiling the DVI to feed to gs(1);\n" \
  "    TITLE - optionally, a title to embed in the PDF in case\n" \
  "            none is embedded already.\n" \
  "\n" \
  "The command itself alters no file, but prints to stdout\n" \
  "text one can subsequently append to the PDF file to complete it.\n" \
  "Example: " PROGNAME " foo.pdf foo.ps bar.toc 'My Title' >pdf-addendum\n"

std::string filename_pdf = "";
std::string filename_ps  = "";
std::string filename_toc = "";
std::string title        = "";
int toc_page_prefatory = 0;
int toc_page_corporeal = 0;
int bib_page           = 0;
int index_page         = 0;

// ---------------------------------------------------------------------
// Definitions to parse the command line.
// ---------------------------------------------------------------------

// Prepare the elements argp will need to parse the command line.
const char *argp_program_version      = PROGNAME " " PROGVER;
const char *argp_program_bug_address  = "<" BUG_EMAIL ">";
const argp_option argp_option_array[] = {
  {
    "toc-page-pref", 'T', "NUM", 0,
    "the prefatory page number of the document's table of contents", 0
  },
  {
    "toc-page-main", 't', "NUM", 0,
    "the main-body page number of the document's table of contents", 0
  },
  {
    "bib-page", 'b', "NUM", 0,
    "the page number of the document's bibliography", 0
  },
  {
    "index-page", 'i', "NUM", 0,
    "the page number of the document's index", 0
  },
  { 0, 0, 0, 0, 0, 0 }
};
static error_t argp_parse_options(
  const int key, char *const arg, argp_state *const state
) {
  static int n_arg = 0;
  switch (key) {
    case 'T':
      toc_page_prefatory = atoi(arg);
    break;
    case 't':
      toc_page_corporeal = atoi(arg);
    break;
    case 'b':
      bib_page           = atoi(arg);
    break;
    case 'i':
      index_page         = atoi(arg);
    break;
    case ARGP_KEY_ARG:
      if      ( n_arg == 0 ) filename_pdf = arg;
      else if ( n_arg == 1 ) filename_ps  = arg;
      else if ( n_arg == 2 ) filename_toc = arg;
      else if ( n_arg == 3 ) title        = arg;
      else argp_error( state, "too many arguments" );
      ++n_arg;
    break;
    case ARGP_KEY_END:
      if ( n_arg < 3 ) argp_error( state, "too few arguments" );
    break;
    default: return ARGP_ERR_UNKNOWN;
  }
  return 0;
}

// Parse the command line.
void parse_cmd_line( const int argc, char **const argv ) {
  const argp argp1 = {
    argp_option_array,
    argp_parse_options,
    ARGP_ARGS_DOC,
    PROGNAME " -- " DESC_ONE_LINE "\v" ARGP_DOC_TAIL,
    0, 0, 0
  };
  if ( argp_parse( &argp1, argc, argv, 0, 0, 0 ) ) error(
    EINVAL, 0,
    "cannot parse the command line"
  );
}

// ---------------------------------------------------------------------
// The main program.
// ---------------------------------------------------------------------

int main( const int argc, char **const argv ) {

  parse_cmd_line( argc, argv );

  try {

    std::cout << PDF::updator(
      filename_pdf,
      filename_ps,
      filename_toc,
      title
    );

  }

  catch ( Util::TeX_atom::Exc_unbalanced ) {
    error(
      EPERM, 0,
      "found unbalanced braces in the TOC file"
    );
  }
  catch ( Util::Exc_roman_numeral ) {
    error(
      EPERM, 0,
      "failed to parse a Roman numeral"
    );
  }
  catch ( PDF::PDF::Exc_IO ) {
    error(
      EIO, 0,
      "could not open, read from or write to the PDF"
    );
  }
  catch ( PDF::PDF::Exc ) {
    error(
      EPERM, 0,
      "could not interpret the PDF"
    );
  }

  return 0;

}

