
#ifndef PDF_PDF_H
#define PDF_PDF_H

#include <string>
#include "Iref.h"
#include "../Page_no/PS_page_numbering.h"

// ---------------------------------------------------------------------
// To interpret a PDF, through an interface narrower
// and more conventional than LibPoppler's.
// ---------------------------------------------------------------------

// Caution:  One should view code which calls PDF::PDF::get_PDFDoc_ptr()
// with suspicion.  The function is a hack necessary for some purposes
// which, when used, unfortunately violates encapsulation.

// Some notes on this module:
//
// 1.  Various of the comments in this file, in the corresponding *.cc
// and maybe elsewhere would seem to suggest that Libpoppler were
// somehow deficient.  On the contrary, this programmer appreciates the
// availability of Libpoppler and is very glad that it frees him from
// the need independently to implement its relevant functionality!  Of
// course Libpoppler could be improved significantly with commensurate
// programming effort (by someone), as could most code including the
// code you are now reading, but this is not the point.  The only point
// is that the present code is written in view of the admittedly archaic
// interface Libpoppler happens to provide.  The purpose of the comments
// is not to critize Libpoppler (as if anyone seeking criticism of
// Libpoppler would look for it here) but rather solely to explain why
// the present code, which uses Libpoppler, does certain things in a way
// less than obvious to a typical modern C++ programmer.
//
// 2.  In many established modules, one tends to avoid adding new
// symbols unnecessarily, but users of this module should expect new
// symbols to be added at any time.  This is because the module's
// purpose is less to provide its users a thin, stable interface than to
// remove one step from them Libpoppler's interface.
//
//

namespace PDF {
  struct PDF_rep;
  class  PDF;
  int  file_length           ( const PDF &pdf );
  int  offset_last_xref_table( const std::string &pdf_filename );
  Iref iref_catalog          ( const PDF &pdf );
  Iref iref_info             ( const PDF &pdf );
  int  n_obj                 ( const PDF &pdf );
  int  offset                ( const PDF &pdf, int i );
  int  n_page                ( const PDF &pdf );
  int  i_page(
    const PDF &pdf,
    Iref iref,
    bool do_not_throw = false
  );
  Iref iref_page             ( const PDF &pdf, int i );
}

class PDF::PDF {
  private:
    PDF_rep *rep;
  public:
    // The exception classes are imprecise.  Basically, Exc_IO() is
    // thrown when the problem seems likely to have involved failure to
    // read a file, whereas Exc_PDF() is thrown when the PDF file is
    // found but seems to be corrupted.  Given the way Libpoppler is
    // defined, it would take too much programming effort to be more
    // precise, but if one does not like the exception categories given
    // then one can always default to catching Exc().
    struct Exc {};
    struct Exc_IO  : public Exc {};
    struct Exc_PDF : public Exc {};
    explicit PDF( const std::string &filename );
    ~PDF();
    friend int  file_length           ( const PDF &pdf );
    friend int  offset_last_xref_table( const std::string &pdf_filename );
    friend Iref iref_catalog          ( const PDF &pdf );
    friend Iref iref_info             ( const PDF &pdf );
    friend int  n_obj                 ( const PDF &pdf );
    friend int  offset                ( const PDF &pdf, int i );
    friend int  n_page                ( const PDF &pdf );
    friend int  i_page(
      const PDF &pdf,
      Iref iref,
      bool do_not_throw
    );
    friend Iref iref_page             ( const PDF &pdf, int i );
    // The get_PDFDoc_ptr() member function is a necessary hack.  Its
    // intended user is code which calls Libpoppler to manipulate
    // Libpoppler's representation of a PDF object to dump the object to
    // a string.  Libpoppler's peculiar presentation unfortunately
    // renders obvious alternatives impractical or unacceptable.  To
    // discourage casual or accidental use, the function demands a magic
    // integer, the correct value of which you can find hardwired into
    // the PDF.cc code.
    PDF_rep *get_PDF_rep( int magic );
};

#endif

