#ifndef FS_OFD_ACTION_H_
#define FS_OFD_ACTION_H_

#include "common/fs_common.h"

/**
 * @brief Foxit 命名空间。
 *
 * @details Foxit PDF SDK 的所有定义和类都在此命名空间内定义。
 */
namespace foxit {
/**
* @brief ofd 命名空间。
*/
namespace ofd {
/** 此类表示类型为e_ActionTypeGoto的动作跳转的目标信息。 */
class ActionDestinationInfo FS_FINAL : public Object {
 public:
  /**
    * @brief OFD跳转动作的目标类型枚举类型。
    *
    * @details 该枚举值应单独使用。
    */
  typedef enum _GotoDestType {
    /** @brief 目标类型：未知。 */
    e_GotoDestTypeUnknown   =  0,
    /** @brief 目标类型：XYZ。 */
    e_GotoDestTypeXYZ  =  1,
    /** @brief 目标类型：适合页面。 */
    e_GotoDestTypeFit  =  2,
    /** @brief 目标类型：适合宽度。 */
    e_GotoDestTypeFitH  =  3,
    /** @brief 目标类型：适合高度。 */
    e_GotoDestTypeFitV  =  4,
    /** @brief 目标类型：适合区域。 */
    e_GotoDestTypeFitR  =  5
  } GotoDestType;
  

  /**
   * @brief 带参数的构造函数。
   *
   * @param[in] page_id   页面ID。
   * @param[in] type      目标类型。请参考从 @link GotoDestType::e_GotoDestTypeXYZ @endlink 开始的值，
   *                      这应该是这些值中的一个。
   * @param[in] left      左边距，单位为毫米。
   * @param[in] right     右边距，单位为毫米。
   * @param[in] top       上边距，单位为毫米。
   * @param[in] bottom    下边距，单位为毫米。
   * @param[in] zoom      缩放比例，取值范围为0.1-64。
   */
  explicit ActionDestinationInfo(foxit::uint32 page_id, GotoDestType type, float left, float right, float top, float bottom, float zoom) :
    page_id(page_id),
    type(type),
    left(left),
    right(right),
    top(top),
    bottom(bottom),
    zoom(zoom) {}

  /**
   * @brief 构造函数，通过另一个动作跳转目标信息对象。
   *
   * @param[in] other 另一个动作跳转目标信息对象。
   */
  ActionDestinationInfo(const ActionDestinationInfo& other) {
    this->page_id = other.page_id;
    this->type = other.type;
    this->left = other.left;
    this->right = other.right;
    this->top = other.top;
    this->bottom = other.bottom;
    this->zoom = other.zoom;
  }

  /**
   * @brief 赋值操作符。
   *
   * @param[in] other 另一个动作跳转目标信息对象，其值将被赋给当前对象。
   *
   * @return 当前对象自身的引用。
   */
  ActionDestinationInfo& operator = (const ActionDestinationInfo& other) {
    this->page_id = other.page_id;
    this->type = other.type;
    this->left = other.left;
    this->right = other.right;
    this->top = other.top;
    this->bottom = other.bottom;
    this->zoom = other.zoom;
    return *this;
  }

  /**
   * @brief 设置值。
   *
   * @param[in] page_id   页面ID。
   * @param[in] type      目标类型。请参考从 @link GotoDestType::e_GotoDestTypeXYZ @endlink 开始的值，
   *                      这应该是这些值中的一个。
   * @param[in] left      左边距，单位为毫米。
   * @param[in] right     右边距，单位为毫米。
   * @param[in] top       上边距，单位为毫米。
   * @param[in] bottom    下边距，单位为毫米。
   * @param[in] zoom      缩放比例，取值范围为0.1-64。
   *
   * @return 无。
   */
  void Set(foxit::uint32 page_id, GotoDestType type, float left, float right, float top, float bottom, float zoom) {
    this->page_id = page_id;
    this->type = type;
    this->left = left;
    this->right = right;
    this->top = top;
    this->bottom = bottom;
    this->zoom = zoom;
  }

  /**
   * @brief 页面ID。
   *
   */
  foxit::uint32 page_id;

  /**
   * @brief 目标类型。请参考从 @link GotoDestType::e_GotoDestTypeXYZ @endlink 开始的值，
   *        这应该是这些值中的一个。
   */
  GotoDestType type;

  /**
   * @brief 左边距，单位为毫米。
   *
   */
  float left;

  /**
   * @brief 右边距，单位为毫米。
   *
   */
  float right;

  /**
   * @brief 上边距，单位为毫米。
   *
   */
  float top;

  /**
   * @brief 下边距，单位为毫米。
   *
   */
  float bottom;

  /**
   * @brief 缩放比例，取值范围为0.1-64。
   *
   */
  float zoom;
};

/** 此类表示和OFD动作相关的操作。 */
class Action : public Base {
 public:
  /**
    * @brief OFD动作类型定义枚举类型。
    *
    * @details 该枚举值应单独使用。
    */
  typedef enum _ActionType {
    /** @brief 动作类型：未知。 */
    e_ActionTypeUnknown   =  0,
    /** @brief 动作类型：跳转。 */
    e_ActionTypeGoto  =  1,
    /** @brief 动作类型：URI。 */
    e_ActionTypeUri  =  2,
    /** @brief 动作类型：声音。 */
    e_ActionTypeSound  =  3,
    /** @brief 动作类型：视频。 */
    e_ActionTypeMovie  =  4,
    /** @brief 动作类型：跳转到动作。 */
    e_ActionTypeGotoA  =  5
  } ActionType;
  
  /**
    * @brief OFD动作触发事件枚举类型。
    *
    * @details 该枚举值应单独使用。
    */
  typedef enum _ActionEventTriggerType {
    /** @brief 动作触发类型：文档打开。 */
    e_ActionEventTriggerTypeDocumentOpen   =  0,
    /** @brief 动作触发类型：页面打开。 */
    e_ActionEventTriggerTypePageOpen  =  1,
    /** @brief 动作触发类型：鼠标点击。 */
    e_ActionEventTriggerTypeClick  =  2
  } ActionEventTriggerType;
  

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

  /**
   * @brief 用另一个动作对象构造当前动作对象。
   *
   * @param[in] other 另一个动作对象。
   */
  Action(const Action& other);

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

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

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

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

  /**
   * @brief 获取动作类型。
   *
   * @return 动作类型。请参考从 @link foxit::ofd::Action::e_ActionTypeGoto @endlink 开始的值，
   *         这应该是这些值中的一个。
   */
  foxit::ofd::Action::ActionType GetType();

  /**
   * @brief 获取事件触发器。
   *
   * @return 事件触发器值，这应该是从 @link foxit::ofd::Action::e_ActionTypeDocumentOpen @endlink 开始的值，
   *         这应该是这些值中的一个。
   */
  ActionEventTriggerType GetEventTrigger();

  /**
   * @brief 设置事件触发器。
   *
   * @param[in] event_trigger  事件触发器值, 这应该是从 @link foxit::ofd::Action::e_ActionTypeDocumentOpen @endlink 开始的值，
   *                           这应该是这些值中的一个。
   *
   * @return 无。
   */
  void SetEventTrigger(ActionEventTriggerType event_trigger);

  explicit Action(FS_HANDLE handle);
};

/** 此类表示和OFD跳转动作相关的操作。 */
class GoToAction FS_FINAL : public Action {
 public:
  /**
   * @brief 构造函数。
   */
  GoToAction();

  /**
   * @brief  构造函数，从现有@link foxit::ofd::Action @endlink对象。
   * @param[in] object Action对象。
                       此对象必须是一个有效的对象，并且其类型必须是@link foxit::ofd::Action::ActionType::e_ActionTypeGoto @endlink，否则构造函数将抛出异常。
   */
  explicit GoToAction(Action object);

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

  /**
   * @brief 构造函数，通过另一个跳转动作对象。
   *
   * @param[in] other 另一个跳转动作对象。
   */
  GoToAction(const GoToAction& other);

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

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

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

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

  /**
   * @brief 获取跳转目标信息。
   *
   * @return 跳转目标信息。请参考 @link foxit::ofd::ActionDestinationInfo @endlink 。
   */
  foxit::ofd::ActionDestinationInfo GetDestination();

  /**
   * @brief 设置跳转目标信息。
   *
   * @param[in] x        目标位置的X坐标，单位为毫米。
   * @param[in] y        目标位置的Y坐标，单位为毫米。
   * @param[in] page_id  目标页面ID。
   *
   * @return 无。
   */
  void SetDestination(float x, float y, foxit::uint32 page_id);

  explicit GoToAction(FS_HANDLE handle);
};

/** 此类表示和OFD URI动作相关的操作。 */
class URIAction FS_FINAL : public Action {
 public:
  /**
   * @brief 构造函数。
   */
  URIAction();

  /**
   * @brief  构造函数，从现有@link foxit::ofd::Action @endlink对象。
   * @param[in] object Action对象。
                       此对象必须是一个有效的对象，并且其类型必须是@link foxit::ofd::Action::ActionType::e_ActionTypeUri @endlink，否则构造函数将抛出异常。
   */
  explicit URIAction(Action object);

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

  /**
   * @brief 构造函数，通过另一个URI动作对象。
   *
   * @param[in] other 另一个URI动作对象。
   */
  URIAction(const URIAction& other);

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

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

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

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

  /**
   * @brief 获取URI。
   *
   * @return URI值。
   */
  String GetURI();

  /**
   * @brief 设置URI。
   *
   * @param[in] uri  指定的URI值。
   *
   * @return 无。
   */
  void SetURI(const String& uri);

  explicit URIAction(FS_HANDLE handle);
};

/** 此类表示和OFD声音动作相关的操作。 */
class SoundAction FS_FINAL : public Action {
 public:
  /**
   * @brief 构造函数。
   */
  SoundAction();

  /**
   * @brief  构造函数，从现有@link foxit::ofd::Action @endlink对象。
   * @param[in] object Action对象。
                       此对象必须是一个有效的对象，并且其类型必须是@link foxit::ofd::Action::ActionType::e_ActionTypeSound @endlink，否则构造函数将抛出异常。
   */
  explicit SoundAction(Action object);

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

  /**
   * @brief 构造函数，通过另一个声音动作对象。
   *
   * @param[in] other 另一个声音动作对象。
   */
  SoundAction(const SoundAction& other);

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

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

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

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

  /**
   * @brief 获取资源ID。
   *
   * @return 资源ID。
   */
  foxit::uint32 GetResourceID();

  /**
   * @brief 获取音量。
   *
   * @return 音量值。
   */
  int GetVolume();

  /**
   * @brief 检查是否重复播放。
   *
   * @return <b>true</b> 表示重复播放，<b>false</b> 表示不重复播放。
   */
  bool IsRepeat();

  /**
   * @brief 检查是否同步播放。
   *
   * @return <b>true</b> 表示同步播放，<b>false</b> 表示不同步播放。
   */
  bool IsSynchronous();

  /**
   * @brief 设置资源ID。
   *
   * @param[in] resource_id  资源ID值。
   *
   * @return 无。
   */
  void SetResourceID(foxit::uint32 resource_id);

  /**
   * @brief 设置音量。
   *
   * @param[in] volume  音量值，取值范围为0-100。
   *
   * @return 无。
   */
  void SetVolume(int volume);

  /**
   * @brief 设置是否重复播放。
   *
   * @param[in] repeat  指定是否重复播放。<b>true</b>表示重复播放，<b>false</b>表示不重复播放。
   *
   * @return 无。
   */
  void EnableRepeat(bool repeat);

  /**
   * @brief 设置是否同步播放。
   *
   * @param[in] synchronous  指定是否同步播放。<b>true</b>表示同步播放，<b>false</b>表示不同步播放。
   *
   * @return 无。
   */
  void EnableSynchronous(bool synchronous);

  explicit SoundAction(FS_HANDLE handle);
};

/** 此类表示和OFD视频动作相关的操作。 */
class MovieAction FS_FINAL : public Action {
 public:
  /**
    * @brief OFD视频动作的操作类型枚举类型。
    *
    * @details 该枚举值应单独使用。
    */
  typedef enum _MovieOperatorType {
    /** @brief 操作类型：播放。 */
    e_MovieOperatorTypePlay   =  0,
    /** @brief 操作类型：停止。 */
    e_MovieOperatorTypeStop  =  1,
    /** @brief 操作类型：暂停。 */
    e_MovieOperatorTypePause  =  2,
    /** @brief 操作类型：继续。 */
    e_MovieOperatorTypeResume  =  3
  } MovieOperatorType;
  

  /**
   * @brief 构造函数。
   */
  MovieAction();

  /**
   * @brief  构造函数，从现有@link foxit::ofd::Action @endlink对象。
   * @param[in] object Action对象。
                       此对象必须是一个有效的对象，并且其类型必须是@link foxit::ofd::Action::ActionType::e_ActionTypeMovie @endlink，否则构造函数将抛出异常。
   */
  explicit MovieAction(Action object);

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

  /**
   * @brief 构造函数，通过另一个视频动作对象。
   *
   * @param[in] other 另一个视频动作对象。
   */
  MovieAction(const MovieAction& other);

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

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

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

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

  /**
   * @brief 获取资源ID。
   *
   * @return 资源ID。
   */
  foxit::uint32 GetResourceID();

  /**
   * @brief 获取操作类型。
   *
   * @return 操作类型。请参考从 @link foxit::ofd::MovieAction::e_MovieOperatorTypePlay @endlink 开始的值，
   *         这应该是这些值中的一个。
   */
  MovieOperatorType GetOperator();

  /**
   * @brief 设置资源ID。
   *
   * @param[in] resource_ID  资源ID值。
   *
   * @return 无。
   */
  void SetResourceID(foxit::uint32 resource_id);

  /**
   * @brief 设置操作类型。
   *
   * @param[in] op  操作类型。请参考从 @link foxit::ofd::MovieAction::e_MovieOperatorTypePlay @endlink 开始的值,
   *                这应该是这些值中的一个。
   *
   * @return 无。
   */
  void SetOperator(MovieOperatorType op);

  explicit MovieAction(FS_HANDLE handle);
};

/** 此类表示和OFD动作集合相关的操作。 */
class Actions FS_FINAL : public Base {
 public:
  /** @brief 析构函数。 */
  ~Actions();

  /**
   * @brief 构造函数，通过另一个动作集合对象。
   *
   * @param[in] other 另一个动作集合对象。
   */
  Actions(const Actions& other);

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

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

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

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

  /**
   * @brief 获取动作的数量。
   *
   * @return 动作的数量。
   */
  int GetActionCount();

  /**
   * @brief 获取指定索引的动作对象。
   *
   * @param[in] index 指定的动作索引，有效范围：从0到(<i>count - 1</i>)。
   *                  <i>count</i>由函数 @link foxit::ofd::Actions::GetActionCount @endlink 返回。
   *
   * @return 指定索引的动作对象。
   */
  Action GetAction(int index);

  /**
   * @brief 添加动作对象。
   *
   * @param[in] type 指定的动作类型。请参考从 @link foxit::ofd::Action::e_ActionTypeGoto @endlink 开始的值，
   *                 这应该是这些值中的一个。
   *
   * @return 添加的动作对象。
   */
  Action AddAction(Action::ActionType type);

  /**
   * @brief 移除指定索引的动作对象。
   *
   * @param[in] index 指定的动作索引，有效范围：从0到<i>count - 1</i>。
   *                  <i>count</i>由函数 @link foxit::ofd::Actions::GetActionCount @endlink 返回。
   *
   * @return <b>true</b> 表示移除成功，<b>false</b> 表示移除失败。
   */
  bool RemoveAction(int index);

  explicit Actions(FS_HANDLE handle);
};

}  // namespace ofd
}  // namespace foxit

#endif  // FS_OFD_ACTION_H_
