using System;
using UnityEngine;
using UnityEngine.Profiling;

// TODO: Find a way to break this the hell up.

// TODO: Normalize conventions away from Java-style SetX to properties.
public class SVGGraphicsStroke : ISVGPathDraw {
  private SVGGraphics _graphics;
  private SVGBasicDraw _basicDraw;
  private float _width;
  private bool isUseWidth = false;

  public SVGGraphicsStroke(SVGGraphics graphics) {
    _graphics = graphics;

    _basicDraw = new SVGBasicDraw();
    _basicDraw.SetPixelMethod = new SetPixelDelegate(SetPixel);
  }

  private void SetPixel(int x, int y) {
    _graphics.SetPixel(x, y);
  }

  //Ve Line Cap, dau cuoi Left
  private static Vector2[] rect_points = new Vector2[4];

  private void StrokeLineCapLeft(Vector2 p1, Vector2 p2, float width) {
    if((int)width == 1)
      return;
    if((_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Unknown) ||
        (_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Butt))
      return;
    if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
      return;
    if(_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Round) {
      _graphics.FillCircle(p1, width / 2f);
      return;
    }

    Vector2 _p1 = Vector2.zero;
    Vector2 _p2 = Vector2.zero;
    Vector2 _p3 = Vector2.zero;
    Vector2 _p4 = Vector2.zero;

    _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);

    Vector2 t_p1 = Vector2.zero;
    Vector2 t_p2 = Vector2.zero;
    Vector2 t_p3 = Vector2.zero;
    Vector2 t_p4 = Vector2.zero;

    _graphics.GetThickLine(_p2, _p1, width, ref t_p1, ref t_p2, ref t_p3, ref t_p4);

    rect_points[0] = t_p1;
    rect_points[1] = _p2;
    rect_points[2] = _p1;
    rect_points[3] = t_p3;
    _graphics.FillPolygon(rect_points);
  }

  //Ve Line Cap, dau cuoi Right
  private void StrokeLineCapRight(Vector2 p1, Vector2 p2, float width) {
    if((int)width == 1)
      return;
    if((_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Unknown) ||
        (_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Butt))
      return;

    if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
      return;
    if(_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Round) {
      _graphics.FillCircle(p2, width / 2f);
      return;
    }

    Vector2 _p1 = Vector2.zero;
    Vector2 _p2 = Vector2.zero;
    Vector2 _p3 = Vector2.zero;
    Vector2 _p4 = Vector2.zero;

    _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);

    Vector2 t_p1 = Vector2.zero;
    Vector2 t_p2 = Vector2.zero;
    Vector2 t_p3 = Vector2.zero;
    Vector2 t_p4 = Vector2.zero;

    _graphics.GetThickLine(_p4, _p3, width, ref t_p1, ref t_p2, ref t_p3, ref t_p4);

    rect_points[0] = _p4;
    rect_points[1] = t_p2;
    rect_points[2] = t_p4;
    rect_points[3] = _p3;
    _graphics.FillPolygon(rect_points);
  }

  private static Vector2[] joint_points = new Vector2[8],
  joint_points_small = new Vector2[6];

  private void StrokeLineJoin(Vector2 p1, Vector2 p2, Vector2 p3, float width) {
    if((int)width == 1)
      return;
    if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
      return;
    if(_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Round) {
      _graphics.FillCircle(p2, width / 2f);
      return;
    }

    if((_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Miter) ||
        (_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Unknown)) {
      Vector2 _p1 = Vector2.zero;
      Vector2 _p2 = Vector2.zero;
      Vector2 _p3 = Vector2.zero;
      Vector2 _p4 = Vector2.zero;

      _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);


      Vector2 _p5 = Vector2.zero;
      Vector2 _p6 = Vector2.zero;
      Vector2 _p7 = Vector2.zero;
      Vector2 _p8 = Vector2.zero;

      _graphics.GetThickLine(p2, p3, width, ref _p5, ref _p6, ref _p7, ref _p8);

      Vector2 _cp1, _cp2;
      _cp1 = _graphics.GetCrossPoint(_p1, _p3, _p5, _p7);
      _cp2 = _graphics.GetCrossPoint(_p2, _p4, _p6, _p8);


      //Vector2[] points = new Vector2[8];
      joint_points[0] = p2;
      joint_points[1] = _p3;
      joint_points[2] = _cp1;
      joint_points[3] = _p5;

      joint_points[4] = p2;
      joint_points[5] = _p6;
      joint_points[6] = _cp2;
      joint_points[7] = _p4;
      _graphics.FillPolygon(joint_points);
      return;
    }
    if(_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Bevel) {
      Vector2 _p1 = Vector2.zero;
      Vector2 _p2 = Vector2.zero;
      Vector2 _p3 = Vector2.zero;
      Vector2 _p4 = Vector2.zero;

      _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);


      Vector2 _p5 = Vector2.zero;
      Vector2 _p6 = Vector2.zero;
      Vector2 _p7 = Vector2.zero;
      Vector2 _p8 = Vector2.zero;

      _graphics.GetThickLine(p2, p3, width, ref _p5, ref _p6, ref _p7, ref _p8);

      joint_points_small[0] = p2;
      joint_points_small[1] = _p3;
      joint_points_small[2] = _p5;

      joint_points_small[3] = p2;
      joint_points_small[4] = _p6;
      joint_points_small[5] = _p4;
      _graphics.FillPolygon(joint_points_small);
      return;
    }
  }

  public void MoveTo(Vector2 p) {
    _basicDraw.MoveTo(p);
  }

  public void CircleTo(Vector2 p, float r) {
    if((isUseWidth) && ((int)_width > 1)) {
      CircleTo(p, r, _width);
      return;
    }
    Circle(p, r);
  }

  // TODO: Kill this method.
  public void CircleTo(Vector2 p, float r, float width) {
    Circle(p, r, width);
  }

  public void EllipseTo(Vector2 p, float r1, float r2, float angle) {
    if((isUseWidth) && ((int)_width > 1)) {
      EllipseTo(p, r1, r2, angle, _width);
      return;
    }
    Ellipse(p, r1, r2, angle);
  }

  public void EllipseTo(Vector2 p, float r1, float r2, float angle, float width) {
    Ellipse(p, r1, r2, angle, width);
  }

  public void ArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p) {
    if((isUseWidth) && ((int)_width > 1))
      ArcTo(r1, r2, angle, largeArcFlag, sweepFlag, p, _width);
    else
      _basicDraw.ArcTo(r1, r2, angle, largeArcFlag, sweepFlag, p);
  }

  public void ArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p, float width) {
    Profiler.BeginSample("SVGGraphicsStroke.ArcTo");
    float rx = r1, ry = r2;
    Vector2 p1 = _basicDraw.currentPoint, p2 = p;

    float _radian = (angle * Mathf.PI / 180.0f);
    // TODO: Do we have single-precision methods we can use here?  How's the performance?
    float _CosRadian = (float)Math.Cos(_radian);
    float _SinRadian = (float)Math.Sin(_radian);
    float temp1 = (p1.x - p2.x) / 2.0f;
    float temp2 = (p1.y - p2.y) / 2.0f;
    float tx = (_CosRadian * temp1) + (_SinRadian * temp2);
    float ty = (-_SinRadian * temp1) + (_CosRadian * temp2);

    double trx2 = rx * rx;
    double try2 = ry * ry;
    double tx2 = tx * tx;
    double ty2 = ty * ty;


    double radiiCheck = tx2 / trx2 + ty2 / try2;
    if(radiiCheck > 1) {
      rx = (float)Math.Sqrt((float)radiiCheck) * rx;
      ry = (float)Math.Sqrt((float)radiiCheck) * ry;
      trx2 = rx * rx;
      try2 = ry * ry;
    }

    double tm1 = (trx2 * try2 - trx2 * ty2 - try2 * tx2) / (trx2 * ty2 + try2 * tx2);
    tm1 = (tm1 < 0) ? 0 : tm1;

    float tm2 = (largeArcFlag == sweepFlag) ? -(float)Math.Sqrt((float)tm1) : (float)Math.Sqrt((float)tm1);

    float tcx = tm2 * ((rx * ty) / ry);
    float tcy = tm2 * (-(ry * tx) / rx);

    float cx = _CosRadian * tcx - _SinRadian * tcy + ((p1.x + p2.x) / 2.0f);
    float cy = _SinRadian * tcx + _CosRadian * tcy + ((p1.y + p2.y) / 2.0f);

    float ux = (tx - tcx) / rx;
    float uy = (ty - tcy) / ry;
    float vx = (-tx - tcx) / rx;
    float vy = (-ty - tcy) / ry;

    float tp, n;
    n = (float)Math.Sqrt((ux * ux) + (uy * uy));
    tp = ux;
    float _angle = (uy < 0) ? -(float)Math.Acos(tp / n) : (float)Math.Acos(tp / n);
    _angle = _angle * 180.0f / Mathf.PI;
    _angle %= 360f;

    n = (float)Math.Sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
    tp = ux * vx + uy * vy;
    float _delta = (ux * vy - uy * vx < 0) ? -(float)Math.Acos(tp / n) : (float)Math.Acos(tp / n);
    _delta = _delta * 180.0f / Mathf.PI;

    if(!sweepFlag && _delta > 0)
      _delta -= 360f;
    else if(sweepFlag && _delta < 0)
      _delta += 360f;

    _delta %= 360f;

    int number = 50;
    float deltaT = _delta / number;
    //---Get Control Point
    Vector2 _controlPoint1 = Vector2.zero;
    Vector2 _controlPoint2 = Vector2.zero;

    for(int i = 0; i <= number; i++) {
      float t_angle = (deltaT * i + _angle) * Mathf.PI / 180.0f;
      _controlPoint1.x = _CosRadian * rx * (float)Math.Cos(t_angle) - _SinRadian * ry * (float)Math.Sin(t_angle) + cx;
      _controlPoint1.y = _SinRadian * rx * (float)Math.Cos(t_angle) + _CosRadian * ry * (float)Math.Sin(t_angle) + cy;
      if((_controlPoint1.x != p1.x) && (_controlPoint1.y != p1.y))
        i = number + 1;
    }


    for(int i = number; i >= 0; i--) {
      float t_angle = (deltaT * i + _angle) * Mathf.PI / 180.0f;
      _controlPoint2.x = _CosRadian * rx * (float)Math.Cos(t_angle) - _SinRadian * ry * (float)Math.Sin(t_angle) + cx;
      _controlPoint2.y = _SinRadian * rx * (float)Math.Cos(t_angle) + _CosRadian * ry * (float)Math.Sin(t_angle) + cy;
      if((_controlPoint2.x != p2.x) && (_controlPoint2.y != p2.y))
        i = -1;
    }
    //-----
    Vector2 _p1 = Vector2.zero;
    Vector2 _p2 = Vector2.zero;
    Vector2 _p3 = Vector2.zero;
    Vector2 _p4 = Vector2.zero;

    _graphics.GetThickLine(p1, _controlPoint1, width, ref _p1, ref _p2, ref _p3, ref _p4);

    Vector2 _p5 = Vector2.zero;
    Vector2 _p6 = Vector2.zero;
    Vector2 _p7 = Vector2.zero;
    Vector2 _p8 = Vector2.zero;

    _graphics.GetThickLine(_controlPoint2, p2, width, ref _p5, ref _p6, ref _p7, ref _p8);

    float _half = width / 2f;
    float _ihalf1 = _half;
    float _ihalf2 = width - _ihalf1 + 0.5f;
    //-----

    float t_len1 = (_p1.x - cx) * (_p1.x - cx) + (_p1.y - cy) * (_p1.y - cy);
    float t_len2 = (_p2.x - cx) * (_p2.x - cx) + (_p2.y - cy) * (_p2.y - cy);

    Vector2 tempPoint;
    if(t_len1 > t_len2) {
      tempPoint = _p1;
      _p1 = _p2;
      _p2 = tempPoint;
    }

    t_len1 = (_p7.x - cx) * (_p7.x - cx) + (_p7.y - cy) * (_p7.y - cy);
    t_len2 = (_p8.x - cx) * (_p8.x - cx) + (_p8.y - cy) * (_p8.y - cy);

    if(t_len1 > t_len2) {
      tempPoint = _p7;
      _p7 = _p8;
      _p8 = tempPoint;
    }

    Profiler.BeginSample("SVGGraphicsStroke.ArcTo[CreateGraphicsPath]");
    SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
    _graphicsPath.AddMoveTo(_p2);
    _graphicsPath.AddArcTo(r1 + _ihalf1, r2 + _ihalf1, angle, largeArcFlag, sweepFlag, _p8);
    _graphicsPath.AddLineTo(_p7);
    _graphicsPath.AddArcTo(r1 - _ihalf2, r2 - _ihalf2, angle, largeArcFlag, !sweepFlag, _p1);
    _graphicsPath.AddLineTo(_p2);
    Profiler.EndSample();
    Profiler.BeginSample("SVGGraphicsStroke.ArcTo[FillPath]");
    _graphics.FillPath(_graphicsPath);
    Profiler.EndSample();
    MoveTo(p);
    Profiler.EndSample();
  }

  public void CubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p) {
    if((isUseWidth) && ((int)_width > 1)) {
      CubicCurveTo(p1, p2, p, _width);
      return;
    }
    _basicDraw.CubicCurveTo(p1, p2, p);
  }

  public void CubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p, float width) {
    Vector2 _point = Vector2.zero;
    _point = _basicDraw.currentPoint;

    Vector2 _p1 = Vector2.zero;
    Vector2 _p2 = Vector2.zero;
    Vector2 _p3 = Vector2.zero;
    Vector2 _p4 = Vector2.zero;

    bool temp;
    temp = _graphics.GetThickLine(_point, p1, width, ref _p1, ref _p2, ref _p3, ref _p4);
    if(temp == false) {
      QuadraticCurveTo(p2, p, width);
      return;
    }

    Vector2 _p5 = Vector2.zero;
    Vector2 _p6 = Vector2.zero;
    Vector2 _p7 = Vector2.zero;
    Vector2 _p8 = Vector2.zero;

    _graphics.GetThickLine(p1, p2, width, ref _p5, ref _p6, ref _p7, ref _p8);

    Vector2 _p9 = Vector2.zero;
    Vector2 _p10 = Vector2.zero;
    Vector2 _p11 = Vector2.zero;
    Vector2 _p12 = Vector2.zero;

    _graphics.GetThickLine(p2, p, width, ref _p9, ref _p10, ref _p11, ref _p12);

    Vector2 _cp1, _cp2, _cp3, _cp4;
    _cp1 = _graphics.GetCrossPoint(_p1, _p3, _p5, _p7);
    _cp2 = _graphics.GetCrossPoint(_p2, _p4, _p6, _p8);
    _cp3 = _graphics.GetCrossPoint(_p5, _p7, _p9, _p11);
    _cp4 = _graphics.GetCrossPoint(_p6, _p8, _p10, _p12);

    _basicDraw.MoveTo(_point);
    _basicDraw.CubicCurveTo(p1, p2, p);

    SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
    _graphicsPath.AddMoveTo(_p2);
    _graphicsPath.AddCubicCurveTo(_cp2, _cp4, _p12);
    _graphicsPath.AddLineTo(_p11);
    _graphicsPath.AddCubicCurveTo(_cp3, _cp1, _p1);
    _graphicsPath.AddLineTo(_p2);
    _graphics.FillPath(_graphicsPath);

    MoveTo(p);
  }

  public void QuadraticCurveTo(Vector2 p1, Vector2 p) {
    if((isUseWidth) && ((int)_width > 1)) {
      QuadraticCurveTo(p1, p, _width);
      return;
    }
    _basicDraw.QuadraticCurveTo(p1, p);
  }

  public void QuadraticCurveTo(Vector2 p1, Vector2 p, float width) {
    Vector2 _point = Vector2.zero;
    _point = _basicDraw.currentPoint;

    Vector2 _p1 = Vector2.zero;
    Vector2 _p2 = Vector2.zero;
    Vector2 _p3 = Vector2.zero;
    Vector2 _p4 = Vector2.zero;

    _graphics.GetThickLine(_point, p1, width, ref _p1, ref _p2, ref _p3, ref _p4);

    Vector2 _p5 = Vector2.zero;
    Vector2 _p6 = Vector2.zero;
    Vector2 _p7 = Vector2.zero;
    Vector2 _p8 = Vector2.zero;

    _graphics.GetThickLine(p1, p, width, ref _p5, ref _p6, ref _p7, ref _p8);

    Vector2 _cp1, _cp2;
    _cp1 = _graphics.GetCrossPoint(_p1, _p3, _p5, _p7);
    _cp2 = _graphics.GetCrossPoint(_p2, _p4, _p6, _p8);

    SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
    _graphicsPath.AddMoveTo(_p2);
    _graphicsPath.AddQuadraticCurveTo(_cp2, _p8);
    _graphicsPath.AddLineTo(_p7);
    _graphicsPath.AddQuadraticCurveTo(_cp1, _p1);
    _graphicsPath.AddLineTo(_p2);
    _graphics.FillPath(_graphicsPath);

    MoveTo(p);
  }

  public void LineTo(Vector2 p) {
    if((isUseWidth) && ((int)_width > 1)) {
      LineTo(p, _width);
      return;
    }
    _basicDraw.LineTo(p);
  }

  public void LineTo(Vector2 p, float width) {
    Vector2 _point = Vector2.zero;
    _point = _basicDraw.currentPoint;
    Line(_point, p, width);
    MoveTo(p);
  }

  public void Line(Vector2 p1, Vector2 p2) {
    if((isUseWidth) && ((int)_width > 1)) {
      Line(p1, p2, _width);
      return;
    }
    _basicDraw.Line(p1, p2);
  }

  public void Line(Vector2 p1, Vector2 p2, float width) {
    if((int)width == 1)
      Line(p1, p2);
    else {
      if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
        return;
      StrokeLineCapLeft(p1, p2, width);
      StrokeLineCapRight(p1, p2, width);
      Vector2 _p1 = Vector2.zero;
      Vector2 _p2 = Vector2.zero;
      Vector2 _p3 = Vector2.zero;
      Vector2 _p4 = Vector2.zero;

      _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);

      Vector2[] points = new Vector2[4];
      points[0] = _p1;
      points[1] = _p3;
      points[2] = _p4;
      points[3] = _p2;
      _graphics.FillPolygon(points);
    }
  }

  public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) {
    if((isUseWidth) && ((int)_width > 1)) {
      Rect(p1, p2, p3, p4, _width);
      return;
    }
    _basicDraw.Rect(p1, p2, p3, p4);
  }

  public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float width) {
    if((int)width == 1)
      Rect(p1, p2, p3, p4);
    //Vector2[] points = new Vector2[4];
    rect_points[0] = p1;
    rect_points[1] = p2;
    rect_points[2] = p3;
    rect_points[3] = p4;
    Polygon(rect_points, width);
  }

  public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
                          float r1, float r2,
                          float angle) {
    if((isUseWidth) && ((int)_width > 1)) {
      RoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
                  angle, _width);
      return;
    }
    _basicDraw.MoveTo(p1);
    _basicDraw.LineTo(p2);
    _basicDraw.ArcTo(r1, r2, angle, false, true, p3);

    _basicDraw.MoveTo(p3);
    _basicDraw.LineTo(p4);
    _basicDraw.ArcTo(r1, r2, angle, false, true, p5);

    _basicDraw.MoveTo(p5);
    _basicDraw.LineTo(p6);
    _basicDraw.ArcTo(r1, r2, angle, false, true, p7);

    _basicDraw.MoveTo(p7);
    _basicDraw.LineTo(p8);
    _basicDraw.ArcTo(r1, r2, angle, false, true, p1);
  }

  public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
                          float r1, float r2,
                          float angle, float width) {
    if((int)width == 1) {
      RoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
                  angle);
      return;
    }

    Line(p1, p2, width);
    Line(p3, p4, width);
    Line(p5, p6, width);
    Line(p7, p8, width);
    // TODO: IIRC, `Vector2.zero` is a p/invoke.  Would it be safe to chain assignments here?  Would it be more
    // TODO: performant?  What about just calling `new Vector2(0f, 0f)`?
    Vector2 _p1 = Vector2.zero;
    Vector2 _p2 = Vector2.zero;
    Vector2 _p3 = Vector2.zero;
    Vector2 _p4 = Vector2.zero;

    _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);

    Vector2 _p5 = Vector2.zero;
    Vector2 _p6 = Vector2.zero;
    Vector2 _p7 = Vector2.zero;
    Vector2 _p8 = Vector2.zero;

    //-------
    _graphics.GetThickLine(p3, p4, width, ref _p5, ref _p6, ref _p7, ref _p8);

    SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();

    _graphicsPath.AddMoveTo(_p4);
    _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p6);
    _graphicsPath.AddLineTo(_p5);
    _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p3);
    _graphicsPath.AddLineTo(_p4);


    _graphics.FillPath(_graphicsPath);

    //-------
    _graphics.GetThickLine(p5, p6, width, ref _p1, ref _p2, ref _p3, ref _p4);

    _graphicsPath.Reset();
    _graphicsPath.AddMoveTo(_p8);
    _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p2);
    _graphicsPath.AddLineTo(_p1);
    _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p7);
    _graphicsPath.AddLineTo(_p8);

    _graphics.FillPath(_graphicsPath);

    //----------
    _graphics.GetThickLine(p7, p8, width, ref _p5, ref _p6, ref _p7, ref _p8);

    _graphicsPath.Reset();
    _graphicsPath.AddMoveTo(_p4);
    _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p6);
    _graphicsPath.AddLineTo(_p5);
    _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p3);
    _graphicsPath.AddLineTo(_p4);

    _graphics.FillPath(_graphicsPath);

    //-------
    _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);

    _graphicsPath.Reset();
    _graphicsPath.AddMoveTo(_p8);
    _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p2);
    _graphicsPath.AddLineTo(_p1);
    _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p7);
    _graphicsPath.AddLineTo(_p8);

    _graphics.FillPath(_graphicsPath);
  }

  public void Circle(Vector2 p, float r) {
    if((isUseWidth) && ((int)_width > 1)) {
      Circle(p, r, _width);
      return;
    }
    _basicDraw.Circle(p, r);
  }

  public void Circle(Vector2 p, float r, float width) {
    if((int)width == 1)
      Circle(p, r);
    else {
      int r1 = (int)(width / 2f);
      int r2 = (int)width - r1;

      //Vector2[] _points = new Vector2[1];
      //_points[0] = new Vector2(p.x, p.y);

      SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
      _graphicsPath.AddCircleTo(p, r + r1);
      _graphicsPath.AddCircleTo(p, r - r2);

      _graphics.FillPath(_graphicsPath, p);
    }
  }

  public void Ellipse(Vector2 p, float rx, float ry, float angle) {
    if((isUseWidth) && ((int)_width > 1)) {
      Ellipse(p, rx, ry, angle, _width);
      return;
    }
    _basicDraw.Ellipse(p, rx, ry, angle);
  }

  public void Ellipse(Vector2 p, float rx, float ry, float angle, float width) {
    if((int)width == 1)
      Ellipse(p, rx, ry, angle);
    else {
      int r1 = (int)(width / 2f);
      int r2 = (int)width - r1;

      //Vector2[] _points = new Vector2[1] { p };

      SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
      _graphicsPath.AddEllipseTo(p, rx + r1, ry + r1, angle);
      _graphicsPath.AddEllipseTo(p, rx - r2, ry - r2, angle);

      _graphics.FillPath(_graphicsPath, p);
    }
  }

  public void Polygon(Vector2[] points) {
    if((isUseWidth) && ((int)_width > 1)) {
      Polygon(points, _width);
      return;
    }

    int _length = points.GetLength(0);
    if(_length > 1) {
      _basicDraw.MoveTo(points[0]);
      for(int i = 1; i < _length; i++)
        _basicDraw.LineTo(points[i]);
      _basicDraw.LineTo(points[0]);
    }
  }

  public void Polygon(Vector2[] points, float width) {
    if((int)width == 1) {
      Polygon(points);
      return;
    }
    int _length = points.GetLength(0);
    if(_length > 1) {
      if(_length == 2) {
        Line(points[0], points[1], width);
        StrokeLineCapLeft(points[0], points[1], width);
        StrokeLineCapRight(points[0], points[1], width);
      } else if(_length > 2) {
        StrokeLineJoin(points[_length - 1], points[0], points[1], width);
        Line(points[0], points[1], width);

        StrokeLineJoin(points[_length - 2], points[_length - 1], points[0], width);
        Line(points[_length - 1], points[0], width);
        for(int i = 1; i < _length - 1; i++) {
          StrokeLineJoin(points[i - 1], points[i], points[i + 1], width);
          Line(points[i], points[i + 1], width);
        }
      }
    }
  }

  public void DrawPath(SVGGraphicsPath graphicsPath) {
    graphicsPath.RenderPath(this, false);
  }

  //Fill co Stroke trong do luon
  public void DrawPath(SVGGraphicsPath graphicsPath, float width) {
    _width = width;
    isUseWidth = true;
    graphicsPath.RenderPath(this, false);
    isUseWidth = false;
  }
}