#ifndef FS_OFD_PATHOBJECT_H_
#define FS_OFD_PATHOBJECT_H_

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

/**
 * @brief Foxit 命名空间。
 *
 * @details Foxit PDF SDK 的所有定义和类都在此命名空间内定义。
 */
namespace foxit {
/**
 * @brief ofd 命名空间。
 */
namespace ofd {
/**
 * @brief ofd graphics 命名空间。
 */
namespace graphics {
class OFDPathData;

/** 此类代表了Path数据点描述信息。 */
class PathPoint FS_FINAL : public Object {
 public:
  /**
   * @brief OFD路径类型枚举。
   *
   * @details 该枚举值应单独使用。
   */
  typedef enum _PathPointType {
    /** @brief 正常类型。 */
    e_PathPointTypeNormal = 0,
    /** @brief 起始类型。 */
    e_PathPointTypeStart = 1,
    /** @brief 移动类型。 */
    e_PathPointTypeMoveTo = 2,
    /** @brief 直线类型。 */
    e_PathPointTypeLineTo = 3,
    /** @brief 二次贝塞尔曲线类型。 */
    e_PathPointTypeQuadraticBezierTo = 4,
    /** @brief 三次贝塞尔曲线类型。 */
    e_PathPointTypeCubicBezierTo = 5,
    /** @brief 弧线类型。 */
    e_PathPointTypeArcTo = 6,
    /** @brief 结束类型。 */
    e_PathPointTypeClose = 7
  } PathPointType;
  
  /**
   * @brief 构造函数。
   */
  PathPoint()
      : x(0)
      , y(0)
      , type(e_PathPointTypeNormal) {
  }

  /**
   * @brief 带参数的构造函数。
   *
   * @param[in] x        x轴方向上的值。
   * @param[in] y        y轴方向上的值。
   * @param[in] type     路径类型。请参考从 @link foxit::ofd::graphics::PathPoint::e_PathPointTypeNormal @endlink 开始的值，
   *                     应该是这些值中的一个。
   */
  PathPoint(float x, float y, PathPointType type) :
    x(x),
    y(x),
    type(type) {
  }

  /**
   * @brief 赋值操作符。
   *
   * @param[in] other  另一个Path数据点描述信息对象，其值将被赋给当前对象。
   *
   * @return 当前对象自身的引用。
   */
  PathPoint& operator=(const PathPoint& other) {
    this->x = other.x;
    this->y = other.y;
    this->type = other.type;

    return *this;
  }

  /**
   * @brief 设置值。
   *
   * @param[in] x        x轴方向上的值。
   * @param[in] y        y轴方向上的值。
   * @param[in] type     路径类型。请参考从 @link foxit::ofd::graphics::PathPoint::e_PathPointTypeNormal @endlink 开始的值，
   *                     应该是这些值中的一个。
   *
   * @return 无。
   */
  void Set(float x, float y, PathPointType type) {
    this->x = x;
    this->y = y;
    this->type = type;
  }

  /**
   * @brief  x轴方向上的值。
   */
  float           x;

  /**
   * @brief  y轴方向上的值。
   */
  float           y;

  /**
   * @brief 路径类型。请参考从 @link foxit::ofd::graphics::PathPoint::e_PathPointTypeNormal @endlink 开始的值，
   *        应该是这些值中的一个。
   */
  PathPointType   type;
};

/** 此类表示椭圆描述信息。 */
class EllipseInfo FS_FINAL : public Object {
 public:
  /**
   * @brief 带参数的构造函数。
   *
   * @param[in] x_radius          x轴方向上半径。
   * @param[in] y_radius          y轴方向上半径。
   * @param[in] rotation_angle    旋转角度。
   * @param[in] large_arc         是否是大圆弧。
   * @param[in] sweep_direction   弧线方向是否为顺时针。
   */
  EllipseInfo(float x_radius, float y_radius, float rotation_angle, bool large_arc, bool sweep_direction)
   : x_radius(x_radius),
     y_radius(y_radius),
     rotation_angle(rotation_angle),
     large_arc(large_arc),
     sweep_direction(sweep_direction) {
  }

  /**
   * @brief 赋值操作符。
   *
   * @param[in] other  另一个椭圆信息对象，其值将被赋给当前对象。
   *
   * @return 对当前对象自身的引用。
   */
  EllipseInfo& operator=(const EllipseInfo& other) {
    this->x_radius = other.x_radius;
    this->y_radius = other.y_radius;
    this->rotation_angle = other.rotation_angle;
    this->large_arc = other.large_arc;
    this->sweep_direction = other.sweep_direction;

    return *this;
  }

  /**
   * @brief 设置值。
   *
   * @param[in] x_radius          x轴方向上半径。
   * @param[in] y_radius          y轴方向上半径。
   * @param[in] rotation_angle    旋转角度。
   * @param[in] large_arc         是否是大圆弧。
   * @param[in] sweep_direction   弧线方向是否为顺时针。
   *
   * @return 无。
   */
  void Set(float x_radius, float y_radius, float rotation_angle, bool large_arc, bool sweep_direction) {
    this->x_radius = x_radius;
    this->y_radius = y_radius;
    this->rotation_angle = rotation_angle;
    this->large_arc = large_arc;
    this->sweep_direction = sweep_direction;
  }

  /**
   * @brief x轴方向上半径。
   */
  float     x_radius;

  /**
   * @brief y轴方向上半径。
   */
  float     y_radius;

  /**
   * @brief 旋转角度。
   */
  float     rotation_angle;

  /**
   * @brief 是否是大圆弧。
   */
  bool      large_arc;

  /**
   * @brief 弧线方向是否为顺时针。
   */
  bool      sweep_direction;
};

FSDK_DEFINE_ARRAY(PathPointArray, PathPoint)

/** 此类表示和OFD路径对象相关的方法。*/
class OFDPathObject FS_FINAL : public OFDGraphicsObject {
 public:
  /**
   * @brief OFD路径填充模式枚举。
   *
   * @details 该枚举值应单独使用。
   */
  typedef enum _PathFillMode {
    /** @brief 非零填充。 */
    e_PathFillNonZero = 0,
    /** @brief 奇偶填充。 */
    e_PathFillEvenOdd = 1
  } PathFillMode;
  

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

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

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

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

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

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

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

  /**
   * @brief 判断路径对象填充属性。
   *
   * @return <b>true</b>表示有填充，<b>false</b>表示没有填充。
   */
  bool IsFill();

  /**
   * @brief 判断路径对象描边属性。
   *
   * @return <b>true</b>表示描边，<b>false</b>表示没有描边。
   */
  bool IsStroke();

  /**
   * @brief 获取路径数据对象。
   *
   * @return 路径数据对象。
   */
  OFDPathData GetPathData();

  /**
   * @brief 获取路径对象中路径元素描述序列。
   *
   * @return 路径元素描述字符串。
   */
  String GetAbbreviatedData();

  /**
   * @brief 获取路径对象填充模式。
   *
   * @return 路径对象填充模式值。请参考从 @link foxit::ofd::graphics::OFDPathObject::e_PathFillNonZero @endlink 开始的值，
   *         应该是这些值中的一个。
   */
  PathFillMode GetFillMode();

  /**
   * @brief 设置路径对象填充属性。
   *
   * @param[in] fill  填充属性。<b>true</b>表示填充，<b>false</b>表示不填充。
   *
   * @return 无。
   */
  void SetFill(bool fill);

  /**
   * @brief 设置路径对象填充模式。
   *
   * @param[in] fill_mode     填充模式。请参考从 @link foxit::ofd::graphics::OFDPathObject::e_PathFillNonZero @endlink 开始的值，
   *                          应该是这些值中的一个。
   *
   * @return 无。
   */
  void SetFillMode(PathFillMode fill_mode = e_PathFillNonZero);

  /**
   * @brief 设置路径对象描边属性。
   *
   * @param[in] stroke    描边属性。<b>true</b>表示描边，<b>false</b>表示不描边。
   *
   * @return 无。
   */
  void SetStroke(bool stroke);

  /**
   * @brief 设置路径对象中路径元素描述序列。
   *
   * @param[in] abbreviated_data  路径元素描述序列。
   *
   * @return 无。
   */
  void SetAbbreviatedData(const String& abbreviated_data);

  /**
   * @brief 设置路径数据对象。
   *
   * @param[in] path      路径数据对象。
   *
   * @return 无。
   */
  void SetPathData(const OFDPathData& path);

  explicit OFDPathObject(FS_HANDLE handle);
};

/** 此类表示和OFD路径数据相关的方法。*/
class OFDPathData FS_FINAL : public Base {
 public:
  /** @brief 不带参数函数。 */
  OFDPathData();

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

  /**
   * @brief 构造函数，通过另一个OFD路径数据。
   *
   * @param[in] other  另一个OFD路径数据。
   */
  OFDPathData(const OFDPathData& other);

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

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

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

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

  /**
   * @brief 定义图形起始点坐标。
   *
   * @param[in] x         x坐标。坐标系为OFD坐标系。
   * @param[in] y         y坐标。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void StartFigure(float x, float y);

  /**
   * @brief 将当前点移动到指定点位置。
   *
   * @param[in] x         x坐标。坐标系为OFD坐标系。
   * @param[in] y         y坐标。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void MoveTo(float x, float y);

  /**
   * @brief 从当前点连接一条到指定点的线段，并将当前点移动到指定点。
   *
   * @param[in] x         x坐标。坐标系为OFD坐标系。
   * @param[in] y         y坐标。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void LineTo(float x, float y);

  /**
   * @brief 从当前点链接一条到点pt2的二次贝塞尔曲线，并将当前点移动到点pt2，此贝塞尔曲线使用点pt1作为其控制点。
   *
   * @param[in] x1         x1坐标。坐标系为OFD坐标系。
   * @param[in] y1         y1坐标。坐标系为OFD坐标系。
   * @param[in] x2         x2坐标。坐标系为OFD坐标系。
   * @param[in] y2         y2坐标。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void QuadraticBezierTo(float x1, float y1, float x2, float y2);

  /**
   * @brief 从当前点连接一条到点pt3的三次贝塞尔曲线，并将当前点移动到点pt3，此贝塞尔曲线使用点pt1和点pt2作为其控制点。
   *
   * @param[in] x1         x1坐标。坐标系为OFD坐标系。
   * @param[in] y1         y1坐标。坐标系为OFD坐标系。
   * @param[in] x2         x2坐标。坐标系为OFD坐标系。
   * @param[in] y2         y2坐标。坐标系为OFD坐标系。
   * @param[in] x3         x3坐标。坐标系为OFD坐标系。
   * @param[in] y3         y3坐标。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void CubicBezierTo(float x1, float y1, float x2, float y2, float x3, float y3);

  /**
   * @brief 从当前点连接一条到点的圆弧，并将当前点移动到点。
   *
   * @param[in] arc_info      圆弧的信息。
   * @param[in] x             x坐标。坐标系为OFD坐标系。
   * @param[in] y             y坐标。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void ArcTo(EllipseInfo arc_info, float x, float y);

  /**
   * @brief 添加路径点数据集合。
   *
   * @param[in] points    路径点数据集合。坐标系为OFD坐标系。
   *
   * @return 无。
   */
  void AddPoints(PathPointArray& points);

  /**
   * @brief 自动闭合，表示将当前点和起始点用线段直接连接。
   *
   * @return 无。
   */
  void CloseFigure();

  /**
   * @brief 清空path操作。
   *
   * @return 无。
   */
  void ClearPath();

  /**
   * @brief 附加path操作。
   *
   * @param[in] path_append        路径数据对象。
   *
   * @return 无。
   */
  void AppendPath(const OFDPathData& path_append);

  /**
   * @brief 拷贝path。
   *
   * @param[in] path              路径数据对象。
   *
   * @return 无。
   */
  void CopyPath(const OFDPathData& path);

  /**
   * @brief 获取路径数据点个数。
   *
   * @return 路径数据点个数。
   */
  int GetPointCount();

  /**
   * @brief 获取指定索引的路径数据点。
   *
   * @param[in] index 路径数据点索引（从0开始）。有效范围：从0到(<i>count</i>-1)。
   *            <i>count</i> 由函数 @link OFDPathData::GetPointCount @endlink 返回。
   *
   * @return 指定索引的路径数据点。
   */
  PathPoint GetPoint(int index);

  explicit OFDPathData(FS_HANDLE handle);
};

}  // namespace graphics
}  // namespace ofd
}  // namespace foxit

#endif  // FS_OFD_PATHOBJECT_H_
