#ifndef FS_OFD_DOC_H_
#define FS_OFD_DOC_H_

#include "common/fs_common.h"
#include "common/fs_image.h"

/**
 * @brief Foxit 命名空间。
 *
 * @details Foxit PDF SDK 的所有定义和类都在此命名空间内定义。
 */
namespace foxit {
namespace fld {
class FLDDoc;
}
/**
 * @brief ofd 命名空间。
 */
namespace ofd {
class OFDPage;
class OFDTemplatePage;
class Catalog;
class Bookmarks;
class CustomTags;
class TagTreeNode;
class Outline;
class Attachments;
class Attachment;
class OFDPermission;
class Annots;
/**
 * @brief ofdseal 命名空间。
 */
namespace ofdseal {
class Signature;
}

/** 此类代表了页码参数信息。 */
class PageNumberParameter FS_FINAL : public Object {
 public:
  /**
   * @brief OFD添加页码位置枚举类型。
   *
   * @details 该枚举值应单独使用。
   */
  typedef enum _PageNumberLocationType {
    /** @brief 位置左上。 */
    e_PageNumberLocationTypeLeftTop   =  0,
    /** @brief 位置上中。 */
    e_PageNumberLocationTypeTopMiddle  =  1,
    /** @brief 位置右上。 */
    e_PageNumberLocationTypeRightTop  =  2,
    /** @brief 位置左下。 */
    e_PageNumberLocationTypeLeftBottom  =  3,
    /** @brief 位置下中。 */
    e_PageNumberLocationTypeBottomMiddle  =  4,
    /** @brief 位置右下。 */
    e_PageNumberLocationTypeRightBottom  =  5
  } PageNumberLocationType;
  
  /**
   * @brief OFD添加页码边距枚举类型。
   *
   * @details 该枚举值应单独使用。
   */
  typedef enum _PageNumberMarginType {
    /** @brief 边距小。 */
    e_PageNumberMarginTypeSmall   =  0,
    /** @brief 边距正常。 */
    e_PageNumberMarginTypeNormal  =  1,
    /** @brief 边距大。 */
    e_PageNumberMarginTypeLarge  =  2
  } PageNumberMarginType;
  

  /**
   * @brief 构造函数。
   */
  PageNumberParameter() :
    location(PageNumberParameter::e_PageNumberLocationTypeLeftTop),
    font_name(L"宋体"),
    font_size(12),
    text_color(0),
    start_page(0),
    end_page(0),
    is_first_page_cover(false),
    first_page_number(1),
    is_folio(false),
    margin(PageNumberParameter::e_PageNumberMarginTypeNormal),
    skip_blank_page(false) {}

  /**
   * @brief 带参数的构造函数。
   *
   * @param[in] location                页码位置类型。
   *                                    请参考从 @link PageNumberLocationType::e_PageNumberLocationTypeLeftTop @endlink 开始的值，
   *                                    这应该是这些值中的一个。默认为位置左上。
   * @param[in] font_name               页码文本字体名称。默认为"宋体"。
   * @param[in] font_size               页码文本字体大小。这应该是一个正值，默认为12。
   * @param[in] text_color              页码文本颜色。默认为黑色。
   * @param[in] start_page              起始页面索引，有效范围：从0到(<i>count</i>-1)。
   *                                    <i>count</i> 由函数 @link OFDPagckage::GetDocumentCount @endlink 返回。
   *                                    默认为0。
   * @param[in] end_page                终止页面索引，有效范围：从0到(<i>count</i>-1)。
   *                                    <i>count</i> 由函数 @link OFDPagckage::GetDocumentCount @endlink 返回。
   *                                    默认为0。
   * @param[in] is_first_page_cover     首页是否为封面，<b>true</b>代表首页，<b>false</b>代表非首页。默认为非首页。
   * @param[in] first_page_number       起始页码的数值，默认为1。
   * @param[in] is_folio                是否为对开页面，<b>true</b>代表是对开页面，<b>false</b>代表不是。默认为不是对开页面。
   * @param[in] margin                  页码边距类型。
   *                                    请参考从 @link PageNumberMarginType::e_PageNumberMarginTypeSmall @endlink 开始的值，
   *                                    这应该是这些值中的一个。默认为正常边距。
   * @param[in] skip_blank_page         是否跳过空白页。<b>true</b>代表跳过空白页，<b>false</b>代表不跳过空白页。默认为不跳过空白页。
   */
  explicit PageNumberParameter(PageNumberLocationType location, const WString& font_name, float font_size, foxit::RGB text_color, int start_page,
    int end_page, bool is_first_page_cover, int first_page_number, bool is_folio, PageNumberMarginType margin, bool skip_blank_page) :
    location(location),
    font_name(font_name),
    font_size(font_size),
    text_color(text_color),
    start_page(start_page),
    end_page(end_page),
    is_first_page_cover(is_first_page_cover),
    first_page_number(first_page_number),
    is_folio(is_folio),
    margin(margin),
    skip_blank_page(skip_blank_page) {}

  /**
   * @brief 用另一个页码参数对象的构造函数。
   *
   * @param[in] other  另一个页码参数对象。
   */
  PageNumberParameter(const PageNumberParameter& other) {
    this->location = other.location;
    this->font_name = other.font_name;
    this->font_size = other.font_size;
    this->text_color = other.text_color;
    this->start_page = other.start_page;
    this->end_page = other.end_page;
    this->is_first_page_cover = other.is_first_page_cover;
    this->first_page_number = other.first_page_number;
    this->is_folio = other.is_folio;
    this->margin = other.margin;
    this->skip_blank_page = other.skip_blank_page;
  }

  /**
   * @brief 赋值操作符。
   *
   * @param[in] char_info  另一个页码参数对象，其值将被赋给当前对象。
   *
   * @return 对当前对象自身的引用。
   */
  PageNumberParameter& operator = (const PageNumberParameter& other) {
    this->location = other.location;
    this->font_name = other.font_name;
    this->font_size = other.font_size;
    this->text_color = other.text_color;
    this->start_page = other.start_page;
    this->end_page = other.end_page;
    this->is_first_page_cover = other.is_first_page_cover;
    this->first_page_number = other.first_page_number;
    this->is_folio = other.is_folio;
    this->margin = other.margin;
    this->skip_blank_page = other.skip_blank_page;
    return *this;
  }

  /**
   * @brief 设置值。
   *
   * @param[in] location                页码位置类型。
   *                                    请参考从 @link PageNumberLocationType::e_PageNumberLocationTypeLeftTop @endlink 开始的值，
   *                                    这应该是这些值中的一个。
   * @param[in] font_name               页码文本字体名称。
   * @param[in] font_size               页码文本字体大小。
   * @param[in] text_color              页码文本颜色。
   * @param[in] start_page              起始页面，有效范围：从1到(<i>count</i>)。
   *                                    <i>count</i> 由函数 @link OFDPagckage::GetDocumentCount @endlink 返回。
   * @param[in] end_page                终止页面索引，有效范围：从1到(<i>count</i>)。
   *                                    <i>count</i> 由函数 @link OFDPagckage::GetDocumentCount @endlink 返回。
   * @param[in] is_first_page_cover     首页是否为封面，<b>true</b>代表首页，<b>false</b>代表非首页。
   * @param[in] first_page_number       起始页码的数值。
   * @param[in] is_folio                是否为对开页面，<b>true</b>代表是对开页面，<b>false</b>代表不是。
   * @param[in] margin                  页码边距类型。
   *                                    请参考从 @link PageNumberMarginType::e_PageNumberMarginTypeSmall @endlink 开始的值，
   *                                    这应该是这些值中的一个。
   * @param[in] skip_blank_page         是否跳过空白页。<b>true</b>代表跳过空白页，<b>false</b>代表不跳过空白页。
   *
   * @return 无。
   */
  void Set(PageNumberLocationType location, const WString& font_name, float font_size, foxit::RGB text_color, int start_page,
           int end_page, bool is_first_page_cover, int first_page_number, bool is_folio, PageNumberMarginType margin, bool skip_blank_page) {
    this->location = location;
    this->font_name = font_name;
    this->font_size = font_size;
    this->text_color = text_color;
    this->start_page = start_page;
    this->end_page = end_page;
    this->is_first_page_cover = is_first_page_cover;
    this->first_page_number = first_page_number;
    this->is_folio = is_folio;
    this->margin = margin;
    this->skip_blank_page = skip_blank_page;
  }

  /**
   * @brief 页码位置类型。
   *
   * @details 请参考从 @link PageNumberLocationType::e_PageNumberLocationTypeLeftTop @endlink 开始的值，
   *          这应该是这些值中的一个。
   *          默认为位置左上。
   */
  PageNumberLocationType location;

  /**
   * @brief 页码文本字体名称。默认为"宋体"。
   */
  WString font_name;

  /**
   * @brief 页码文本字体大小。这应该是一个正值，默认为12。
   */
  float font_size;

  /**
   * @brief 页码文本颜色。默认为黑色。
   */
  foxit::RGB text_color;

  /**
   * @brief 起始页面，有效范围：从1到(<i>count</i>)。<i>count</i> 由函数 @link OFDPagckage::GetDocumentCount @endlink 返回。
   *        默认为0。
   */
  int start_page;

  /**
   * @brief 终止页面，有效范围：从1到(<i>count</i>)。<i>count</i> 由函数 @link OFDPagckage::GetDocumentCount @endlink 返回。
   *        默认为0。
   */
  int end_page;

  /**
   * @brief 首页是否为封面，<b>true</b>代表首页，<b>false</b>代表非首页。
   *        默认为非首页。
   */
  bool is_first_page_cover;

  /**
   * @brief 起始页码的数值，默认为1。
   */
  int first_page_number;

  /**
   * @brief 是否为对开页面，<b>true</b>代表是对开页面，<b>false</b>代表不是。
   *        默认为不是对开页面。
   */
  bool is_folio;

  /**
   * @brief 页码位置类型。
   *
   * @details 请参考从 @link PageNumberLocationType::e_PageNumberLocationTypeLeftTop @endlink 开始的值，
   *          这应该是这些值中的一个。
   *          默认为正常边距。
   */
  PageNumberMarginType margin;

  /**
   * @brief 是否跳过空白页。<b>true</b>代表跳过空白页，<b>false</b>代表不跳过空白页。
   *        默认为不跳过空白页。
   */
  bool skip_blank_page;
};

/** 此类表示和OFD文档相关的方法。*/
class OFDDoc FS_FINAL : public Base {
 public:
   /**
    * @brief OFD文档加密方法枚举类型。
    *
    * @details 该枚举值应单独使用。
    */
  typedef enum _EncryptMethod {
    /** @brief 加密方法：无。 */
    e_OFDEncryptMethodNone   =  0,
    /** @brief 加密方法：密码加密 */
    e_OFDEncryptMethodPwd  =  1,
    /** @brief 加密方法：证书加密 */
    e_OFDEncryptMethodCert  =  2
  } EncryptMethod;
  
  /**
   * @brief OFD文档加密类型枚举类型。
   *
   * @details 该枚举值应单独使用。
   */
  typedef enum _EncryptType {
    /** @brief 加密类型：无。 */
    e_OFDEncryptTypeNone   =  0,
    /** @brief 加密类型：RC4。 */
    e_OFDEncryptTypeRC4  =  1,
    /** @brief 加密类型：AES128。 */
    e_OFDEncryptTypeAES128  =  2,
    /** @brief 加密类型：AES256。 */
    e_OFDEncryptTypeAES256  =  3,
    /** @brief 加密类型：SM4。 */
    e_OFDEncryptTypeSM4  =  4
  } EncryptType;
  
  /**
   * @brief OFD资源类型枚举类型。
   *
   * @details 该枚举值应单独使用。
   */
  typedef enum _ResourceType {
    /** @brief 未知类型。 */
    e_OFDResourceTypeUnknown   =  0,
    /** @brief 颜色空间资源类型。 */
    e_OFDResourceTypeColorSpace  =  1,
    /** @brief 绘制参数资源类型。 */
    e_OFDResourceTypeDrawParam  =  2,
    /** @brief 字体资源类型。 */
    e_OFDResourceTypeFont  =  3,
    /** @brief 多媒体资源类型。 */
    e_OFDResourceTypeMultimedia  =  4,
    /** @brief 复合图形单元资源类型。 */
    e_OFDResourceTypeCompositeGraphicUnit  =  5
  } ResourceType;
  

  /**
   * @brief 构造函数，从现有@link foxit::fld::FLDDoc @endlink对象。
   *
   * @param[in] doc  FLD文档对象。
   */
  explicit OFDDoc(const foxit::fld::FLDDoc& doc);

  /** @brief 析构函数。 */
  ~OFDDoc();

  /**
   * @brief 构造函数，通过另一个OFD文档对象。
   *
   * @param[in] other  另一个OFD文档对象。
   */
  OFDDoc(const OFDDoc& other);

  /**
   * @brief 赋值操作符。
   *
   * @param[in] other  另一个OFD文档对象，其值将被赋给当前对象。
   *
   * @return 当前对象自身的引用。
   */
  OFDDoc& operator = (const OFDDoc& other);

  /**
   * @brief 相等操作符。
   *
   * @param[in] other  另一个OFD文档对象。此函数将检查当前对象是否等于这个对象。
   *
   * @return <b>true</b> 表示相等，<b>false</b> 表示不相等。
   */
  bool operator == (const OFDDoc& other) const;

  /**
   * @brief 不相等操作符。
   *
   * @param[in] other  另一个OFD文档对象。此函数将检查当前对象是否不等于这个对象。
   *
   * @return <b>true</b> 表示不相等，<b>false</b> 表示相等。
   */
  bool operator != (const OFDDoc& other) const;

  /**
   * @brief 检查当前对象是否为空。
   *
   * @details 当前对象为空时，表示当前对象是无用的。
   *
   * @return <b>true</b> 表示当前对象为空，<b>false</b> 表示不为空。
   */
  bool IsEmpty() const;

  /**
   * @brief 获取OFD文档页面数量。
   *
   * @return OFD文档页面数量。
   */
  int GetPageCount();

  /**
   * @brief 获取OFD页面。
   *
   * @param[in] index          页面索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *
   * @return OFD页面对象。
   */
  OFDPage GetPage(int index);

  /**
   * @brief 获取OFD页面。
   *
   * @param[in] id          页面ID。
   *
   * @return OFD页面对象。
   */
  OFDPage GetPageByID(foxit::uint32 id);

  /**
   * @brief 添加新的页面。
   *
   * @return 在最后一页后添加新的OFD页面对象。
   */
  OFDPage AddPage();

  /**
   * @brief 插入新的OFD页面。
   *
   * @param[in] index   新的页面索引。有效范围：从0到(<i>count</i>)。
   *                    <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *
   * @return OFD页面对象。
   */
  OFDPage InsertPage(int index);

  /**
   * @brief 删除指定的OFD页面。
   *
   * @param[in] index   要删除的页面索引。有效范围：从0到(<i>count</i>-1)。
   *                    <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *
   * @return 无。
   */
  void RemovePage(int index);

  /**
   * @brief 指定保存需要保留的OFD页面。保存后，未保留的页面将被删除。
   *
   * @param[in] index   保留页面索引。有效范围：从0到(<i>count</i>-1)。
   *                    <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *
   * @return 无。
   */
  void ReservedPage(int index);

  /**
   * @brief 移动页面到指定索引。
   *
   * @param[in] index      要移动页面索引。有效范围：从0到(<i>count</i>-1)。
   *                       <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   * @param[in] dest_index 页面目的地索引。有效范围：从0到(<i>count</i>)。
   *                       <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *
   * @return <b>true</b>表示移动成功，<b>false</b>表示移动失败。
   */
  bool MovePage(int index, int dest_index);

  /**
   * @brief 获取OFD文档模板页面数量。
   *
   * @return OFD文档模板数量。
   */
  int GetTemplatePageCount();

  /**
   * @brief 获取OFD模板页面。
   *
   * @param[in] index          页面索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetTemplatePageCount @endlink 返回。
   *
   * @return OFD模板页面对象。
   */
  OFDTemplatePage GetTemplatePage(int index);

  /**
   * @brief 获取OFD模板页面。
   *
   * @param[in] id          模板页面id。
   *
   * @return OFD模板页面对象。
   */
  OFDTemplatePage GetTemplatePageByID(int id);

  /**
   * @brief 获取OFD模板页面。
   *
   * @param[in] name          模板页面名字。
   *
   * @return OFD模板页面对象。
   */
  OFDTemplatePage GetTemplatePageByName(const String& name);

  /**
   * @brief 插入模板页面。
   *
   * @param[in] index        插入的页面索引。有效范围：从0到(<i>count</i>-1)。
   *                         <i>count</i> 由函数 @link OFDDoc::GetTemplatePageCount @endlink 返回。
   *
   * @return OFD模板页面对象。
   */
  OFDTemplatePage InsertTemplatePage(int index);

  /**
   * @brief 删除模板页面。
   *
   * @param[in] index        删除页面索引。有效范围：从0到(<i>count</i>-1)。
   *                         <i>count</i> 由函数 @link OFDDoc::GetTemplatePageCount @endlink 返回。
   *
   * @return 无。
   */
  void RemoveTemplatePage(int index);

  /**
   * @brief 删除所有模板页面。
   *
   * @return 无。
   */
  void RemoveAllTemplatePages();

  /**
   * @brief 添加新的模板页面。
   *
   * @return 模板页面对象。
   */
  OFDTemplatePage AddTemplatePage();

  /**
   * @brief 添加新的模板页面。
   *
   * @param[in] page        用于创建模板页面的OFD页面对象。
   *
   * @return 模板页面对象。
   */
  OFDTemplatePage AddTemplatePageFromPage(OFDPage page);

  /**
   * @brief 添加新的页面。
   *
   * @param[in] index 	    用于创建页面的模板页面索引。 有效范围：从0到(<i>count</i>-1)。
   *                        <i>count</i> 由函数 @link OFDDoc::GetTemplatePageCount @endlink 返回。
   * @param[in] dest_index  插入的页面索引。有效范围：从0到(<i>count</i>)。
   *                        <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *                        默认值-1表示在最后一页后添加。
   *
   * @return 页面对象。
   */
  OFDPage AddPageFromTemplatePage(int index, int dest_index = -1);

  /**
   * @brief 创建OFD附件集合。
   *
   * @return 附件集合对象。
   */
  Attachments CreateAttachments();

  /**
   * @brief 获取OFD附件集合。
   *
   * @return 附件集合对象。
   */
  Attachments GetAttachments();

  /**
   * @brief 获取OFD附件数量
   *
   * @return 附件数量。
   */
  int GetAttachmentCount();

  /**
   * @brief 获取OFD附件对象。
   *
   * @param[in] index          附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetAttachmentCount @endlink 返回。
   *
   * @return OFD附件对象。
   */
  Attachment GetAttachment(int index);

  /**
   * @brief 获取OFD附件对象。
   *
   * @param[in] name          附件名。
   *
   * @return OFD附件对象。
   */
  Attachment GetAttachmentByName(const String& name);

  /**
   * @brief 获取OFD附件内存缓冲区。
   *
   * @param[in] index          附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetAttachmentCount @endlink 返回。
   *
   * @return OFD附件内存缓冲区。
   */
  String GetAttachmentBuffer(int index);

  /**
   * @brief 获取OFD附件文件指针。
   *
   * @param[in] index          附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetAttachmentCount @endlink 返回。
   *
   * @return OFD附件文件指针对象。
   */
  foxit::common::file::ReaderCallback* GetAttachmentFile(int index);

  /**
   * @brief 保存附件到文件中。
   *
   * @param[in] index          附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetAttachmentCount @endlink 返回。
   * @param[in] file_path      保存附件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ExportAttachment(int index, const String& file_path);

  /**
   * @brief 保存附件到文件中。
   *
   * @param[in] index          附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetAttachmentCount @endlink 返回。
   * @param[in] file_path      保存附件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ExportAttachment(int index, const WString& file_path);

  /**
   * @brief 保存附件到文件中。
   *
   * @param[in] index          附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetAttachmentCount @endlink 返回。
   * @param[in] file_writer    用户实现的 @link common::file::WriterCallback @endlink 对象，用于保存附件文档。
   *
   * @return 无。
   */
  void ExportAttachment(int index, foxit::common::file::WriterCallback* file_writer);

  /**
   * @brief 添加附件。
   *
   * @param[in] file_name      附件路径。
   * @param[in] name           附件名称。
   * @param[in] usage          附件用途。
   *
   * @return 附件对象。
   */
  Attachment AddAttachment(const String& file_name, const String& name = NULL, const String& usage = NULL);

  /**
   * @brief 添加附件。
   *
   * @param[in] file_name      附件路径。
   * @param[in] name           附件名称。
   * @param[in] usage          附件用途。
   *
   * @return 附件对象。
   */
  Attachment AddAttachment(const WString& file_name, const String& name = NULL, const String& usage = NULL);

  /**
   * @brief 获取OFD XML附件数量
   *
   * @return 附件数量。
   */
  int GetXmlFileAttachmentCount();

  /**
   * @brief 保存XML附件到文件中。
   *
   * @param[in] index          XML附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetXmlFileAttachmentCount @endlink 返回。
   * @param[in] file_path      保存附件的文件路径。它不应该是空字符串。
   *
   * @return <b>true</b>表示删除成功，<b>false</b>表示删除失败。
   */
  bool SaveXmlFileAttachment(int index, const String& file_path);

  /**
   * @brief 保存XML附件到文件中。
   *
   * @param[in] index          XML附件索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetXmlFileAttachmentCount @endlink 返回。
   * @param[in] file_path      保存附件的文件路径。它不应该是空字符串。
   *
   * @return <b>true</b>表示删除成功，<b>false</b>表示删除失败。
   */
  bool SaveXmlFileAttachment(int index, const WString& file_path);

  /**
   * @brief 获取OFD Metadata项。
   *
   * @param[in] key        关键字。
   *
   * @return 关键字对应的值。
   */
  WString GetMetadata(const WString& key);

  /**
   * @brief 设置OFD Metadata项。
   *
   * @param[in] key        关键字。
   * @param[in] value      关键字对应的值。
   *
   * @return 无。
   */
  void SetMetadata(const WString& key, const WString& value);

  /**
   * @brief 获取OFD Metadata项数量。
   *
   * @return Metadata项数量。
   */
  int GetKeywordCount();

  /**
   * @brief 插入关键字到OFD Metadata项。
   *
   * @param[in] keyword     关键字。
   * @param[in] index       插入的关键字索引，默认值为-1。
   *
   * @return 无。
   */
  void InsertKeyword(const WString& keyword, int index = -1);

  /**
   * @brief 删除指定关键字。
   *
   * @param[in] index 要删除的关键字索引。有效范围：从0到(<i>count</i>-1)。
   *                  <i>count</i> 由函数 @link OFDDoc::GetKeywordCount @endlink 返回。
   *
   * @return 无。
   */
  void RemoveKeyword(int index);

  /**
   * @brief 获取OFD自定义数据数量。
   *
   * @return 自定义数据数量。
   */
  int GetCustomDataCount();

  /**
   * @brief 获取OFD自定义数据。
   *
   * @param[in] index          自定义数据索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetCustomDataCount @endlink 返回。
   *
   * @return 自定义数据数量。
   */
  WString GetCustomDataName(int index);

  /**
   * @brief 获取OFD自定义值。
   *
   * @param[in] index          自定义数据索引。有效范围：从0到(<i>count</i>-1)。
   *                           <i>count</i> 由函数 @link OFDDoc::GetCustomDataCount @endlink 返回。
   *
   * @return 自定义数据数量。
   */
  WString GetCustomDataValue(int index);

  /**
   * @brief 添加OFD自定义数据。
   *
   * @param[in] key        自定义数据关键字。
   * @param[in] value      自定义数据值。
   *
   * @return 无。
   */
  void AddCustomData(const String& key, const String& value);

  /**
   * @brief 插入OFD自定义数据。
   *
   * @param[in] key        自定义数据关键字。
   * @param[in] value      自定义数据值。
   * @param[in] index      插入的自定义数据索引。
   *
   * @return 无。
   */
  void InsertCustomData(const String& key, const String& value, int index);

  /**
   * @brief 删除OFD自定义数据。
   *
   * @param[in] index      要删除的自定义数据索引。有效范围：从0到(<i>count</i>-1)。
   *                       <i>count</i> 由函数 @link OFDDoc::GetCustomDataCount @endlink 返回。
   *
   * @return <b>true</b>表示删除成功，<b>false</b>表示删除失败。
   */
  void RemoveCustomData(int index);

  /**
   * @brief 从文件添加资源到OFD文档。
   *
   * @param[in] file_path      资源文件路径。只能是mp4文件或者图片文件。它不应该是空字符串。
   * @param[in] format         资源格式。只能是mp4或者图片格式，图片格式不支持webp、jpx。
   * @return 资源ID。
   */
  foxit::uint32 AddResourceFromFile(const String& file_path, const String& format);

  /**
   * @brief 从文件添加资源到OFD文档。
   *
   * @param[in] file_path      资源文件路径。只能是mp4文件或者图片文件。它不应该是空字符串。
   * @param[in] format         资源格式。只能是mp4或者图片格式，图片格式不支持webp、jpx。
   *
   * @return 资源ID。
   */
  foxit::uint32 AddResourceFromFile(const WString& file_path, const String& format);

  /**
   * @brief 从图片文件添加资源到OFD文档。
   *
   * @param[in] file_path      资源文件路径。它不应该是空字符串。
   *
   * @return 资源ID。
   */
  foxit::uint32 AddImageResourceFromFile(const String& file_path);

  /**
   * @brief 从图片文件添加资源到OFD文档。
   *
   * @param[in] file_path      资源文件路径。它不应该是空字符串。图片格式不支持webp。
   *
   * @return 资源ID。
   */
  foxit::uint32 AddImageResourceFromFile(const WString& file_path);

  /**
   * @brief 从图片文件添加资源到OFD文档。
   *
   * @param[in] buffer 图片内存缓冲区。
   * @param[in] format 图片格式。
   *                   请参考从 @link foxit::common::Image::Type::e_None @endlink 开始的值。
   *                   不支持 @link foxit::common::Image::Type::e_WEBP @endlink 格式。
   *
   * @return 资源ID。
   */
  foxit::uint32 AddImageResourceFromBuffer(const String& buffer, foxit::common::Image::Type format);

  /**
   * @brief 添加字体资源到OFD文档。
   *
   * @param[in] font_family 字体家族名称。
   * @param[in] font_name   字体名称。
   *
   * @return 资源ID。
   */
  foxit::uint32 AddFontResourceFromName(const String& font_family, const String& font_name);

  /**
   * @brief 获取资源类型通过资源ID。
   *
   * @param[in] res_id 	      资源ID。
   *
   * @return 资源类型。
   *         请参考从 @link ResourceType::e_OFDResourceTypeUnknown @endlink 开始的值。
   */
  ResourceType GetResourceTypeByID(foxit::uint32 res_id);

  /**
   * @brief 通过资源ID获取多媒体文件指针。
   *
   * @param[in] res_id 	资源ID。
   *
   * @return 多媒体文件指针对象。
   */
  foxit::common::file::ReaderCallback* GetMultiMediaFileByID(int res_id);

  /**
   * @brief 保存多媒体文件。
   *
   * @param[in] res_id 	      资源ID。
   * @param[in] file_path     保存多媒体文件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ExportMultiMediaByID(foxit::uint32 res_id, const String& file_path);

  /**
   * @brief 保存多媒体文件。
   *
   * @param[in] res_id        资源ID。
   * @param[in] file_path     保存多媒体文件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ExportMultiMediaByID(foxit::uint32 res_id, const WString& file_path);

  /**
   * @brief 保存多媒体文件。
   *
   * @param[in] res_id 	      资源ID。
   * @param[in] file_writer   保存多媒体文件的用户实现的 @link common::file::WriterCallback @endlink 对象。
   *
   * @return 无。
   */
  void ExportMultiMediaByID(foxit::uint32 res_id, foxit::common::file::WriterCallback* file_writer);

  /**
   * @brief 获取多媒体内存缓冲区。
   *
   * @param[in] res_id 	      资源ID。
   *
   * @return 多媒体内存缓冲区。
   */
  String GetMultiMediaBufferByID(foxit::uint32 res_id);

  /**
   * @brief 获取多媒体文件名。
   *
   * @param[in] res_id 	      资源ID。
   *
   * @return 多媒体文件名。
   */
  WString GetMultiMediaFileNameByID(foxit::uint32 res_id);

  /**
   * @brief 获取多媒体类型。
   *
   * @param[in] res_id 	      资源ID。
   *
   * @return 多媒体类型。
   */
  WString GetMultiMediaTypeByID(foxit::uint32 res_id);

  /**
   * @brief 获取多媒体格式。
   *
   * @param[in] res_id 	      资源ID。
   *
   * @return 多媒体格式。
   */
  WString GetMultiMediaFormatByID(foxit::uint32 res_id);

  /**
   * @brief 导出注释。
   *
   * @param[in] file_path     导出注释文件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ExportAnnots(const String& file_path);

  /**
   * @brief 导出注释。
   *
   * @param[in] start_index   起始页面索引。有效范围：从0到(<i>count</i>-1)。
   *                          <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   * @param[in] end_index     终止页面索引。有效范围：从0到(<i>count</i>-1)。
   *                          <i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   * @param[in] file_path     导出注释文件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ExportAnnots(int start_index, int end_index, const String& file_path);

  /**
   * @brief 导入注释。
   *
   * @param[in] file_path     导入注释文件的文件路径。它不应该是空字符串。
   *
   * @return 无。
   */
  void ImportAnnots(const String& file_path);

  /**
   * @brief 根据页码参数添加页码。
   *
   * @param[in] param         页面页码参数结构体对象。
   *
   * @return 无。
   */
  void AddPageNumber(const PageNumberParameter& param);

  /**
   * @brief 插入新的文档。
   *
   * @param[in] other         被插入的文档对象。
   * @param[in] dest_index    插入的页面索引，默认值为-1，表示插入到最后面。
   *                          有效范围：从-1到(<i>count</i> - 1)。<i>count</i> 由函数 @link OFDDoc::GetPageCount @endlink 返回。
   *
   * @return <b>true</b>表示插入文档成功，<b>false</b>表示插入文档失败。
   */
  bool InsertDocument(const OFDDoc& other, int dest_index = -1);

  /**
   * @brief 创建大纲。
   *
   * @return 大纲对象。
   */
  Outline CreateOutline();

  /**
   * @brief 获取大纲。
   *
   * @return 大纲对象。
   */
  Outline GetOutline();

  /**
   * @brief 删除所有大纲节点。
   *
   * @return <b>true</b>表示删除成功，<b>false</b>表示删除失败。
   */
  bool RemoveOutline();

  /**
   * @brief 添加目录。
   *
   * @param[in] catalog  目录对象。
   *
   * @return <b>true</b>表示添加成功，<b>false</b>表示添加失败。
   */
  bool AddCatalog(const Catalog& catalog);

  /**
   * @brief 获取签名和签章数量。
   *
   * @return 签名和签章数量。
   */
  int GetSignatureCount();

  /**
   * @brief 获取签名或签章对象。
   *
   * @param[in] index  签章索引。有效范围：从0到(<i>count</i>-1)。
   *                   <i>count</i> 由函数 @link OFDDoc::GetSignatureCount @endlink 返回。
   *
   * @return 签名或签章对象。
   */
  ofdseal::Signature GetSignature(int index);

  /**
   * @brief 创建书签。
   *
   * @return 书签对象。
   */
  Bookmarks CreateBookmarks();

  /**
   * @brief 获取书签。
   *
   * @return 书签对象。
   */
  Bookmarks GetBookmarks();

  /**
   * @brief 创建自定义标签。
   *
   * @return 自定义标签对象。
   */
  CustomTags CreateCustomTags();

  /**
   * @brief 获取自定义标签。
   *
   * @return 自定义标签对象。
   */
  CustomTags GetCustomTags();

  /**
   * @brief 获取指定类型的票据标引树根节点。
   *
   * @param[in] type  票据标引类型，例如电子证照类型"Cert"。
   *
   * @return 票据标引树根节点对象。
   */
  TagTreeNode GetTagTreeRoot(const String& type);

  /**
   * @brief 在文档中初始化指定类型的票据标引树根节点。
   *
   * @param[in] type           票据标引类型，例如电子证照类型"Cert"。
   * @param[in] name_space     票据标引命名空间，例如电子证照命名空间"Cert"。
   * @param[in] name           票据标引名称，例如电子证照名称"电子证照"。
   * @param[in] file_extension 票据标引文件扩展名，例如电子证照“Certificate”，生成的标引文件为"Tag_Certificate.xml"。
   * @param[in] key_unique     票据标引键是否唯一，<b>true</b>表示唯一，<b>false</b>表示不唯一。
   *
   * @return 无。
   */
  void InitializeTagTreeNode(const String& type, const String& name_space, const String& name, const String& file_extension, bool key_unique);

  /**
   * @brief 在文档中初始化电子证照标引树根节点。
   *
   * @param[in] key_unique  票据标引键是否唯一，<b>true</b>表示唯一，<b>false</b>表示不唯一。
   *
   * @return 无。
   */
  void InitializeCertTagTreeNode(bool key_unique);

  /**
   * @brief 开始添加票据标引节点。
   *
   * @param[in] key_path  票据标引节点路径。
   *
   * @return 无。
   */
  void BeginTagTreeNode(const String& key_path);

  /**
   * @brief 添加自定义票据标引树节点元数据。
   *
   * @param[in] key    元数据关键字。
   * @param[in] value  元数据值。
   *
   * @return 无。
   */
  void AddTagTreeNodeMetaData(const String& key, const String& value);

  /**
   * @brief 结束添加票据标引节点。
   *
   * @param[in] key_path  票据标引节点路径。
   *
   * @return 无。
   */
  void EndTagTreeNode(const String& key_path);

  /**
   * @brief 清除票据标引所有节点。
   *
   * @return 无。
   */
  void ClearTagTreeNode();

  /**
   * @brief 导出公文语义xml文件。
   *
   * @param[in] file_path  导出公文语义xml文件的文件路径。它不应该是空字符串。
   *
   * @return <b>true</b>表示导出成功，<b>false</b>表示导出失败。
   */
  bool ExportOfficeDoc(const String& file_path);

  /**
   * @brief 导出公文语义xml文件。
   *
   * @param[in] file_path  导出公文语义xml文件的文件路径。它不应该是空字符串。
   *
   * @return <b>true</b>表示导出成功，<b>false</b>表示导出失败。
   */
  bool ExportOfficeDoc(const WString& file_path);

  /**
   * @brief 将安全语义删除，恢复到原始文档。存在安全语义时此函数才会执行恢复操作，否则什么都不会发生。
   *
   * @return <b>true</b>表示恢复成功，<b>false</b>表示恢复失败。
   */
  bool RestoreOriginalDocument();

  /**
   * @brief 刷新文档所有对象权限。存在安全语义时此函数才会执行刷新操作，否则什么都不会发生。
   *
   * @param[in] authenticated  是否通过认证。
   *
   * @return <b>true</b>表示刷新成功，<b>false</b>表示刷新失败。
   */
  bool RefreshObjectsPermission(bool authenticated);

  /**
   * @brief 移除文档加密。
   *
   * @param[in] owner_password  所有者密码。
   *
   * @return <b>true</b>表示移除成功，<b>false</b>表示移除失败。
   */
  bool RemoveEncryption(const String& owner_password);

  /**
   * @brief 获取权限对象。
   *
   * @return 权限对象。
   */
  OFDPermission GetPermissions();

  /**
   * @brief 创建权限对象。
   *
   * @return 权限对象。
   */
  OFDPermission CreatePermissions();

  /**
   * @brief 内嵌字体。
   *
   * @param[in] font_name  字体名称，必须是OFD中使用的字体。
   *                       否则什么都不会发生。
   *
   * @return 无。
   */
  void EmbedFont(const String& font_name);

  /**
   * @brief 获取版本数量。
   *
   * @return 无。
   */
  int GetVersionCount();

  /**
   * @brief 设置当前版本。
   *
   * @param[in] index  版本索引。有效范围：从0到(<i>count</i>-1)。
   *                   <i>count</i> 由函数 @link OFDDoc::GetVersionCount @endlink 返回。
   *
   * @return 无。
   */
  void SetCurrentVersion(int index);

  /**
   * @brief 创建版本，并切换到该版本。只能创建一个版本。
   *
   * @return 无。
   */
  void CreateVersion();

  explicit OFDDoc(FS_HANDLE handle = NULL);
};

}  // namespace ofd
}  // namespace foxit

#endif  // FS_OFD_DOC_H_
