import 'package:flutter/material.dart';

enum MeasureCursorType {
  cursor01,
  cursor02,
  cursor03,
  cursor04,
  cursor05,
}

class MeasureCursor extends StatelessWidget {
  const MeasureCursor({
    Key? key,
    required this.type,
    required this.size,
    this.color,
  }) : super(key: key);

  final double size;

  final MeasureCursorType type;

  final Color? color;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: size,
      height: size,
      child: RepaintBoundary(
        child: CustomPaint(painter: _CursorPainter(type, color: color)),
      ),
    );
  }
}

class _CursorPainter extends CustomPainter {
  const _CursorPainter(this.type, {this.color});

  final MeasureCursorType type;

  final Color? color;

  @override
  void paint(Canvas canvas, Size size) {
    final double width = size.width;
    final double offset = width / 2;
    // position center point
    canvas.translate(offset, offset);

    _CursorPathGeometry(
      cursorType: type,
      offset: offset,
      color: color,
    ).draw(canvas);
  }

  @override
  bool shouldRepaint(covariant _CursorPainter oldDelegate) {
    return oldDelegate.color != color || oldDelegate.type != type;
  }
}

class _CursorPathGeometry {
  _CursorPathGeometry({
    required double offset,
    required this.cursorType,
    this.color,
  }) {
    _offset = offset;
    _paint = Paint()
      ..color = color ?? const Color.fromARGB(255, 255, 255, 0)
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;

    _assemblePathArray();
  }

  // ignore: constant_identifier_names
  static const double LINE_RATIO = 0.8;

  late final Paint _paint;

  late double _offset;

  final MeasureCursorType cursorType;

  final Color? color;

  final List<Path> _pathArray = <Path>[];

  List<Path> get pathArray => _pathArray;

  void draw(Canvas canvas) {
    canvas.save();
    for (final Path path in _pathArray) {
      canvas.drawPath(path, _paint);
    }
    canvas.restore();
  }

  void _assemblePathArray() {
    switch (cursorType) {
      case MeasureCursorType.cursor01:
        _pathArray.add(_buildHorizontalLine());
        _pathArray.add(_buildVerticalLine());
        break;
      case MeasureCursorType.cursor02:
        _pathArray.add(_buildLeftBias());
        _pathArray.add(_buildRightBias());
        break;
      case MeasureCursorType.cursor03:
        _pathArray.add(_buildHorizontalLine());
        _pathArray.add(_buildLeftBias());
        _pathArray.add(_buildRightBias());
        break;
      case MeasureCursorType.cursor04:
        _pathArray.add(_buildVerticalLine());
        _pathArray.add(_buildLeftBias());
        _pathArray.add(_buildRightBias());
        break;
      case MeasureCursorType.cursor05:
        _pathArray.add(_buildLeftSide());
        _pathArray.add(_buildRightSide());
        _pathArray.add(_buildTopSide());
        _pathArray.add(_buildBottomSide());
        _offset *= LINE_RATIO;
        _pathArray.add(_buildHorizontalLine());
        _pathArray.add(_buildVerticalLine());
        break;
    }
  }

  Path _buildHorizontalLine() {
    return Path()
      ..moveTo(-_offset, 0)
      ..lineTo(_offset, 0);
  }

  Path _buildVerticalLine() {
    return Path()
      ..moveTo(0, -_offset)
      ..lineTo(0, _offset);
  }

  Path _buildLeftBias() {
    return Path()
      ..moveTo(-_offset, -_offset)
      ..lineTo(_offset, _offset);
  }

  Path _buildRightBias() {
    return Path()
      ..moveTo(_offset, -_offset)
      ..lineTo(-_offset, _offset);
  }

  Path _buildLeftSide() {
    return Path()
      ..moveTo(-_offset, -_offset * LINE_RATIO)
      ..lineTo(-_offset, _offset * LINE_RATIO);
  }

  Path _buildRightSide() {
    return Path()
      ..moveTo(_offset, -_offset * LINE_RATIO)
      ..lineTo(_offset, _offset * LINE_RATIO);
  }

  Path _buildTopSide() {
    return Path()
      ..moveTo(-_offset * LINE_RATIO, -_offset)
      ..lineTo(_offset * LINE_RATIO, -_offset);
  }

  Path _buildBottomSide() {
    return Path()
      ..moveTo(-_offset * LINE_RATIO, _offset)
      ..lineTo(_offset * LINE_RATIO, _offset);
  }
}
