//========================================================================
//
// Annot.h
//
// Copyright 2000-2003 Glyph & Cog, LLC
//
//========================================================================

//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
// Copyright (C) 2007, 2008 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2007-2011, 2013, 2015, 2018 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2007, 2008 Iñigo Martínez <inigomartinez@gmail.com>
// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
// Copyright (C) 2008 Pino Toscano <pino@kde.org>
// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
// Copyright (C) 2009-2011, 2013, 2016-2019 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright (C) 2012, 2015 Tobias Koenig <tokoe@kdab.com>
// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
// Copyright (C) 2018 Dileep Sankhla <sankhla.dileep96@gmail.com>
// Copyright (C) 2018, 2019 Tobias Deiminger <haxtibal@posteo.de>
// Copyright (C) 2018, 2020 Oliver Sander <oliver.sander@tu-dresden.de>
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
// Copyright (C) 2019 Umang Malik <umang99m@gmail.com>
// Copyright (C) 2019 João Netto <joaonetto901@gmail.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

#ifndef ANNOT_H
#define ANNOT_H

#include <memory>
#include <atomic>
#include <mutex>
#include <vector>

#include "Object.h"

class XRef;
class Gfx;
class CharCodeToUnicode;
class GfxFont;
class GfxResources;
class Page;
class PDFDoc;
class Form;
class FormWidget;
class FormField;
class FormFieldButton;
class FormFieldText;
class FormFieldChoice;
class PDFRectangle;
class Movie;
class LinkAction;
class Sound;
class FileSpec;

enum AnnotLineEndingStyle {
  annotLineEndingSquare,        // Square
  annotLineEndingCircle,        // Circle
  annotLineEndingDiamond,       // Diamond
  annotLineEndingOpenArrow,     // OpenArrow
  annotLineEndingClosedArrow,   // ClosedArrow
  annotLineEndingNone,          // None
  annotLineEndingButt,          // Butt
  annotLineEndingROpenArrow,    // ROpenArrow
  annotLineEndingRClosedArrow,  // RClosedArrow
  annotLineEndingSlash          // Slash
};

enum AnnotExternalDataType {
  annotExternalDataMarkupUnknown,
  annotExternalDataMarkup3D       // Markup3D
};

//------------------------------------------------------------------------
// AnnotCoord
//------------------------------------------------------------------------

class AnnotCoord {
public:

  AnnotCoord() : x(0), y(0) { }
  AnnotCoord(double _x, double _y) : x(_x), y(_y) { }

  double getX() const { return x; }
  double getY() const { return y; }

protected:

  double x, y;
};

//------------------------------------------------------------------------
// AnnotPath
//------------------------------------------------------------------------

class AnnotPath {
public:
  AnnotPath();
  AnnotPath(Array *array);
  AnnotPath(std::vector<AnnotCoord> &&coords);
  ~AnnotPath();

  AnnotPath(const AnnotPath &) = delete;
  AnnotPath& operator=(const AnnotPath &other) = delete;

  double getX(int coord) const;
  double getY(int coord) const;
  AnnotCoord *getCoord(int coord);
  int getCoordsLength() const { return coords.size(); }
protected:
  std::vector<AnnotCoord> coords;

  void parsePathArray(Array *array);
};
  
//------------------------------------------------------------------------
// AnnotCalloutLine
//------------------------------------------------------------------------

class AnnotCalloutLine {
public:

  AnnotCalloutLine(double x1, double y1, double x2, double y2);
  virtual ~AnnotCalloutLine() { }

  AnnotCalloutLine(const AnnotCalloutLine &) = delete;
  AnnotCalloutLine& operator=(const AnnotCalloutLine &other) = delete;

  double getX1() const { return coord1.getX(); }
  double getY1() const { return coord1.getY(); }
  double getX2() const { return coord2.getX(); }
  double getY2() const { return coord2.getY(); }
  
protected:

  AnnotCoord coord1, coord2;
};

//------------------------------------------------------------------------
// AnnotCalloutMultiLine
//------------------------------------------------------------------------

class AnnotCalloutMultiLine: public AnnotCalloutLine {
public:

  AnnotCalloutMultiLine(double x1, double y1, double x2, double y2,
    double x3, double y3);

  double getX3() const { return coord3.getX(); }
  double getY3() const { return coord3.getY(); }

protected:

  AnnotCoord coord3;
};

//------------------------------------------------------------------------
// AnnotBorderEffect
//------------------------------------------------------------------------

class AnnotBorderEffect {
public:

  enum AnnotBorderEffectType {
    borderEffectNoEffect, // S
    borderEffectCloudy    // C
  };

  AnnotBorderEffect(Dict *dict);

  AnnotBorderEffectType getEffectType() const { return effectType; }
  double getIntensity() const { return intensity; }

private:

  AnnotBorderEffectType effectType; // S  (Default S)
  double intensity;                 // I  (Default 0)
};

//------------------------------------------------------------------------
// AnnotQuadrilateral
//------------------------------------------------------------------------

class AnnotQuadrilaterals {
public:
  class AnnotQuadrilateral {
  public:
    AnnotQuadrilateral();
    AnnotQuadrilateral(double x1, double y1, double x2, double y2, double x3,
      double y3, double x4, double y4);

    AnnotCoord coord1, coord2, coord3, coord4;
  };

  AnnotQuadrilaterals(Array *array, PDFRectangle *rect);
  AnnotQuadrilaterals(std::unique_ptr<AnnotQuadrilateral[]> &&quads, int quadsLength);
  ~AnnotQuadrilaterals();

  AnnotQuadrilaterals(const AnnotQuadrilaterals &) = delete;
  AnnotQuadrilaterals& operator=(const AnnotQuadrilaterals &other) = delete;

  double getX1(int quadrilateral);
  double getY1(int quadrilateral);
  double getX2(int quadrilateral);
  double getY2(int quadrilateral);
  double getX3(int quadrilateral);
  double getY3(int quadrilateral);
  double getX4(int quadrilateral);
  double getY4(int quadrilateral);
  int getQuadrilateralsLength() const { return quadrilateralsLength; }
protected:

  std::unique_ptr<AnnotQuadrilateral[]> quadrilaterals;
  int quadrilateralsLength;
};

//------------------------------------------------------------------------
// AnnotBorder
//------------------------------------------------------------------------

class AnnotBorder {
public:
  enum AnnotBorderType {
    typeArray,
    typeBS
  };

  enum AnnotBorderStyle {
    borderSolid,      // Solid
    borderDashed,     // Dashed
    borderBeveled,    // Beveled
    borderInset,      // Inset
    borderUnderlined  // Underlined
  };

  virtual ~AnnotBorder();

  AnnotBorder(const AnnotBorder &) = delete;
  AnnotBorder& operator=(const AnnotBorder &other) = delete;

  virtual void setWidth(double new_width) { width = new_width; }

  virtual AnnotBorderType getType() const = 0;
  virtual double getWidth() const { return width; }
  virtual int getDashLength() const { return dashLength; }
  virtual double *getDash() const { return dash; }
  virtual AnnotBorderStyle getStyle() const { return style; }

  virtual Object writeToObject(XRef *xref) const = 0;

protected:
  AnnotBorder();

  bool parseDashArray(Object *dashObj);

  AnnotBorderType type;
  double width;
  static const int DASH_LIMIT = 10; // implementation note 82 in Appendix H.
  int dashLength;
  double *dash;
  AnnotBorderStyle style;
};

//------------------------------------------------------------------------
// AnnotBorderArray
//------------------------------------------------------------------------

class AnnotBorderArray: public AnnotBorder {
public:
  AnnotBorderArray();
  AnnotBorderArray(Array *array);

  void setHorizontalCorner(double hc) { horizontalCorner = hc; }
  void setVerticalCorner(double vc) { verticalCorner = vc; }

  double getHorizontalCorner() const { return horizontalCorner; }
  double getVerticalCorner() const { return verticalCorner; }

private:
  AnnotBorderType getType() const override { return typeArray; }
  Object writeToObject(XRef *xref) const override;

  double horizontalCorner;          // (Default 0)
  double verticalCorner;            // (Default 0)
  // double width;                  // (Default 1)  (inherited from AnnotBorder)
};

//------------------------------------------------------------------------
// AnnotBorderBS
//------------------------------------------------------------------------

class AnnotBorderBS: public AnnotBorder {
public:

  AnnotBorderBS();
  AnnotBorderBS(Dict *dict);

private:
  AnnotBorderType getType() const override { return typeBS; }
  Object writeToObject(XRef *xref) const override;

  const char *getStyleName() const;

  // double width;           // W  (Default 1)   (inherited from AnnotBorder)
  // AnnotBorderStyle style; // S  (Default S)   (inherited from AnnotBorder)
  // double *dash;           // D  (Default [3]) (inherited from AnnotBorder)
};

//------------------------------------------------------------------------
// AnnotColor
//------------------------------------------------------------------------

class AnnotColor {
public:

  enum AnnotColorSpace {
    colorTransparent = 0,
    colorGray        = 1,
    colorRGB         = 3,
    colorCMYK        = 4
  };

  AnnotColor();
  AnnotColor(double gray);
  AnnotColor(double r, double g, double b);
  AnnotColor(double c, double m, double y, double k);
  AnnotColor(Array *array, int adjust = 0);

  void adjustColor(int adjust);

  AnnotColorSpace getSpace() const { return (AnnotColorSpace) length; }
  const double *getValues() const { return values; }

  Object writeToObject(XRef *xref) const;

private:

  double values[4];
  int length;
};

//------------------------------------------------------------------------
// DefaultAppearance
//------------------------------------------------------------------------

class DefaultAppearance {
public:

  DefaultAppearance(Object &&fontNameA, double fontPtSizeA, std::unique_ptr<AnnotColor> fontColorA);
  DefaultAppearance(GooString *da);
  void setFontName(Object &&fontNameA);
  const Object &getFontName() const { return fontName; }
  void setFontPtSize(double fontPtSizeA);
  double getFontPtSize() const { return fontPtSize; }
  void setFontColor(std::unique_ptr<AnnotColor> fontColorA);
  const AnnotColor *getFontColor() const { return fontColor.get(); }
  GooString *toAppearanceString() const;

  DefaultAppearance(const DefaultAppearance &) = delete;
  DefaultAppearance& operator=(const DefaultAppearance&) = delete;

private:

  Object fontName;
  double fontPtSize;
  std::unique_ptr<AnnotColor> fontColor;
};

//------------------------------------------------------------------------
// AnnotIconFit
//------------------------------------------------------------------------

class AnnotIconFit {
public:

  enum AnnotIconFitScaleWhen {
    scaleAlways,  // A
    scaleBigger,  // B
    scaleSmaller, // S
    scaleNever    // N
  };

  enum AnnotIconFitScale {
    scaleAnamorphic,  // A
    scaleProportional // P
  };

  AnnotIconFit(Dict *dict);

  AnnotIconFitScaleWhen getScaleWhen() { return scaleWhen; }
  AnnotIconFitScale getScale() { return scale; }
  double getLeft() { return left; }
  double getBottom() { return bottom; }
  bool getFullyBounds() { return fullyBounds; }

protected:

  AnnotIconFitScaleWhen scaleWhen;  // SW (Default A)
  AnnotIconFitScale scale;          // S  (Default P)
  double left;                      // A  (Default [0.5 0.5]
  double bottom;                    // Only if scale is P
  bool fullyBounds;                 // FB (Default false)
};

//------------------------------------------------------------------------
// AnnotAppearance
//------------------------------------------------------------------------

class AnnotAppearance {
public:

  enum AnnotAppearanceType {
    appearNormal,
    appearRollover,
    appearDown
  };

  AnnotAppearance(PDFDoc *docA, Object *dict);
  ~AnnotAppearance();

  // State is ignored if no subdictionary is present
  Object getAppearanceStream(AnnotAppearanceType type, const char *state);

  // Access keys in normal appearance subdictionary (N)
  std::unique_ptr<GooString> getStateKey(int i);
  int getNumStates();

  // Removes all associated streams in the xref table. Caller is required to
  // reset parent annotation's AP and AS after this call.
  void removeAllStreams();

  // Test if this AnnotAppearance references the specified stream
  bool referencesStream(Ref refToStream);

private:
  static bool referencesStream(const Object *stateObj, Ref refToStream);
  void removeStream(Ref refToStream);
  void removeStateStreams(const Object *state);

protected:
  PDFDoc *doc;
  Object appearDict;            // Annotation's AP
};

//------------------------------------------------------------------------
// AnnotAppearanceCharacs
//------------------------------------------------------------------------

class AnnotAppearanceCharacs {
public:

  enum AnnotAppearanceCharacsTextPos {
    captionNoIcon,    // 0
    captionNoCaption, // 1
    captionBelow,     // 2
    captionAbove,     // 3
    captionRight,     // 4
    captionLeft,      // 5
    captionOverlaid   // 6
  };

  AnnotAppearanceCharacs(Dict *dict);
  ~AnnotAppearanceCharacs();

  AnnotAppearanceCharacs(const AnnotAppearanceCharacs &) = delete;
  AnnotAppearanceCharacs& operator=(const AnnotAppearanceCharacs &) = delete;

  int getRotation() const { return rotation; }
  const AnnotColor *getBorderColor() const { return borderColor.get(); }
  const AnnotColor *getBackColor() const { return backColor.get(); }
  const GooString *getNormalCaption() const { return normalCaption.get(); }
  const GooString *getRolloverCaption() { return rolloverCaption.get(); }
  const GooString *getAlternateCaption() { return alternateCaption.get(); }
  const AnnotIconFit *getIconFit() { return iconFit.get(); }
  AnnotAppearanceCharacsTextPos getPosition() const { return position; }

protected:

  int rotation;                                // R  (Default 0)
  std::unique_ptr<AnnotColor> borderColor;     // BC
  std::unique_ptr<AnnotColor> backColor;       // BG
  std::unique_ptr<GooString> normalCaption;    // CA
  std::unique_ptr<GooString> rolloverCaption;  // RC
  std::unique_ptr<GooString> alternateCaption; // AC
  // I
  // RI
  // IX
  std::unique_ptr<AnnotIconFit> iconFit;       // IF
  AnnotAppearanceCharacsTextPos position;      // TP (Default 0)
};

//------------------------------------------------------------------------
// AnnotAppearanceBBox
//------------------------------------------------------------------------

class AnnotAppearanceBBox
{
public:
  AnnotAppearanceBBox(PDFRectangle *rect);

  void setBorderWidth(double w) { borderWidth = w; }

  // The following functions operate on coords relative to [origX origY]
  void extendTo(double x, double y);
  void getBBoxRect(double bbox[4]) const;

  // Get boundaries in page coordinates
  double getPageXMin() const;
  double getPageYMin() const;
  double getPageXMax() const;
  double getPageYMax() const;

private:
  double origX, origY, borderWidth;
  double minX, minY, maxX, maxY;
};

//------------------------------------------------------------------------
// AnnotAppearanceBuilder
//------------------------------------------------------------------------
class Matrix;
class AnnotAppearanceBuilder {
public:
  AnnotAppearanceBuilder();
  ~AnnotAppearanceBuilder();

  AnnotAppearanceBuilder(const AnnotAppearanceBuilder &) = delete;
  AnnotAppearanceBuilder& operator=(const AnnotAppearanceBuilder &) = delete;

  void setDrawColor(const AnnotColor *color, bool fill);
  void setLineStyleForBorder(const AnnotBorder *border);
  void setTextFont(const Object &fontName, double fontSize);
  void drawCircle(double cx, double cy, double r, bool fill);
  void drawCircleTopLeft(double cx, double cy, double r);
  void drawCircleBottomRight(double cx, double cy, double r);
  void drawLineEnding(AnnotLineEndingStyle endingStyle, double x, double y, double size, bool fill, const Matrix& m);
  void drawLineEndSquare(double x, double y, double size, bool fill, const Matrix& m);
  void drawLineEndCircle(double x, double y, double size, bool fill, const Matrix& m);
  void drawLineEndDiamond(double x, double y, double size, bool fill, const Matrix& m);
  void drawLineEndArrow(double x, double y, double size, int orientation, bool isOpen, bool fill, const Matrix& m);
  void drawLineEndSlash(double x, double y, double size, const Matrix& m);
  void drawFieldBorder(const FormField *field, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect);
  bool drawFormField(const FormField *field, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, const GooString *appearState, XRef *xref, bool *addedDingbatsResource);
  static double lineEndingXShorten(AnnotLineEndingStyle endingStyle, double size);
  static double lineEndingXExtendBBox(AnnotLineEndingStyle endingStyle, double size);
  void writeString(const GooString &str);

  void append(const char *text);
  void appendf(const char *fmt, ...) GOOSTRING_FORMAT;

  const GooString *buffer() const;

private:
  bool drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, const PDFRectangle *rect,
		   const GooString *da, const GfxResources *resources, int quadding);
  bool drawFormFieldButton(const FormFieldButton *field, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, const GooString *appearState, XRef *xref, bool *addedDingbatsResource);
  bool drawFormFieldText(const FormFieldText *fieldText, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect);
  bool drawFormFieldChoice(const FormFieldChoice *fieldChoice, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect);
  bool drawText(const GooString *text, const GooString *da, const GfxResources *resources,
		const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
		bool multiline, int comb, int quadding,
		bool txField, bool forceZapfDingbats,
		XRef *xref, bool *addedDingbatsResource, // xref and addedDingbatsResource both must not be null if forceZapfDingbats is passed
		bool password);
  void drawArrowPath(double x, double y, const Matrix& m, int orientation=1);

  GooString *appearBuf;
};

//------------------------------------------------------------------------
// Annot
//------------------------------------------------------------------------

class Annot {
  friend class Annots;
  friend class Page;
public:
  enum AnnotFlag {
    flagUnknown        = 0x0000,
    flagInvisible      = 0x0001,
    flagHidden         = 0x0002,
    flagPrint          = 0x0004,
    flagNoZoom         = 0x0008,
    flagNoRotate       = 0x0010,
    flagNoView         = 0x0020,
    flagReadOnly       = 0x0040,
    flagLocked         = 0x0080,
    flagToggleNoView   = 0x0100,
    flagLockedContents = 0x0200
  };

  enum AnnotSubtype {
    typeUnknown,        //                 0
    typeText,           // Text            1
    typeLink,           // Link            2
    typeFreeText,       // FreeText        3
    typeLine,           // Line            4
    typeSquare,         // Square          5
    typeCircle,         // Circle          6
    typePolygon,        // Polygon         7
    typePolyLine,       // PolyLine        8
    typeHighlight,      // Highlight       9
    typeUnderline,      // Underline      10
    typeSquiggly,       // Squiggly       11
    typeStrikeOut,      // StrikeOut      12
    typeStamp,          // Stamp          13
    typeCaret,          // Caret          14
    typeInk,            // Ink            15
    typePopup,          // Popup          16
    typeFileAttachment, // FileAttachment 17
    typeSound,          // Sound          18
    typeMovie,          // Movie          19
    typeWidget,         // Widget         20
    typeScreen,         // Screen         21
    typePrinterMark,    // PrinterMark    22
    typeTrapNet,        // TrapNet        23
    typeWatermark,      // Watermark      24
    type3D,             // 3D             25
    typeRichMedia       // RichMedia      26
  };

  /**
   * Describes the additional actions of a screen or widget annotation.
   */
  enum AdditionalActionsType {
    actionCursorEntering, ///< Performed when the cursor enters the annotation's active area
    actionCursorLeaving,  ///< Performed when the cursor exists the annotation's active area
    actionMousePressed,   ///< Performed when the mouse button is pressed inside the annotation's active area
    actionMouseReleased,  ///< Performed when the mouse button is released inside the annotation's active area
    actionFocusIn,        ///< Performed when the annotation receives the input focus
    actionFocusOut,       ///< Performed when the annotation loses the input focus
    actionPageOpening,    ///< Performed when the page containing the annotation is opened
    actionPageClosing,    ///< Performed when the page containing the annotation is closed
    actionPageVisible,    ///< Performed when the page containing the annotation becomes visible
    actionPageInvisible   ///< Performed when the page containing the annotation becomes invisible
  };

  enum FormAdditionalActionsType {
    actionFieldModified,   ///< Performed when the when the user modifies the field
    actionFormatField,     ///< Performed before the field is formatted to display its value
    actionValidateField,   ///< Performed when the field value changes
    actionCalculateField,  ///< Performed when the field needs to be recalculated
  };

  Annot(PDFDoc *docA, PDFRectangle *rectA);
  Annot(PDFDoc *docA, Object &&dictObject);
  Annot(PDFDoc *docA, Object &&dictObject, const Object *obj);
  bool isOk() { return ok; }

  void incRefCnt();
  void decRefCnt();

  virtual void draw(Gfx *gfx, bool printing);
  // Get the resource dict of the appearance stream
  virtual Object getAppearanceResDict();

  bool match(const Ref *refA) const
    { return ref == *refA; }

  double getXMin();
  double getYMin();
  double getXMax();
  double getYMax();

  void setRect(PDFRectangle *rect);
  void setRect(double x1, double y1, double x2, double y2);

  // Sets the annot contents to new_content
  // new_content should never be NULL
  virtual void setContents(GooString *new_content);
  void setName(GooString *new_name);
  void setModified(GooString *new_modified);
  void setFlags(unsigned int new_flags);

  void setBorder(std::unique_ptr<AnnotBorder> &&new_border);
  void setColor(std::unique_ptr<AnnotColor> &&new_color);

  void setAppearanceState(const char *state);

  // getters
  PDFDoc *getDoc() const { return doc; }
  bool getHasRef() const { return hasRef; }
  Ref getRef() const { return ref; }
  AnnotSubtype getType() const { return type; }
  PDFRectangle *getRect() const { return rect.get(); }
  void getRect(double *x1, double *y1, double *x2, double *y2) const;
  const GooString *getContents() const { return contents.get(); }
  int getPageNum() const { return page; }
  const GooString *getName() const { return name.get(); }
  const GooString *getModified() const { return modified.get(); }
  unsigned int getFlags() const { return flags; }
  AnnotAppearance *getAppearStreams() const { return appearStreams.get(); }
  const GooString *getAppearState() const { return appearState.get(); }
  AnnotBorder *getBorder() const { return border.get(); }
  AnnotColor *getColor() const { return color.get(); }
  int getTreeKey() const { return treeKey; }

  int getId() { return ref.num; }

  // Check if point is inside the annot rectangle.
  bool inRect(double x, double y) const;

  static void layoutText(const GooString *text, GooString *outBuf, int *i, const GfxFont *font,
		  double *width, double widthLimit, int *charCount,
		  bool noReencode);

private:
  void readArrayNum(Object *pdfArray, int key, double *value);
  // write vStr[i:j[ in appearBuf

  void initialize (PDFDoc *docA, Dict *dict);
  void setPage (int pageIndex, bool updateP); // Called by Page::addAnnot and Annots ctor


protected:
  virtual ~Annot();
  virtual void removeReferencedObjects(); // Called by Page::removeAnnot
  Object createForm(const GooString *appearBuf, double *bbox, bool transparencyGroup, Dict *resDict);
  Object createForm(const GooString *appearBuf, double *bbox, bool transparencyGroup, Object &&resDictObject); // overload to support incRef/decRef
  Dict *createResourcesDict(const char *formName, Object &&formStream, const char *stateName,
			   double opacity, const char *blendMode);
  bool isVisible(bool printing);
  int getRotation() const;

  // Updates the field key of the annotation dictionary
  // and sets M to the current time
  void update(const char *key, Object &&value);

  // Delete appearance streams and reset appearance state
  void invalidateAppearance();

  Object annotObj;

  std::atomic_int refCnt;

  // required data
  AnnotSubtype type;                                // Annotation type
  std::unique_ptr<PDFRectangle> rect;               // Rect

  // optional data
  std::unique_ptr<GooString> contents;              // Contents
  std::unique_ptr<GooString> name;                  // NM
  std::unique_ptr<GooString> modified;              // M
  int       page;                                   // P
  unsigned int flags;                                      // F (must be a 32 bit unsigned int)
  std::unique_ptr<AnnotAppearance> appearStreams;   // AP
  Object appearance;                                // a reference to the Form XObject stream
                                                    //   for the normal appearance
  std::unique_ptr<AnnotAppearanceBBox> appearBBox;  // BBox of generated appearance
  std::unique_ptr<GooString> appearState;           // AS
  int treeKey;                                      // Struct Parent;
  Object oc;                                        // OC

  PDFDoc *doc;
  Ref ref;                      // object ref identifying this annotation
  std::unique_ptr<AnnotBorder> border;              // Border, BS
  std::unique_ptr<AnnotColor> color;                // C
  bool ok;

  bool hasRef;
  mutable std::recursive_mutex mutex;
};

//------------------------------------------------------------------------
// AnnotPopup
//------------------------------------------------------------------------

class AnnotPopup: public Annot {
public:
  AnnotPopup(PDFDoc *docA, PDFRectangle *rect);
  AnnotPopup(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotPopup() override;

  bool hasParent() const { return parentRef != Ref::INVALID(); }
  void setParent(Annot *parentA);
  bool getOpen() const { return open; }
  void setOpen(bool openA);

protected:
  void initialize(PDFDoc *docA, Dict *dict);

  Ref parentRef; // Parent
  bool open;   // Open
};

//------------------------------------------------------------------------
// AnnotMarkup
//------------------------------------------------------------------------

class AnnotMarkup: public Annot {
public:
  enum  AnnotMarkupReplyType {
    replyTypeR,     // R
    replyTypeGroup  // Group
  };

  AnnotMarkup(PDFDoc *docA, PDFRectangle *rect);
  AnnotMarkup(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotMarkup() override;

  // getters
  const GooString *getLabel() const { return label.get(); }
  AnnotPopup *getPopup() const { return popup.get(); }
  double getOpacity() const { return opacity; }
  // getRC
  const GooString *getDate() const { return date.get(); }
  bool isInReplyTo() const { return inReplyTo != Ref::INVALID(); }
  int getInReplyToID() const { return inReplyTo.num; }
  const GooString *getSubject() const { return subject.get(); }
  AnnotMarkupReplyType getReplyTo() const { return replyTo; }
  AnnotExternalDataType getExData() const { return exData; }

  // The annotation takes the ownership of new_popup
  void setPopup(std::unique_ptr<AnnotPopup> &&new_popup);
  void setLabel(GooString *new_label);
  void setOpacity(double opacityA);
  void setDate(GooString *new_date);

protected:
  void removeReferencedObjects() override;

  std::unique_ptr<GooString> label;   // T            (Default author)
  std::unique_ptr<AnnotPopup> popup;  // Popup
  double opacity;                     // CA           (Default 1.0)
  // RC
  std::unique_ptr<GooString> date;    // CreationDate
  Ref inReplyTo;                      // IRT
  std::unique_ptr<GooString> subject; // Subj
  AnnotMarkupReplyType replyTo;       // RT           (Default R)
  // this object is overridden by the custom intent fields defined in some
  // annotation types.
  //GooString *intent;                // IT
  AnnotExternalDataType exData;       // ExData

private:
  void initialize(PDFDoc *docA, Dict *dict);
};

//------------------------------------------------------------------------
// AnnotText
//------------------------------------------------------------------------

class AnnotText: public AnnotMarkup {
public:
  enum AnnotTextState {
    stateUnknown,
    // Marked state model
    stateMarked,    // Marked
    stateUnmarked,  // Unmarked
    // Review state model
    stateAccepted,  // Accepted
    stateRejected,  // Rejected
    stateCancelled, // Cancelled
    stateCompleted, // Completed
    stateNone       // None
  };

  AnnotText(PDFDoc *docA, PDFRectangle *rect);
  AnnotText(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotText() override;

  void draw(Gfx *gfx, bool printing) override;

  // getters
  bool getOpen() const { return open; }
  const GooString *getIcon() const { return icon.get(); }
  AnnotTextState getState() const { return state; }

  void setOpen(bool openA);
  void setIcon(GooString *new_icon);

private:

  void initialize(PDFDoc *docA, Dict *dict);

  bool open;                       // Open       (Default false)
  std::unique_ptr<GooString> icon;  // Name       (Default Note)
  AnnotTextState state;             // State      (Default Umarked if
                                    //             StateModel Marked
                                    //             None if StareModel Review)
};

//------------------------------------------------------------------------
// AnnotMovie
//------------------------------------------------------------------------



class AnnotMovie: public Annot {
 public:
  AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA);
  AnnotMovie(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotMovie() override;

  void draw(Gfx *gfx, bool printing) override;

  const GooString* getTitle() const { return title.get(); }
  Movie* getMovie() { return movie.get(); }

 private:
  void initialize(PDFDoc *docA, Dict *dict);

  std::unique_ptr<GooString> title; // T
  std::unique_ptr<Movie> movie;     // Movie + A
};


//------------------------------------------------------------------------
// AnnotScreen
//------------------------------------------------------------------------

class AnnotScreen: public Annot {
 public:

  AnnotScreen(PDFDoc *docA, PDFRectangle *rect);
  AnnotScreen(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotScreen() override;

  const GooString* getTitle() const { return title.get(); }

  AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs.get(); }
  LinkAction *getAction() { return action.get(); } // The caller should not delete the result
  std::unique_ptr<LinkAction> getAdditionalAction(AdditionalActionsType type);

 private:
  void initialize(PDFDoc *docA, Dict *dict);


  std::unique_ptr<GooString> title;                      // T

  std::unique_ptr<AnnotAppearanceCharacs> appearCharacs; // MK

  std::unique_ptr<LinkAction> action;                    // A
  Object additionalActions;                              // AA
};

//------------------------------------------------------------------------
// AnnotLink
//------------------------------------------------------------------------

class AnnotLink: public Annot {
public:

  enum AnnotLinkEffect {
    effectNone,     // N
    effectInvert,   // I
    effectOutline,  // O
    effectPush      // P
  };

  AnnotLink(PDFDoc *docA, PDFRectangle *rect);
  AnnotLink(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotLink() override;

  void draw(Gfx *gfx, bool printing) override;

  // getters
  LinkAction *getAction() const { return action.get(); }
  AnnotLinkEffect getLinkEffect() const { return linkEffect; }
  AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals.get(); }

protected:

  void initialize(PDFDoc *docA, Dict *dict);

  std::unique_ptr<LinkAction> action;                  // A, Dest
  AnnotLinkEffect linkEffect;                          // H          (Default I)
  //Dict *uriAction;                                   // PA

  std::unique_ptr<AnnotQuadrilaterals> quadrilaterals; // QuadPoints
};

//------------------------------------------------------------------------
// AnnotFreeText
//------------------------------------------------------------------------

class AnnotFreeText: public AnnotMarkup {
public:

  enum AnnotFreeTextQuadding {
    quaddingLeftJustified,  // 0
    quaddingCentered,       // 1
    quaddingRightJustified  // 2
  };

  enum AnnotFreeTextIntent {
    intentFreeText,           // FreeText
    intentFreeTextCallout,    // FreeTextCallout
    intentFreeTextTypeWriter  // FreeTextTypeWriter
  };

  static const double undefinedFontPtSize;

  AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, const DefaultAppearance &da);
  AnnotFreeText(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotFreeText() override;

  void draw(Gfx *gfx, bool printing) override;
  Object getAppearanceResDict() override;
  void setContents(GooString *new_content) override;

  void setDefaultAppearance(const DefaultAppearance &da);
  void setQuadding(AnnotFreeTextQuadding new_quadding);
  void setStyleString(GooString *new_string);
  void setCalloutLine(AnnotCalloutLine *line);
  void setIntent(AnnotFreeTextIntent new_intent);

  // getters
  std::unique_ptr<DefaultAppearance> getDefaultAppearance() const;
  AnnotFreeTextQuadding getQuadding() const { return quadding; }
  // return rc
  const GooString *getStyleString() const { return styleString.get(); }
  AnnotCalloutLine *getCalloutLine() const {  return calloutLine.get(); }
  AnnotFreeTextIntent getIntent() const { return intent; }
  AnnotBorderEffect *getBorderEffect() const { return borderEffect.get(); }
  PDFRectangle *getRectangle() const { return rectangle.get(); }
  AnnotLineEndingStyle getEndStyle() const { return endStyle; }

protected:

  void initialize(PDFDoc *docA, Dict *dict);
  void generateFreeTextAppearance();

  // required
  std::unique_ptr<GooString> appearanceString;      // DA

  // optional
  AnnotFreeTextQuadding quadding;                   // Q  (Default 0)
  // RC
  std::unique_ptr<GooString> styleString;           // DS
  std::unique_ptr<AnnotCalloutLine> calloutLine;    // CL
  AnnotFreeTextIntent intent;                       // IT
  std::unique_ptr<AnnotBorderEffect> borderEffect;  // BE
  std::unique_ptr<PDFRectangle> rectangle;          // RD
  // inherited  from Annot
  // AnnotBorderBS border;                          // BS
  AnnotLineEndingStyle endStyle;                    // LE (Default None)
};

//------------------------------------------------------------------------
// AnnotLine
//------------------------------------------------------------------------

class AnnotLine: public AnnotMarkup {
public:

  enum AnnotLineIntent {
    intentLineArrow,    // LineArrow
    intentLineDimension // LineDimension
  };

  enum AnnotLineCaptionPos {
    captionPosInline, // Inline
    captionPosTop     // Top
  };

  AnnotLine(PDFDoc *docA, PDFRectangle *rect);
  AnnotLine(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotLine() override;

  void draw(Gfx *gfx, bool printing) override;
  Object getAppearanceResDict() override;
  void setContents(GooString *new_content) override;

  void setVertices(double x1, double y1, double x2, double y2);
  void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end);
  void setInteriorColor(std::unique_ptr<AnnotColor> &&new_color);
  void setLeaderLineLength(double len);
  void setLeaderLineExtension(double len);
  void setCaption(bool new_cap);
  void setIntent(AnnotLineIntent new_intent);

  // getters
  AnnotLineEndingStyle getStartStyle() const { return startStyle; }
  AnnotLineEndingStyle getEndStyle() const { return endStyle; }
  AnnotColor *getInteriorColor() const { return interiorColor.get(); }
  double getLeaderLineLength() const { return leaderLineLength; }
  double getLeaderLineExtension() const { return leaderLineExtension; }
  bool getCaption() const { return caption; }
  AnnotLineIntent getIntent() const { return intent; }
  double  getLeaderLineOffset() const { return leaderLineOffset; }
  AnnotLineCaptionPos getCaptionPos() const { return captionPos; }
  Dict *getMeasure() const { return measure; }
  double getCaptionTextHorizontal() const { return captionTextHorizontal; }
  double getCaptionTextVertical() const { return captionTextVertical; }
  double getX1() const { return coord1->getX(); }
  double getY1() const { return coord1->getY(); }
  double getX2() const { return coord2->getX(); }
  double getY2() const { return coord2->getY(); }

protected:

  void initialize(PDFDoc *docA, Dict *dict);
  void generateLineAppearance();

  // required
  std::unique_ptr<AnnotCoord> coord1;
  std::unique_ptr<AnnotCoord> coord2;

  // optional
  // inherited  from Annot
  // AnnotBorderBS border;                   // BS
  AnnotLineEndingStyle startStyle;           // LE       (Default [/None /None])
  AnnotLineEndingStyle endStyle;             //
  std::unique_ptr<AnnotColor> interiorColor; // IC
  double leaderLineLength;                   // LL       (Default 0)
  double leaderLineExtension;                // LLE      (Default 0)
  bool caption;                              // Cap      (Default false)
  AnnotLineIntent intent;                    // IT
  double leaderLineOffset;                   // LLO
  AnnotLineCaptionPos captionPos;            // CP       (Default Inline)
  Dict *measure;                             // Measure
  double captionTextHorizontal;              // CO       (Default [0, 0])
  double captionTextVertical;                //
};

//------------------------------------------------------------------------
// AnnotTextMarkup
//------------------------------------------------------------------------

class AnnotTextMarkup: public AnnotMarkup {
public:

  AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
  AnnotTextMarkup(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotTextMarkup() override;

  void draw(Gfx *gfx, bool printing) override;

  // typeHighlight, typeUnderline, typeSquiggly or typeStrikeOut
  void setType(AnnotSubtype new_type);

  void setQuadrilaterals(AnnotQuadrilaterals *quadPoints);

  AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals.get(); }

protected:

  void initialize(PDFDoc *docA, Dict *dict);

  std::unique_ptr<AnnotQuadrilaterals> quadrilaterals; // QuadPoints
};

//------------------------------------------------------------------------
// AnnotStamp
//------------------------------------------------------------------------

class AnnotStamp: public AnnotMarkup {
public:

  AnnotStamp(PDFDoc *docA, PDFRectangle *rect);
  AnnotStamp(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotStamp() override;

  void setIcon(GooString *new_icon);

  // getters
  const GooString *getIcon() const { return icon.get(); }

private:

  void initialize(PDFDoc *docA, Dict *dict);

  std::unique_ptr<GooString> icon; // Name       (Default Draft)
};

//------------------------------------------------------------------------
// AnnotGeometry
//------------------------------------------------------------------------

class AnnotGeometry: public AnnotMarkup {
public:

  AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
  AnnotGeometry(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotGeometry() override;

  void draw(Gfx *gfx, bool printing) override;

  void setType(AnnotSubtype new_type); // typeSquare or typeCircle
  void setInteriorColor(std::unique_ptr<AnnotColor> &&new_color);

  // getters
  AnnotColor *getInteriorColor() const { return interiorColor.get(); }
  AnnotBorderEffect *getBorderEffect() const { return borderEffect.get(); }
  PDFRectangle *getGeometryRect() const { return geometryRect.get(); }

private:

  void initialize(PDFDoc *docA, Dict *dict);

  std::unique_ptr<AnnotColor> interiorColor;       // IC
  std::unique_ptr<AnnotBorderEffect> borderEffect; // BE
  std::unique_ptr<PDFRectangle> geometryRect;      // RD (combined with Rect)
};

//------------------------------------------------------------------------
// AnnotPolygon
//------------------------------------------------------------------------

class AnnotPolygon: public AnnotMarkup {
public:

  enum AnnotPolygonIntent {
    polygonCloud,      // PolygonCloud
    polylineDimension, // PolyLineDimension
    polygonDimension   // PolygonDimension
  };

  AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
  AnnotPolygon(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotPolygon() override;

  void draw(Gfx *gfx, bool printing) override;
  void generatePolyLineAppearance(AnnotAppearanceBuilder* appearBuilder);
  void setType(AnnotSubtype new_type); // typePolygon or typePolyLine
  void setVertices(AnnotPath *path);
  void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end);
  void setInteriorColor(std::unique_ptr<AnnotColor> &&new_color);
  void setIntent(AnnotPolygonIntent new_intent);

  // getters
  AnnotPath *getVertices() const { return vertices.get(); }
  AnnotLineEndingStyle getStartStyle() const { return startStyle; }
  AnnotLineEndingStyle getEndStyle() const { return endStyle; }
  AnnotColor *getInteriorColor() const { return interiorColor.get(); }
  AnnotBorderEffect *getBorderEffect() const { return borderEffect.get(); }
  AnnotPolygonIntent getIntent() const { return intent; }

private:

  void initialize(PDFDoc *docA, Dict *dict);

  // required
  std::unique_ptr<AnnotPath> vertices;              // Vertices

  // optional
  AnnotLineEndingStyle startStyle;                  // LE       (Default [/None /None])
  AnnotLineEndingStyle endStyle;                    //
  // inherited  from Annot
  // AnnotBorderBS border;                          // BS
  std::unique_ptr<AnnotColor> interiorColor;        // IC
  std::unique_ptr<AnnotBorderEffect> borderEffect;  // BE
  AnnotPolygonIntent intent;                        // IT
  // Measure
};

//------------------------------------------------------------------------
// AnnotCaret
//------------------------------------------------------------------------

class AnnotCaret: public AnnotMarkup {
public:

  enum AnnotCaretSymbol {
    symbolNone,     // None
    symbolP         // P
  };

  AnnotCaret(PDFDoc *docA, PDFRectangle *rect);
  AnnotCaret(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotCaret() override;

  void setSymbol(AnnotCaretSymbol new_symbol);

  // getters
  AnnotCaretSymbol getSymbol() const { return symbol; }
  PDFRectangle *getCaretRect() const { return caretRect.get(); }

private:

  void initialize(PDFDoc *docA, Dict *dict);

  AnnotCaretSymbol symbol;                 // Sy         (Default None)
  std::unique_ptr<PDFRectangle> caretRect; // RD (combined with Rect)
};

//------------------------------------------------------------------------
// AnnotInk
//------------------------------------------------------------------------

class AnnotInk: public AnnotMarkup {
public:

  AnnotInk(PDFDoc *docA, PDFRectangle *rect);
  AnnotInk(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotInk() override;

  void draw(Gfx *gfx, bool printing) override;

  void setInkList(AnnotPath **paths, int n_paths);

  // getters
  AnnotPath **getInkList() const { return inkList; }
  int getInkListLength() const { return inkListLength; }

private:

  void initialize(PDFDoc *docA, Dict *dict);
  void writeInkList(AnnotPath **paths, int n_paths, Array *dest_array);
  void parseInkList(Array *src_array);
  void freeInkList();

  // required
  AnnotPath **inkList;       // InkList
  int inkListLength;

  // optional
  // inherited from Annot
  // AnnotBorderBS border;  // BS
};

//------------------------------------------------------------------------
// AnnotFileAttachment
//------------------------------------------------------------------------

class AnnotFileAttachment: public AnnotMarkup {
public:

  AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename);
  AnnotFileAttachment(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotFileAttachment() override;

  void draw(Gfx *gfx, bool printing) override;

  // getters
  Object *getFile() { return &file; }
  const GooString *getName() const { return name.get(); }

private:

  void initialize(PDFDoc *docA, Dict *dict);

  // required
  Object file;                      // FS

  // optional
  std::unique_ptr<GooString> name;  // Name
};

//------------------------------------------------------------------------
// AnnotSound
//------------------------------------------------------------------------

class AnnotSound: public AnnotMarkup {
public:

  AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA);
  AnnotSound(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotSound() override;

  void draw(Gfx *gfx, bool printing) override;

  // getters
  Sound *getSound() { return sound.get(); }
  const GooString *getName() const { return name.get(); }

private:

  void initialize(PDFDoc *docA, Dict *dict);

  // required
  std::unique_ptr<Sound> sound;    // Sound

  // optional
  std::unique_ptr<GooString> name; // Name
};

//------------------------------------------------------------------------
// AnnotWidget
//------------------------------------------------------------------------

class AnnotWidget: public Annot {
public:

  enum AnnotWidgetHighlightMode {
    highlightModeNone,    // N
    highlightModeInvert,  // I
    highlightModeOutline, // O
    highlightModePush     // P,T
  };

  AnnotWidget(PDFDoc *docA, Object &&dictObject, const Object *obj);
  AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA);
  ~AnnotWidget() override;

  void draw(Gfx *gfx, bool printing) override;

  void generateFieldAppearance (bool *addedDingbatsResource);
  void updateAppearanceStream ();

  AnnotWidgetHighlightMode getMode() { return mode; }
  AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs.get(); }
  LinkAction *getAction() { return action.get(); }  // The caller should not delete the result
  std::unique_ptr<LinkAction> getAdditionalAction(AdditionalActionsType type);
  std::unique_ptr<LinkAction> getFormAdditionalAction(FormAdditionalActionsType type);
  Dict *getParent() { return parent; }
  void setNewAppearance(Object &&newAppearance);

  bool setFormAdditionalAction(FormAdditionalActionsType type, const GooString &js);

private:

  void initialize(PDFDoc *docA, Dict *dict);

  Form *form;
  FormField *field;                                       // FormField object for this annotation
  AnnotWidgetHighlightMode mode;                          // H  (Default I)
  std::unique_ptr<AnnotAppearanceCharacs> appearCharacs;  // MK
  std::unique_ptr<LinkAction> action;                     // A
  Object additionalActions;                               // AA
  // inherited  from Annot
  // AnnotBorderBS border;                // BS
  Dict *parent;                           // Parent
  Ref updatedAppearanceStream; // {-1,-1} if updateAppearanceStream has never been called
};

//------------------------------------------------------------------------
// Annot3D
//------------------------------------------------------------------------

class Annot3D: public Annot {
  class Activation {
  public:
    enum ActivationATrigger {
      aTriggerUnknown,
      aTriggerPageOpened,  // PO
      aTriggerPageVisible, // PV
      aTriggerUserAction   // XA
    };

    enum ActivationAState {
      aStateUnknown,
      aStateEnabled, // I
      aStateDisabled // L
    };

    enum ActivationDTrigger {
      dTriggerUnknown,
      dTriggerPageClosed,    // PC
      dTriggerPageInvisible, // PI
      dTriggerUserAction     // XD
    };

    enum ActivationDState {
      dStateUnknown,
      dStateUninstantiaded, // U
      dStateInstantiated,   // I
      dStateLive            // L
    };

    Activation(Dict *dict);
  private:
    
    ActivationATrigger aTrigger;  // A   (Default XA)
    ActivationAState aState;      // AIS (Default L)
    ActivationDTrigger dTrigger;  // D   (Default PI)
    ActivationDState dState;      // DIS (Default U)
    bool displayToolbar;         // TB  (Default true)
    bool displayNavigation;      // NP  (Default false);
  };
public:

  Annot3D(PDFDoc *docA, PDFRectangle *rect);
  Annot3D(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~Annot3D() override;

  // getters

private:

  void initialize(PDFDoc *docA, Dict *dict);

  std::unique_ptr<Activation> activation;  // 3DA
};

//------------------------------------------------------------------------
// AnnotRichMedia
//------------------------------------------------------------------------

class AnnotRichMedia: public Annot {
public:
  class Params {
  public:
    Params(Dict *dict);
    ~Params();

    Params(const Params &) = delete;
    Params& operator=(const Params &) = delete;

    const GooString* getFlashVars() const;

  private:
    // optional
    std::unique_ptr<GooString> flashVars; // FlashVars
  };

  class Instance {
  public:
    enum Type {
      type3D,       // 3D
      typeFlash,    // Flash
      typeSound,    // Sound
      typeVideo     // Video
    };

    Instance(Dict *dict);
    ~Instance();

    Instance(const Instance &) = delete;
    Instance& operator=(const Instance &) = delete;

    Type getType() const;
    Params* getParams() const;

  private:
    // optional
    Type type;                      // Subtype
    std::unique_ptr<Params> params; // Params
  };

  class Configuration {
  public:
    enum Type {
      type3D,       // 3D
      typeFlash,    // Flash
      typeSound,    // Sound
      typeVideo     // Video
    };

    Configuration(Dict *dict);
    ~Configuration();

    Configuration(const Configuration &) = delete;
    Configuration& operator=(const Configuration &) = delete;

    Type getType() const;
    const GooString* getName() const;
    int getInstancesCount() const;
    Instance* getInstance(int index) const;

  private:
    // optional
    Type type;                       // Subtype
    std::unique_ptr<GooString> name; // Name
    Instance **instances;            // Instances
    int nInstances;
  };

  class Content;

  class Asset {
  public:
    Asset();
    ~Asset();

    Asset(const Asset &) = delete;
    Asset& operator=(const Asset &) = delete;

    const GooString* getName() const;
    Object* getFileSpec() const;

  private:
    friend class AnnotRichMedia::Content;

    std::unique_ptr<GooString> name;
    Object fileSpec;
  };

  class Content {
  public:
    Content(Dict *dict);
    ~Content();

    Content(const Content &) = delete;
    Content& operator=(const Content &) = delete;

    int getConfigurationsCount() const;
    Configuration* getConfiguration(int index) const;

    int getAssetsCount() const;
    Asset* getAsset(int index) const;

  private:
    // optional
    Configuration** configurations; // Configurations
    int nConfigurations;

    Asset **assets; // Assets
    int nAssets;
  };

  class Activation {
  public:
    enum Condition {
      conditionPageOpened,  // PO
      conditionPageVisible, // PV
      conditionUserAction   // XA
    };

    Activation(Dict *dict);

    Condition getCondition() const;

  private:
    // optional
    Condition condition;
  };

  class Deactivation {
  public:
    enum Condition {
      conditionPageClosed,    // PC
      conditionPageInvisible, // PI
      conditionUserAction     // XD
    };

    Deactivation(Dict *dict);

    Condition getCondition() const;

  private:
    // optional
    Condition condition;
  };

  class Settings {
  public:
    Settings(Dict *dict);
    ~Settings();

    Settings(const Settings &) = delete;
    Settings& operator=(const Settings &) = delete;

    Activation* getActivation() const;
    Deactivation* getDeactivation() const;

  private:
    // optional
    std::unique_ptr<Activation> activation;
    std::unique_ptr<Deactivation> deactivation;
  };

  AnnotRichMedia(PDFDoc *docA, PDFRectangle *rect);
  AnnotRichMedia(PDFDoc *docA, Object &&dictObject, const Object *obj);
  ~AnnotRichMedia() override;

  Content* getContent() const;

  Settings* getSettings() const;

private:
  void initialize(PDFDoc *docA, Dict *dict);

  // required
  std::unique_ptr<Content> content;     // RichMediaContent

  // optional
  std::unique_ptr<Settings> settings;   // RichMediaSettings
};


//------------------------------------------------------------------------
// Annots
//------------------------------------------------------------------------

class Annots {
public:

  // Build a list of Annot objects and call setPage on them
  Annots(PDFDoc *docA, int page, Object *annotsObj);

  ~Annots();

  Annots(const Annots &) = delete;
  Annots& operator=(const Annots &) = delete;

  // Iterate through list of annotations.
  int getNumAnnots() const { return annots.size(); }
  Annot *getAnnot(int i) { return annots[i]; }
  void appendAnnot(Annot *annot);
  bool removeAnnot(Annot *annot);

private:
  Annot* createAnnot(Object &&dictObject, const Object *obj);
  Annot *findAnnot(Ref *ref);

  PDFDoc *doc;
  std::vector<Annot*> annots;
};

#endif
