/**
 * 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_splitpdfdoc.h
 * @brief Header file for splitting PDF document related classes and methods.
 */

#ifndef FS_SPLITPDFDOC_H_
#define FS_SPLITPDFDOC_H_

#include "common/fs_common.h"
#include "pdf/fs_pdfdoc.h"

namespace foxit {
namespace pdf {
/** This class represents setting data used to set the name and directory of the PDF documents generated by splitting. */
class SplitOutputSettingData FS_FINAL : public Object{
 public:
  /** @brief Constructor. */
  SplitOutputSettingData()
    : output_folder_path(L""),
      add_before_or_after_orginal_name(false),
      custom_name(L""),
      separator(L""),
      is_overwrite(false) {}

  /**
   * @brief Constructor, with parameters.
   *
   * @param[in] output_folder_path                A valid folder path for the PDF documents generated by splitting.
   *                                              If the value is empty, it means using the folder path of the original PDF document as the folder path for the PDF documents generated through splitting.
   *                                              If the value is not empty, it is used as the folder path for the PDF documents generated through splitting.
   * @param[in] add_before_or_after_orginal_name  The file name of the PDF document generated through splitting is created by adding a custom name, 
   *                                              automatically generated numbers starting from 1, and separator to the original PDF file name. 
   *                                              <b>true</b> means a custom name and number will be added before the original PDF file name.
   *                                              <b>false</b> means a custom name and number will be added after the original PDF file name.
   * @param[in] custom_name                       The file name of the PDF document generated through splitting is created by adding a custom name,
   *                                              automatically generated numbers starting from 1, and separator to the original PDF file name. 
   *                                              This value represents the custom name.
   *                                              If this value is empty, it means that a custom name is not added to the original PDF file name to generate a new file name.
   *                                              If this value is not empty, it means that a custom name is added to the original PDF file name to generate a new file name.
   * @param[in] separator                         The file name of the PDF document generated through splitting is created by adding a custom name,
   *                                              automatically generated numbers starting from 1, and separator to the original PDF file name.
   *                                              This value represents the separator.
   *                                              If this value is empty, it means that the newly generated file name does not include a separator.
   *                                              If this value is not empty, it means that a separator is inserted between the original PDF file name and the custom name to generate a new file name.
   * @param[in] is_overwrite                      A boolean value used to indicate whether to overwrite the PDF document generated by splitting when the file already exists.
   *                                              <b>true</b> means that when the PDF document generated by splitting exists, it will be overwritten.
   *                                              <b>false</b> means that when the PDF document generated by splitting exists, it will not be overwritten.
   */
  SplitOutputSettingData(const wchar_t* output_folder_path, bool add_before_or_after_orginal_name,
                         const wchar_t* custom_name, const wchar_t* separator, bool is_overwrite) {
    this->output_folder_path = output_folder_path;
    this->add_before_or_after_orginal_name = add_before_or_after_orginal_name;
    this->custom_name = custom_name;
    this->separator = separator;
    this->is_overwrite = is_overwrite; 
  }

  /**
   * @brief Assign operator.
   *
   * @param[in] data  Another Split-Output setting data object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  SplitOutputSettingData &operator = (const SplitOutputSettingData& data) {
    this->output_folder_path = data.output_folder_path;
    this->add_before_or_after_orginal_name = data.add_before_or_after_orginal_name;
    this->custom_name = data.custom_name;
    this->separator = data.separator;
    this->is_overwrite = data.is_overwrite;
    return (*this);
  }

  /**
   * @brief Set value.
   *
   * @param[in] output_folder_path                A valid folder path for the PDF documents generated by splitting.
   *                                              If the value is empty, it means using the folder path of the original PDF document as the folder path for the PDF documents generated through splitting.
   *                                              If the value is not empty, it is used as the folder path for the PDF documents generated through splitting.
   * @param[in] add_before_or_after_orginal_name  The file name of the PDF document generated through splitting is created by adding a custom name,
   *                                              automatically generated numbers starting from 1, and separator to the original PDF file name. 
   *                                              <b>true</b> means a custom name and number will be added before the original PDF file name.
   *                                              <b>false</b> means a custom name and number will be added after the original PDF file name.
   * @param[in] custom_name                       The file name of the PDF document generated through splitting is created by adding a custom name,
   *                                              automatically generated numbers starting from 1, and separator to the original PDF file name. 
   *                                              This value represents the custom name.
   *                                              If this value is empty, it means that a custom name is not added to the original PDF file name to generate a new file name.
   *                                              If this value is not empty, it means that a custom name is added to the original PDF file name to generate a new file name.
   * @param[in] separator                         The file name of the PDF document generated through splitting is created by adding a custom name,
   *                                              automatically generated numbers starting from 1, and separator to the original PDF file name.
   *                                              This value represents the separator.
   *                                              If this value is empty, it means that the newly generated file name does not include a separator.
   *                                              If this value is not empty, it means that a separator is inserted between the original PDF file name and the custom name to generate a new file name.
   * @param[in] is_overwrite                      A boolean value used to indicate whether to overwrite the PDF document generated by splitting when the file already exists.
   *                                              <b>true</b> means that when the PDF document generated by splitting exists, it will be overwritten.
   *                                              <b>false</b> means that when the PDF document generated by splitting exists, it will not be overwritten.
   *
   * @return None.
   */
  void Set(const wchar_t* output_folder_path, bool add_before_or_after_orginal_name,
           const wchar_t* custom_name, const wchar_t* separator, bool is_overwrite) {
    this->output_folder_path = output_folder_path;
    this->add_before_or_after_orginal_name = add_before_or_after_orginal_name;
    this->custom_name = custom_name;
    this->separator = separator;
    this->is_overwrite = is_overwrite;
  }

  /**
   * @brief A valid folder path for the PDF documents generated by splitting.
   *
   * @details If the parameter <i>split_doc_array</i> of the called function @link SplitPDFDoc::StartSplitByFileSize @endlink contains an object constructed 
   *          using a constructor of @link SplitDocumentInfo @endlink with parameter <i>file_reader</i> or <i>doc</i>, 
   *          then this value cannot be empty. Otherwise, this value can be empty.
   *          If the value is empty, it means using the folder path of the original PDF document as the folder path for the PDF documents generated through splitting.
   *          If the value is not empty, it is used as the folder path for the PDF documents generated through splitting.
   *
   */
  WString output_folder_path;

  /**
   * @brief A boolean value is used to determine whether to add the custom name and number before or after the original PDF file name.
   *        Default value: <b>false</b>.
   *
   * @details The file name of the PDF document generated through splitting is created by adding a custom name,
   *          automatically generated numbers starting from 1, and separator to the original PDF file name. 
   *          <b>true</b> means a custom name and number will be added before the original PDF file name.
   *          <b>false</b> means a custom name and number will be added after the original PDF file name.
   *
   */
  bool add_before_or_after_orginal_name;

  /**
   * @brief A string value used to be added before or after the original PDF file name to generate a new file name. Default value: <b>L""</b>.
   *
   * @details The file name of the PDF document generated through splitting is created by adding a custom name,
   *          automatically generated numbers starting from 1, and separator to the original PDF file name. 
   *          This value represents the custom name.
   *          If this value is empty, it means that a custom name is not added to the original PDF file name to generate a new file name.
   *          If this value is not empty, it means that a custom name is added to the original PDF file name to generate a new file name.
   *
   */
  WString custom_name;

  /**
   * @brief A string value used to inserted between the original PDF file name and the custom name to generate a new file name. Default value: <b>L""</b>.
   *
   * @details The file name of the PDF document generated through splitting is created by adding a custom name,
   *          automatically generated numbers starting from 1, and separator to the original PDF file name.
   *          This value represents the separator.
   *          If this value is empty, it means that the newly generated file name does not include a separator.
   *          If this value is not empty, it means that a separator is inserted between the original PDF file name and the custom name to generate a new file name.
   *
   */
  WString separator;

  /**
   * @brief A boolean value used to indicate whether to overwrite the PDF document generated by splitting when the file already exists. Default value: <b>false</b>.
   *
   * @details <b>true</b> means that when the PDF document generated by splitting exists, it will be overwritten.
   *          <b>false</b> means that when the PDF document generated by splitting exists, it will not be overwritten.
   *
   */
  bool is_overwrite;
};

/** This class represents information of source PDF document which is to be split. */
class SplitDocumentInfo FS_FINAL : public Base{
 public:
  /**
   * @brief Constructor, with parameters.
   *
   * @details This constructor does not check the validity of input PDF file and
   *          the check will be done in function @link SplitPDFDoc::StartSplitByFileSize @endlink.
   *
   * @param[in] file_path  File path of a PDF file, which is to be split.
   * @param[in] password   Owner password of PDF file which is specified by parameter <i>file_path</i>.
   */
  SplitDocumentInfo(const wchar_t* file_path, const wchar_t* password);

  /**
   * @brief Constructor, with parameters.
   *
   * @details This constructor does not check the validity of input PDF document and
   *          the check will be done in function @link SplitPDFDoc::StartSplitByFileSize @endlink.
   *
   * @param[in] file_reader  A @link common::file::ReaderCallback @endlink object which is implemented by user to be split.It should not be <b>NULL</b>.
   * @param[in] password     Owner password of PDF file which is specified by parameter <i>file_reader</i>.
   * @param[in] file_name    A string value which represents the original PDF file name.  It is used to generate the file name of the PDF document after splitting.
   *                         The file name of the PDF document generated through splitting is created by adding a custom name,
   *                         automatically generated numbers starting from 1, and separator to the original PDF file name.
   */
  SplitDocumentInfo(common::file::ReaderCallback* file_reader, const wchar_t* password, const wchar_t* file_name);

  /**
   * @brief Constructor, with parameters.
   *
   * @details This constructor does not check the validity of input PDF document and
   *          the check will be done in function @link SplitPDFDoc::StartSplitByFileSize @endlink.
   *
   * @param[in] doc        A valid PDF document object which represents a PDF file to be split.
   *                       Please ensure input PDF document object have been loaded; otherwise unknown error may occur later
   *                       when current information object is used.
   * @param[in] file_name  A string value which represents the original PDF file name. It is used to generate the file name of the PDF document after splitting.
   *                       The file name of the PDF document generated through splitting is created by adding a custom name,
   *                       automatically generated numbers starting from 1, and separator to the original PDF file name.
   */
  SplitDocumentInfo(const PDFDoc& doc, const wchar_t* file_name);

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

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

  /**
   * @brief Constructor, with another information object.
   *
   * @param[in] other  Another information object.
   */
  SplitDocumentInfo(const SplitDocumentInfo& other);

  /**
   * @brief Assign operator.
   *
   * @param[in] other  Another information object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  SplitDocumentInfo& operator=(const SplitDocumentInfo& other);

  /**
   * @brief Equal operator.
   *
   * @param[in] other  Another information 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 SplitDocumentInfo& other) const;

  /**
   * @brief Not equal operator.
   *
   * @param[in] other  Another information 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 SplitDocumentInfo& 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;
};

/** This class represents an array of @link SplitDocumentInfo @endlink objects. */
FSDK_DEFINE_ARRAY(SplitDocumentInfoArray, SplitDocumentInfo)

/** This class represents result information of the PDF document generated by splitting. */
class SplitFileResult FS_FINAL : public Object{
 public:
  /**
   * @brief Enumeration for the state of split file.
   *
   * @details Values of this enumeration should be used alone.
   */
  typedef enum _SplitFileState {
    /** @brief The state is split successfully. */
    e_SplitFileSuccess = 0,
    /** 
     * @brief The state is failed due to file size being too small. 
     *
     * @detail If the file size of the PDF document to be split is smaller than the value of parameter <i> max_file_size </i> in 
     *         function @link StartSplitByFileSize @endlink, then this state will be returned in the file split result. 
     */
    e_SplitFileErrSizeTooSmall = 1,
    /**
     * @brief The state is failed due to file exist.
     *
     * @detail If a PDF document generated by splitting already exists, and the value of <i> is_overwrite </i> in the object of @link SplitOutputSettingData @endlink 
     *         is set to <b>false</b>, then this state will be returned in the file split result. 
     */
    e_SplitFileErrFileExist = 2,
    /**
     * @brief The state is failed due to file access being denied.
     *
     * @detail If the PDF document to be split is denied access, then this state will be returned in the file split result.
     */
    /** @brief The state is failed due to file access being denied. */
    e_SplitFileErrAccessDeny = 3
  } SplitFileState;
  

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

  /**
   * @brief Constructor, with parameters.
   *
   * @param[in] before_splitting_file_name  A string value used to represent the original PDF file name before splitting.
   *
   * @param[in] after_split_files_paths     An array of strings used to represent the paths of multiple PDF documents generated by splitting.
   *
   * @param[in] split_file_state            An enumeration value used to represent the status of the PDF documents generated by splitting.
   */
  SplitFileResult(const wchar_t* before_splitting_file_name, WStringArray after_split_files_paths, SplitFileState split_file_state) {
    this->before_splitting_file_name = before_splitting_file_name;
    this->after_split_files_paths = after_split_files_paths;
    this->split_file_state = split_file_state;
  }

  /**
   * @brief Assign operator.
   *
   * @param[in] data  Another Split-File-Result data object, whose value would be assigned to current object.
   *
   * @return Reference to current object itself.
   */
  SplitFileResult &operator = (const SplitFileResult& data) {
    this->before_splitting_file_name = data.before_splitting_file_name;
    this->after_split_files_paths = data.after_split_files_paths;
    this->split_file_state = data.split_file_state;
    return (*this);
  }

  /**
   * @brief A string value used to represent the original PDF file name before splitting.
   *
   */
  WString before_splitting_file_name;

  /**
   * @brief An array of strings used to represent the paths of multiple PDF documents generated by splitting.
   *
   */
  WStringArray after_split_files_paths;

  /**
   * @brief An enumeration value used to represent the status of the PDF documents generated by splitting.
   *
   */
  SplitFileState split_file_state;
};

/** This class represents an array of SplitFileResult objects. */
FSDK_DEFINE_ARRAY(SplitFileResultArray, SplitFileResult)

/**
 * This class represents a callback object used to pause and notify the splitting progress during the splitting process, as well as to notify the result of the split.
 * All the pure virtual functions in this class are used as callback functions and should be implemented by user.
 */
class SplitPDFDocCallback {
 public:
  /**
   * @brief A callback function used to pause the current splitting progress.
   *
   * @return <b>true</b> means to pause now, while <b>false</b> means not to pause now.
   */
  virtual bool NeedToPause() = 0;

  /**
   * @brief A callback function used to notify the current splitting progress.
   *
   * @param[in] before_splitting_file_name  The file name of the original PDF document before splitting.
   * @param[in] after_split_file_path       The file path of the PDF document generated by splitting.
   * @param[in] split_page_count            The count of pages to be split in the current PDF document.
   * @param[in] total_page_count            The total count of pages in the current PDF documen.
   *
   * @return None.
   */
  virtual void ProgressNotify(const wchar_t* before_splitting_file_name, const wchar_t* after_split_file_path, int split_page_count, int total_page_count) = 0;

  /**
   * @brief A callback function used to notify the current split result.
   *
   * @param[in] result_array  An array of @link SplitFileResult @endlink objects.
   *                          When the splitting is completed, the result information of each file split will be notified.
   *
   * @return None.
   */
  virtual void ResultNotify(const SplitFileResultArray& result_array) = 0;
};

/**
 * This class can be used to split a PDF document into multiple PDF documents.
 * @see @link PDFDoc @endlink
 */
class SplitPDFDoc FS_FINAL : public Base{
 public:
  /**
   * @brief Start to split the PDF document into multiple PDF documents.
   *
   * @details This function can be used to batch process multiple documents.<br>
   *          The specific information of the PDF documents after splitting will be returned in the callback function @link SplitPDFDocCallback::ResultNotify @endlink.
   *
   * @param[in] max_file_size    The maximum file size of the PDF document generated by splitting (unit is Megabytes).
   *                             If the file size of the PDF document to be split is smaller than the value of this parameter,
   *                             the PDF document cannot be split and status @link SplitFileResult::e_SplitFileErrSizeTooSmall @endlink will be returned.
   *                             The lower limit of this parameter's value is 0.5 Megabytes.
   * @param[in] setting_data     Setting data used for splitting.
   * @param[in] split_doc_array  An array of PDF documents to be split. The size of this array should be greater than 0.
   * @param[in] split_callback   A @link SplitPDFDocCallback @endlink object which is implemented by user
   *                             to pause and notify the splitting progress during the splitting process,
   *                             as well as to notify the result of the split.
   *                             This can be <b>NULL</b> which means not to pause and notify the splitting progress.
   *                             If this is not <b>NULL</b>, it should be a valid @link SplitPDFDocCallback @endlink
   *                             object implemented by user.<br>
   *                             Default value: <b>NULL</b>.
   *
   * @return A progressive object. Please check the rate of current progress by function
   *         @link common::Progressive::GetRateOfProgress @endlink. If the rate is not 100 yet, call function
   *         @link common::Progressive::Continue @endlink to continue the progress until the progress is finished.
   */
  static common::Progressive StartSplitByFileSize(float max_file_size, const SplitOutputSettingData& setting_data, const SplitDocumentInfoArray& split_doc_array, SplitPDFDocCallback* split_callback = NULL);

};
}  // namespace pdf
}  // namespace foxit

#endif
