/**
 * Copyright (C) 2003-2026, Foxit Software Inc..
 * All Rights Reserved.
 *
 * http://www.foxitsoftware.com
 *
 * The following code is copyrighted and is the proprietary of Foxit Software Inc.. It is not allowed to
 * distribute any parts of Foxit PDF SDK to third party or public without permission unless an agreement
 * is signed between Foxit Software Inc. and customers to explicitly grant customers permissions.
 *
 * @file fs_headerfooter.h
 * @brief Header file for header-footer related definitions and classes.
 */

#ifndef FS_HEADERFOOTER_H_
#define FS_HEADERFOOTER_H_

#include "common/fs_common.h"

/**
 * @brief Foxit namespace.
 *
 * @details All the definitions and classes of Foxit PDF SDK are defined within this namespace.
 */
namespace foxit {
/**
 * @brief pdf namespace.
 */
namespace pdf {
/**
 * This class represents the page number range (not index range) which is used for class @link HeaderFooter @endlink.
 *
 * @see @link HeaderFooter @endlink
 */
class PageNumberRange FS_FINAL : public Object {
 public:
  /**
   * @brief Constructor, with parameters.
   *
   * @param[in] start_number  Page number of the start page in current range, starting from 1.
   * @param[in] end_number    Page number of the end page in current range, starting from 1.
   * @param[in] filter        Filter type to decide which page numbers of this range would be used. Please refer to values
   *                          starting from @link common::Range::e_All @endlink and this should be one of these values.
   */
  explicit PageNumberRange(int32 start_number, int32 end_number, foxit::common::Range::Filter filter)
      : start_number(start_number)
      , end_number(end_number)
      , filter(filter) {}

  /** @brief Constructor. */
  PageNumberRange()
      : start_number(-1)
      , end_number(-1)
      , filter(foxit::common::Range::e_All) {}

  /**
   * @brief Constructor, with another page number range object.
   *
   * @param[in] page_range  Another page number range object.
   */
  PageNumberRange(const PageNumberRange& page_range)
      : start_number(page_range.start_number)
      , end_number(page_range.end_number)
      , filter(page_range.filter) {}

  /**
   * @brief Assign operator.
   *
   * @param[in] page_range  Another page number range object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  PageNumberRange& operator=(const PageNumberRange& page_range) {
    start_number = page_range.start_number;
    end_number = page_range.end_number;
    filter = page_range.filter;
    return *this;
  }

  /**
   * @brief Set value.
   *
   * @param[in] start_number  Page number of the start page in current range, starting from 1.
   * @param[in] end_number    Page number of the end page in current range, starting from 1.
   * @param[in] filter        Filter type to decide which page numbers of this range would be used. Please refer to values
   *                          starting from @link common::Range::e_All @endlink and this should be one of these values.
   *
   * @return None.
   */
  void Set(int32 start_number, int32 end_number, foxit::common::Range::Filter filter) {
    this->start_number = start_number;
    this->end_number = end_number;
    this->filter = filter;
  }

  /** @brief Page number of the start page in current range, starting from 1. */
  int32 start_number;
  /** @brief Page number of the end page in current range, starting from 1. */
  int32 end_number;
  /**
   * @brief Filter type to decide which page numbers of this range would be used. Please refer to values
   *        starting from @link common::Range::e_All @endlink and this should be one of these values.
   */
  foxit::common::Range::Filter filter;
};

/**
 * This class represents the header-footer content.
 * Any string member of this class can set directly or be generated by using class @link HeaderFooterContentGenerator @endlink.
 *
 * @see @link HeaderFooterContentGenerator @endlink.
 */
class HeaderFooterContent FS_FINAL : public Object {
 public:
  /**
   * @brief Constructor, with parameters.
   *
   * @param[in] header_left_content    Content for left header.
   * @param[in] header_center_content  Content for center header.
   * @param[in] header_right_content   Content for right header.
   * @param[in] footer_left_content    Content for left footer.
   * @param[in] footer_center_content  Content for center footer.
   * @param[in] footer_right_content   Content for right footer.
   */
  explicit HeaderFooterContent(const WString& header_left_content, const WString& header_center_content,
                               const WString& header_right_content, const WString& footer_left_content,
                               const WString& footer_center_content, const WString& footer_right_content)
      : header_left_content(header_left_content)
      , header_center_content(header_center_content) 
      , header_right_content(header_right_content)
      , footer_left_content(footer_left_content)
      , footer_center_content(footer_center_content)
      , footer_right_content(footer_right_content) {}

  /** @brief Constructor. */
  HeaderFooterContent() {}

  /**
   * @brief Constructor, with another header-footer content object.
   *
   * @param[in] other  Another header-footer content object.
   */
  HeaderFooterContent(const HeaderFooterContent& other)
      : header_left_content(other.header_left_content)
      , header_center_content(other.header_center_content)
      , header_right_content(other.header_right_content)
      , footer_left_content(other.footer_left_content)
      , footer_center_content(other.footer_center_content)
      , footer_right_content(other.footer_right_content) {}

  /**
   * @brief Assign operator.
   *
   * @param[in] other  Another header-footer content object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  HeaderFooterContent& operator=(const HeaderFooterContent& other) {
    header_left_content = other.header_left_content;
    header_center_content = other.header_center_content;
    header_right_content = other.header_right_content;
    footer_left_content = other.footer_left_content;
    footer_center_content = other.footer_center_content;
    footer_right_content = other.footer_right_content;
    return *this;
  }

  /**
   * @brief Set value.
   *
   * @param[in] header_left_content    Content for left header.
   * @param[in] header_center_content  Content for center header.
   * @param[in] header_right_content   Content for right header.
   * @param[in] footer_left_content    Content for left footer.
   * @param[in] footer_center_content  Content for center footer.
   * @param[in] footer_right_content   Content for right footer.
   *
   * @return None.
   */
  void Set(const WString& header_left_content, const WString& header_center_content,
           const WString& header_right_content, const WString& footer_left_content,
           const WString& footer_center_content, const WString& footer_right_content) {
    this->header_left_content = header_left_content;
    this->header_center_content = header_center_content;
    this->header_right_content = header_right_content;
    this->footer_left_content = footer_left_content;
    this->footer_center_content = footer_center_content;
    this->footer_right_content = footer_right_content;
  }

  /** @brief Content for left header. */
  WString header_left_content;
  /** @brief Content for center header. */
  WString header_center_content;
  /** @brief Content for right header. */
  WString header_right_content;
  /** @brief Content for left footer. */
  WString footer_left_content;
  /** @brief Content for center footer. */
  WString footer_center_content;
  /** @brief Content for right footer. */
  WString footer_right_content;
};

/** This class represents properties and data for a header-footer. */
class HeaderFooter FS_FINAL : public Object {
 public:
  /**
   * @brief Constructor, with parameters.
   *
   * @param[in] font                     A valid font object used for header-footer content.
   *                                     Please refer to comment of <i>font</i> of current object.
   * @param[in] text_size                Text size of header-footer content.
   * @param[in] text_color               Text color used for header-footer content.
   * @param[in] page_range               A page number range object which specifies pages where current header-footer is used.
   *                                     Please refer to comment of <i>page_range</i> of current object.
   * @param[in] page_margin              Page margin which specifies the location for header-footer content.
   *                                     Please refer to comment of <i>page_margin</i> of current object.
   * @param[in] has_text_shrinked        A boolean value that decides whether to shrink text or not.
   * @param[in] has_fixedsize_for_print  A boolean value that decides whether to use fixed size for print or not.
   * @param[in] start_page_number        A virtual page number used for the first page specified in parameter <i>page_range</i>.
   *                                     This can be any number, even different from the actual page number of the specified page.
   *                                     If this value is less than 1, Foxit PDF SDK will use 1 for this value when current header-footer object
   *                                     is used in a PDF document.
   * @param[in] content                  Header-footer content.
   * @param[in] is_to_embed_font         A boolean value that decides whether to embed font or not.
   * @param[in] is_underline             A boolean value that decides whether to underline text or not.
   */
  explicit HeaderFooter(const common::Font& font, float text_size, RGB text_color, const PageNumberRange& page_range, RectF page_margin,
                        bool has_text_shrinked, bool has_fixedsize_for_print, int start_page_number,
                        const HeaderFooterContent& content, bool is_to_embed_font, bool is_underline)
    : font(font)
    , text_size(text_size)
    , text_color(text_color)
    , page_range(page_range)
    , page_margin(page_margin)
    , has_text_shrinked(has_text_shrinked)
    , has_fixedsize_for_print(has_fixedsize_for_print)
    , start_page_number(start_page_number)
    , content(content)
    , is_to_embed_font(is_to_embed_font)
    , is_underline(is_underline)
    , is_replace_font(true) {}

  /** @brief Constructor. */
  HeaderFooter()
    : text_size(0)
    , text_color(0)
    , has_text_shrinked(false)
    , has_fixedsize_for_print(false)
    , start_page_number(0)
    , is_to_embed_font(false)
    , is_underline(false)
    , is_replace_font(true) {
    page_margin = RectF(72.0, 36.0, 72.0, 36.0);
  }

  /**
   * @brief Constructor, with another header-footer object.
   *
   * @param[in] other  Another header-footer object.
   */
  HeaderFooter(const HeaderFooter& other)
    : font(other.font)
    , text_size(other.text_size)
    , text_color(other.text_color)
    , page_range(other.page_range)
    , page_margin(other.page_margin)
    , has_text_shrinked(other.has_text_shrinked)
    , has_fixedsize_for_print(other.has_fixedsize_for_print)
    , start_page_number(other.start_page_number)
    , content(other.content)
    , is_to_embed_font(other.is_to_embed_font)
    , is_underline(other.is_underline)
    , is_replace_font(other.is_replace_font) {}

  /**
   * @brief Assign operator.
   *
   * @param[in] other  Another header-footer object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  HeaderFooter& operator=(const HeaderFooter& other) {
    font = other.font;
    text_size = other.text_size;
    text_color = other.text_color;
    page_range = other.page_range;
    page_margin = other.page_margin;
    has_text_shrinked = other.has_text_shrinked;
    has_fixedsize_for_print = other.has_fixedsize_for_print;
    start_page_number = other.start_page_number;
    content = other.content;
    is_to_embed_font = other.is_to_embed_font;
    is_underline = other.is_underline;
    is_replace_font = other.is_replace_font;
    return *this;
  }

  /**
   * @brief Set value.
   *
   * @param[in] font                     A valid font object which is expected to be used for header-footer content.
   *                                     Please refer to comment of <i>font</i> of current object.
   * @param[in] text_size                Text size of header-footer content.
   * @param[in] text_color               Text color used for header-footer content.
   * @param[in] page_range               A page number range object which specifies pages where current header-footer is used.
   *                                     Please refer to comment of <i>page_range</i> of current object.
   * @param[in] page_margin              Page margin which specifies the location for header-footer content.
   *                                     Please refer to comment of <i>page_margin</i> of current object.
   * @param[in] has_text_shrinked        A boolean value that decides whether to shrink text or not.
   * @param[in] has_fixedsize_for_print  A boolean value that decides whether to use fixed size for print or not.
   * @param[in] start_page_number        A virtual page number used for the first page specified in parameter <i>page_range</i>.
   *                                     This can be any number, even different from the actual page number of the specified page.
   *                                     If this value is less than 1, Foxit PDF SDK will use 1 for this value when current header-footer object
   *                                     is used in a PDF document.
   * @param[in] content                  Header-footer content.
   * @param[in] is_to_embed_font         A boolean value that decides whether to embed font or not.
   * @param[in] is_underline             A boolean value that decides whether to underline text or not.
   *
   * @return None.
   */
  void Set(const common::Font& font, float text_size, RGB text_color, const PageNumberRange& page_range, RectF page_margin,
           bool has_text_shrinked, bool has_fixedsize_for_print, int start_page_number,
           const HeaderFooterContent& content, bool is_to_embed_font, bool is_underline) {
    this->font = font;
    this->text_size = text_size;
    this->text_color = text_color;
    this->page_range = page_range;
    this->page_margin = page_margin;
    this->has_text_shrinked = has_text_shrinked;
    this->has_fixedsize_for_print = has_fixedsize_for_print;
    this->start_page_number = start_page_number;
    this->content = content;
    this->is_to_embed_font = is_to_embed_font;
    this->is_underline = is_underline;
    this->is_replace_font = true;
  }

  /**
   * @brief A valid font object which is expected to be used for header-footer content.
   *
   * @note Sometimes, Foxit PDF SDK cannot match an extract font with this font object.
   *       In this case, Foxit PDF SDK will match a similar font (which is not exactly same as this font object)
   *       for heasder-footer content instead.
   */
  common::Font font;

  /** @brief Text size of header-footer content. */
  float text_size;

  /** @brief Text color used for header-footer content. */
  RGB text_color;

  /**
   * @brief A page number range object which specifies pages where current header-footer is used.
   *
   * @details All the values represented in this range should start from 1 and no more than 
   *          page count of the PDF document, in which current header-footer object is used.
   */
  PageNumberRange page_range;

  /**
   * @brief Page margin which specifies the location for header-footer content. 
   *        Foxit PDF SDK will use a maring defined as (72.0, 36.0, 72.0, 36.0) as default if no margin value is set by user.
   * 
   * @note This value does not represent a rectangle. It just defines the left margin, bottom margin,
   *       right margin and top margin of a PDF page. These margins can be used to locate header-footer content
   *       in different places:
   *       <ul>
   *       <li>Left margin is used to specify the location for left header or footer content to be started.</li>
   *       <li>Right margin is used to specify the location for right header or footer content to be ended.</li>
   *       <li>Bottom margin is used to specify the top location for any footer content to be placed.
   *           If bottom margin is no more than 0, the footer content will be invisible.</li>
   *       <li>Top margin is used to specify the bottom location for any header content to be placed.
   *           If top margin is no more than 0, the header content will be invisible.</li>
   *       </ul>
   */
  RectF page_margin;

  /** @brief A boolean value that decides whether to shrink text or not. */
  bool has_text_shrinked;

  /** @brief A boolean value that decides whether to use fixed size for print or not. */
  bool has_fixedsize_for_print;

  /**
   * @brief A virtual page number used for the first page specified in parameter <i>page_range</i>.
   *        This can be any number, even different from the actual page number of the specified page.
   *
   * @note If this value is less than 1, Foxit PDF SDK will use 1 for this value when current header-footer object is used
   *       in a PDF document.
   */
  int start_page_number;

  /** @brief Header-footer content. */
  HeaderFooterContent content;

  /** @brief A boolean value that decides whether to embed font or not. */
  bool is_to_embed_font;

  /** @brief A boolean value that decides whether to underline text or not. */
  bool is_underline;

  /** @brief (Reserved) A boolean value that decides whether to replace font or not. Currently Foxit PDF SDK will use this as <b>true</b> all the time. */
  bool is_replace_font;
};

 /**
  * This class is the generator for header-footer content. It can help user to combine dates in specified format,
  * page numbers in specified format and any customized text content to one string which can be used as header-footer content.
  */
class HeaderFooterContentGenerator FS_FINAL : public Base {
 public:
  /**
   * @brief Enumeration for date format type.
   *
   * @details Values of this enumeration can be used alone.
   */
  typedef enum _DateFormatType {
    /** @brief If this is used, "m/d" would be used as the date format string. */
    e_DateFormatMSlashD = 0,
    /** @brief If this is used, "m/d/yy" would be used as the date format string. */
    e_DateFormatMSlashDSlashYY = 1,
    /** @brief If this is used, "m/d/yyyy" would be used as the date format string. */
    e_DateFormatMSlashDSlashYYYY = 2,
    /** @brief If this is used, "mm/dd/yy" would be used as the date format string. */
    e_DateFormatMMSlashDDSlashYY = 3,
    /** @brief If this is used, "mm/dd/yyyy" would be used as the date format string. */
    e_DateFormatMMSlashDDSlashYYYY = 4,
    /** @brief If this is used, "d/m/yy" would be used as the date format string. */
    e_DateFormatDSlashMSlashYY = 5,
    /** @brief If this is used, "d/m/yyyy" would be used as the date format string. */
    e_DateFormatDSlashMSlashYYYY = 6,
    /** @brief If this is used, "dd/mm/yy" would be used as the date format string. */
    e_DateFormatDDSlashMMSlashYY = 7,
    /** @brief If this is used, "dd/mm/yyyy" would be used as the date format string. */
    e_DateFormatDDSlashMMSlashYYYY = 8,
    /** @brief If this is used, "mm/yy" would be used as the date format string. */
    e_DateFormatMMSlashYY = 9,
    /** @brief If this is used, "mm/yyyy" would be used as the date format string. */
    e_DateFormatMMSlashYYYY = 10,
    /** @brief If this is used, "m.d.yy" would be used as the date format string. */
    e_DateFormatMDotDDotYY = 11,
    /** @brief If this is used, "m.d.yyyy" would be used as the date format string. */
    e_DateFormatMDotDDotYYYY = 12,
    /** @brief If this is used, "mm.dd.yy" would be used as the date format string. */
    e_DateFormatMMDotDDDotYY = 13,
    /** @brief If this is used, "mm.dd.yyyy" would be used as the date format string. */
    e_DateFormatMMDotDDDotYYYY = 14,
    /** @brief If this is used, "mm.yy" would be used as the date format string. */
    e_DateFormatMMDotYY = 15,
    /** @brief If this is used, "d.m.yyyy" would be used as the date format string. */
    e_DateFormatDDotMDotYYYY = 16,
    /** @brief If this is used, "dd.mm.yy" would be used as the date format string. */
    e_DateFormatDDDotMMDotYY = 17,
    /** @brief If this is used, "dd.mm.yyyy" would be used as the date format string. */
    e_DateFormatDDDotMMDotYYYY = 18,
    /** @brief If this is used, "yy-mm-dd" would be used as the date format string. */
    e_DateFormatYYHyphenMMHyphenDD = 19,
    /** @brief If this is used, "yyyy-mm-dd" would be used as the date format string. */
    e_DateFormatYYYYHyphenMMHyphenDD = 20
  } DateFormatType;
  
  /**
   * @brief Enumeration for page number format type.
   *
   * @details Values of this enumeration can be used alone.
   */
  typedef enum _PageNumberFormat {
    /** @brief If this is used, "1" would be used as the page number format string. */
    e_PageNumberFormatDefault = 0,
    /** @brief If this is used, "1 of n" would be used as the page number format string. */
    e_PageNumberFormatNumberOfCount = 1,
    /** @brief If this is used, "1/n" would be used as the page number format string. */
    e_PageNumberFormatNumberSlashCount = 2,
    /** @brief If this is used, "Page 1" would be used as the page number format string. */
    e_PageNumberFormatPageNumber = 3,
    /** @brief If this is used, "Page 1 of n" would be used as the page number format string. */
    e_PageNumberFormatPageNumberOfCount = 4
  } PageNumberFormat;
  

  // User is strongly recommended NOT to use this method; otherwise unknown situation may occur.
  explicit HeaderFooterContentGenerator(FS_HANDLE handle);

  /** @brief Constructor. */
  HeaderFooterContentGenerator();

  /** @brief Destructor. */
  ~HeaderFooterContentGenerator();

  /**
   * @brief Constructor, with another header-footer content generator object.
   *
   * @param[in] other  Another header-footer content generator object.
   */
  HeaderFooterContentGenerator(const HeaderFooterContentGenerator& other);

  /**
   * @brief Assign operator.
   *
   * @param[in] other  Another header-footer content generator object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  HeaderFooterContentGenerator& operator=(const HeaderFooterContentGenerator& other);

  /**
   * @brief Equal operator.
   *
   * @param[in] other  Another header-footer content generator object. This function will check if current object is equal to this one.
   *
   * @return <b>true</b> means equal, while <b>false</b> means not equal.
   */
  bool operator==(const HeaderFooterContentGenerator& other) const;

  /**
   * @brief Not equal operator.
   *
   * @param[in] other  Another header-footer content generator object. This function will check if current object is not equal to this one.
   *
   * @return <b>true</b> means not equal, while <b>false</b> means equal.
   */
  bool operator!=(const HeaderFooterContentGenerator& other) const;

  /**
   * @brief Check whether current object is empty or not.
   *
   * @details When the current object is empty, that means current object is useless.
   *
   * @return <b>true</b> means current object is empty, while <b>false</b> means not.
   */
  bool IsEmpty() const;

  /**
   * @brief Add a format string for a specified date format type.
   *
   * @details Header-footer content can contain format string for date.
   *          The date format string will be replaced by actual date time in specified format
   *          when the header-footer is used in PDF document.
   *
   * @param[in] format_type  Date format type. Please refer to values starting from
   *                         @link HeaderFooterContentGenerator::e_DateFormatMSlashD @endlink
   *                         and this should be one of these values.
   *
   * @return None.
   */
  void AddDate(DateFormatType format_type);

  /**
   * @brief Add a format string for a specified page number format type.
   *
   * @details Header-footer content can contain format string for page number.
   *          The page number format string will be replaced by page number in specified format
   *          when the header-footer is used in PDF document.
   *
   * @param[in] format_type  Page number format type. Please refer to values starting from
   *                         @link HeaderFooterContentGenerator::e_PageNumberFormatDefault @endlink
   *                         and this should be one of these values.
   *
   * @return None.
   */
  void AddPageNumber(PageNumberFormat format_type);

  /**
   * @brief Add a string.
   *
   * @param[in] new_string  A string.
   *
   * @return None.
   */
  void AddString(const WString& new_string);

  /**
   * @brief Clear strings (including format strings) which have been added to current content generator.
   *
   * @details After this function is called, current content generator will be the same as a newly constructed object.
   *
   * @return None.
   */
  void Clear();

  /**
   * @brief Generate a final string which can be used as header-footer content.
   *
   * @return The final string which can be used as header-footer content.
   */
  WString GenerateContent();
};
}  // namespace pdf
}  // namespace foxit

#endif  // FS_HEADERFOOTER_H_
