// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: camel_case_types
import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:typed_data';

/// Determines the winding rule that decides how the interior of a Path is
/// calculated.
///
/// This enum is used by the [VerticesBuilder.tessellate] method.
// must match ordering in geometry/path.h
enum FillType {
  /// The interior is defined by a non-zero sum of signed edge crossings.
  nonZero,

  /// The interior is defined by an odd number of edge crossings.
  evenOdd,
}

/// Information about how to approximate points on a curved path segment.
///
/// In particular, the values in this object control how many vertices to
/// generate when approximating curves, and what tolerances to use when
/// calculating the sharpness of curves.
///
/// Used by [VerticesBuilder.tessellate].
class SmoothingApproximation {
  /// Creates a new smoothing approximation instance with default values.
  const SmoothingApproximation({
    this.scale = 1.0,
    this.angleTolerance = 0.0,
    this.cuspLimit = 0.0,
  });

  /// The scaling coefficient to use when translating to screen coordinates.
  ///
  /// Values approaching 0.0 will generate smoother looking curves with a
  /// greater number of vertices, and will be more expensive to calculate.
  final double scale;

  /// The tolerance value in radians for calculating sharp angles.
  ///
  /// Values approaching 0.0 will provide more accurate approximation of sharp
  /// turns. A 0.0 value means angle conditions are not considered at all.
  final double angleTolerance;

  /// An angle in radians at which to introduce bevel cuts.
  ///
  /// Values greater than zero will restirct the sharpness of bevel cuts on
  /// turns.
  final double cuspLimit;
}

/// Creates vertices from path commands.
///
/// First, build up the path contours with the [moveTo], [lineTo], [cubicTo],
/// and [close] methods. All methods expect absolute coordinates.
///
/// Then, use the [tessellate] method to create a [Float32List] of vertex pairs.
///
/// Finally, use the [dispose] method to clean up native resources. After
/// [dispose] has been called, this class must not be used again.
class VerticesBuilder {
  VerticesBuilder() : _builder = _createPathFn();

  ffi.Pointer<_PathBuilder>? _builder;
  final List<ffi.Pointer<_Vertices>> _vertices = <ffi.Pointer<_Vertices>>[];

  /// Adds a move verb to the absolute coordinates x,y.
  void moveTo(double x, double y) {
    assert(_builder != null);
    _moveToFn(_builder!, x, y);
  }

  /// Adds a line verb to the absolute coordinates x,y.
  void lineTo(double x, double y) {
    assert(_builder != null);
    _lineToFn(_builder!, x, y);
  }

  /// Adds a cubic Bezier curve with x1,y1 as the first control point, x2,y2 as
  /// the second control point, and end point x3,y3.
  void cubicTo(
    double x1,
    double y1,
    double x2,
    double y2,
    double x3,
    double y3,
  ) {
    assert(_builder != null);
    _cubicToFn(_builder!, x1, y1, x2, y2, x3, y3);
  }

  /// Adds a close command to the start of the current contour.
  void close() {
    assert(_builder != null);
    closeFn(_builder!, true);
  }

  /// Tessellates the path created by the previous method calls into a list of
  /// vertices.
  Float32List tessellate({
    FillType fillType = FillType.nonZero,
    SmoothingApproximation smoothing = const SmoothingApproximation(),
  }) {
    assert(_vertices.isEmpty);
    assert(_builder != null);
    final ffi.Pointer<_Vertices> vertices = _tessellateFn(
      _builder!,
      fillType.index,
      smoothing.scale,
      smoothing.angleTolerance,
      smoothing.cuspLimit,
    );
    _vertices.add(vertices);
    return vertices.ref.points.asTypedList(vertices.ref.size);
  }

  /// Releases native resources.
  ///
  /// After calling dispose, this class must not be used again.
  void dispose() {
    assert(_builder != null);
    _vertices.forEach(_destroyVerticesFn);
    _destroyFn(_builder!);
    _vertices.clear();
    _builder = null;
  }
}

// TODO(dnfield): Figure out where to put this.
// https://github.com/flutter/flutter/issues/99563
final ffi.DynamicLibrary _dylib = () {
  if (Platform.isWindows) {
    return ffi.DynamicLibrary.open('tessellator.dll');
  } else if (Platform.isIOS || Platform.isMacOS) {
    return ffi.DynamicLibrary.open('libtessellator.dylib');
  } else if (Platform.isAndroid || Platform.isLinux) {
    return ffi.DynamicLibrary.open('libtessellator.so');
  }
  throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
}();

class _Vertices extends ffi.Struct {
  external ffi.Pointer<ffi.Float> points;

  @ffi.Uint32()
  external int size;
}

class _PathBuilder extends ffi.Opaque {}

typedef _CreatePathBuilderType = ffi.Pointer<_PathBuilder> Function();
typedef _create_path_builder_type = ffi.Pointer<_PathBuilder> Function();

final _CreatePathBuilderType _createPathFn =
    _dylib.lookupFunction<_create_path_builder_type, _CreatePathBuilderType>(
  'CreatePathBuilder',
);

typedef _MoveToType = void Function(ffi.Pointer<_PathBuilder>, double, double);
typedef _move_to_type = ffi.Void Function(
  ffi.Pointer<_PathBuilder>,
  ffi.Float,
  ffi.Float,
);

final _MoveToType _moveToFn = _dylib.lookupFunction<_move_to_type, _MoveToType>(
  'MoveTo',
);

typedef _LineToType = void Function(ffi.Pointer<_PathBuilder>, double, double);
typedef _line_to_type = ffi.Void Function(
  ffi.Pointer<_PathBuilder>,
  ffi.Float,
  ffi.Float,
);

final _LineToType _lineToFn = _dylib.lookupFunction<_line_to_type, _LineToType>(
  'LineTo',
);

typedef _CubicToType = void Function(
  ffi.Pointer<_PathBuilder>,
  double,
  double,
  double,
  double,
  double,
  double,
);
typedef _cubic_to_type = ffi.Void Function(
  ffi.Pointer<_PathBuilder>,
  ffi.Float,
  ffi.Float,
  ffi.Float,
  ffi.Float,
  ffi.Float,
  ffi.Float,
);

final _CubicToType _cubicToFn =
    _dylib.lookupFunction<_cubic_to_type, _CubicToType>('CubicTo');

typedef _CloseType = void Function(ffi.Pointer<_PathBuilder>, bool);
typedef _close_type = ffi.Void Function(ffi.Pointer<_PathBuilder>, ffi.Bool);

final _CloseType closeFn =
    _dylib.lookupFunction<_close_type, _CloseType>('Close');

typedef _TessellateType = ffi.Pointer<_Vertices> Function(
  ffi.Pointer<_PathBuilder>,
  int,
  double,
  double,
  double,
);
typedef _tessellate_type = ffi.Pointer<_Vertices> Function(
  ffi.Pointer<_PathBuilder>,
  ffi.Int,
  ffi.Float,
  ffi.Float,
  ffi.Float,
);

final _TessellateType _tessellateFn =
    _dylib.lookupFunction<_tessellate_type, _TessellateType>('Tessellate');

typedef _DestroyType = void Function(ffi.Pointer<_PathBuilder>);
typedef _destroy_type = ffi.Void Function(ffi.Pointer<_PathBuilder>);

final _DestroyType _destroyFn =
    _dylib.lookupFunction<_destroy_type, _DestroyType>(
  'DestroyPathBuilder',
);

typedef _DestroyVerticesType = void Function(ffi.Pointer<_Vertices>);
typedef _destroy_vertices_type = ffi.Void Function(ffi.Pointer<_Vertices>);

final _DestroyVerticesType _destroyVerticesFn =
    _dylib.lookupFunction<_destroy_vertices_type, _DestroyVerticesType>(
  'DestroyVertices',
);
