// Copyright 2014 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.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

enum _DragTarget {
  start,
  end
}

// How close a drag's start position must be to the target point. This is
// a distance squared.
const double _kTargetSlop = 2500.0;

// Used by the Painter classes.
const double _kPointRadius = 6.0;

class _DragHandler extends Drag {
  _DragHandler(this.onUpdate, this.onCancel, this.onEnd);

  final GestureDragUpdateCallback onUpdate;
  final GestureDragCancelCallback onCancel;
  final GestureDragEndCallback onEnd;

  @override
  void update(DragUpdateDetails details) {
    onUpdate(details);
  }

  @override
  void cancel() {
    onCancel();
  }

  @override
  void end(DragEndDetails details) {
    onEnd(details);
  }
}

class _IgnoreDrag extends Drag {
}

class _PointDemoPainter extends CustomPainter {
  _PointDemoPainter({
    Animation<double>? repaint,
    required this.arc,
  }) : _repaint = repaint, super(repaint: repaint);

  final MaterialPointArcTween arc;
  final Animation<double>? _repaint;

  void drawPoint(Canvas canvas, Offset point, Color color) {
    final Paint paint = Paint()
      ..color = color.withOpacity(0.25)
      ..style = PaintingStyle.fill;
    canvas.drawCircle(point, _kPointRadius, paint);
    paint
      ..color = color
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2.0;
    canvas.drawCircle(point, _kPointRadius + 1.0, paint);
  }

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint();

    if (arc.center != null) {
      drawPoint(canvas, arc.center!, Colors.grey.shade400);
    }

    paint
      ..isAntiAlias = false // Work-around for github.com/flutter/flutter/issues/5720
      ..color = Colors.green.withOpacity(0.25)
      ..strokeWidth = 4.0
      ..style = PaintingStyle.stroke;
    if (arc.center != null && arc.radius != null) {
      canvas.drawCircle(arc.center!, arc.radius!, paint);
    } else {
      canvas.drawLine(arc.begin!, arc.end!, paint);
    }

    drawPoint(canvas, arc.begin!, Colors.green);
    drawPoint(canvas, arc.end!, Colors.red);

    paint
      ..color = Colors.green
      ..style = PaintingStyle.fill;
    canvas.drawCircle(arc.lerp(_repaint!.value), _kPointRadius, paint);
  }

  @override
  bool hitTest(Offset position) {
    return (arc.begin! - position).distanceSquared < _kTargetSlop
        || (arc.end! - position).distanceSquared < _kTargetSlop;
  }

  @override
  bool shouldRepaint(_PointDemoPainter oldPainter) => arc != oldPainter.arc;
}

class _PointDemo extends StatefulWidget {
  const _PointDemo({ super.key, required this.controller });

  final AnimationController controller;

  @override
  _PointDemoState createState() => _PointDemoState();
}

class _PointDemoState extends State<_PointDemo> {
  final GlobalKey _painterKey = GlobalKey();

  CurvedAnimation? _animation;
  _DragTarget? _dragTarget;
  Size? _screenSize;
  Offset? _begin;
  Offset? _end;

  @override
  void initState() {
    super.initState();
    _animation = CurvedAnimation(parent: widget.controller, curve: Curves.fastOutSlowIn);
  }

  @override
  void dispose() {
    widget.controller.value = 0.0;
    super.dispose();
  }

  Drag _handleOnStart(Offset position) {
    // TODO(hansmuller): allow the user to drag both points at the same time.
    if (_dragTarget != null) {
      return _IgnoreDrag();
    }

    final RenderBox? box = _painterKey.currentContext!.findRenderObject() as RenderBox?;
    final double startOffset = (box!.localToGlobal(_begin!) - position).distanceSquared;
    final double endOffset = (box.localToGlobal(_end!) - position).distanceSquared;
    setState(() {
      if (startOffset < endOffset && startOffset < _kTargetSlop) {
        _dragTarget = _DragTarget.start;
      } else if (endOffset < _kTargetSlop) {
        _dragTarget = _DragTarget.end;
      } else {
        _dragTarget = null;
      }
    });

    return _DragHandler(_handleDragUpdate, _handleDragCancel, _handleDragEnd);
  }

  void _handleDragUpdate(DragUpdateDetails details) {
    switch (_dragTarget!) {
      case _DragTarget.start:
        setState(() {
          _begin = _begin! + details.delta;
        });
        break;
      case _DragTarget.end:
        setState(() {
          _end = _end! + details.delta;
        });
        break;
    }
  }

  void _handleDragCancel() {
    _dragTarget = null;
    widget.controller.value = 0.0;
  }

  void _handleDragEnd(DragEndDetails details) {
    _dragTarget = null;
  }

  @override
  Widget build(BuildContext context) {
    final Size screenSize = MediaQuery.of(context).size;
    if (_screenSize == null || _screenSize != screenSize) {
      _screenSize = screenSize;
      _begin = Offset(screenSize.width * 0.5, screenSize.height * 0.2);
      _end = Offset(screenSize.width * 0.1, screenSize.height * 0.4);
    }

    final MaterialPointArcTween arc = MaterialPointArcTween(begin: _begin, end: _end);
    return RawGestureDetector(
      behavior: _dragTarget == null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque,
      gestures: <Type, GestureRecognizerFactory>{
        ImmediateMultiDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<ImmediateMultiDragGestureRecognizer>(
          () => ImmediateMultiDragGestureRecognizer(),
          (ImmediateMultiDragGestureRecognizer instance) {
            instance.onStart = _handleOnStart;
          },
        ),
      },
      child: ClipRect(
        child: CustomPaint(
          key: _painterKey,
          foregroundPainter: _PointDemoPainter(
            repaint: _animation,
            arc: arc,
          ),
          // Watch out: if this IgnorePointer is left out, then gestures that
          // fail _PointDemoPainter.hitTest() will still be recognized because
          // they do overlap this child, which is as big as the CustomPaint.
          child: IgnorePointer(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Text(
                'Tap the refresh button to run the animation. Drag the green '
                "and red points to change the animation's path.",
                style: Theme.of(context).textTheme.caption?.copyWith(fontSize: 16.0),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _RectangleDemoPainter extends CustomPainter {
  _RectangleDemoPainter({
    required Animation<double> repaint,
    required this.arc,
  }) : _repaint = repaint, super(repaint: repaint);

  final MaterialRectArcTween arc;
  final Animation<double> _repaint;

  void drawPoint(Canvas canvas, Offset p, Color color) {
    final Paint paint = Paint()
      ..color = color.withOpacity(0.25)
      ..style = PaintingStyle.fill;
    canvas.drawCircle(p, _kPointRadius, paint);
    paint
      ..color = color
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2.0;
    canvas.drawCircle(p, _kPointRadius + 1.0, paint);
  }

  void drawRect(Canvas canvas, Rect rect, Color color) {
    final Paint paint = Paint()
      ..color = color.withOpacity(0.25)
      ..strokeWidth = 4.0
      ..style = PaintingStyle.stroke;
    canvas.drawRect(rect, paint);
    drawPoint(canvas, rect.center, color);
  }

  @override
  void paint(Canvas canvas, Size size) {
    drawRect(canvas, arc.begin!, Colors.green);
    drawRect(canvas, arc.end!, Colors.red);
    drawRect(canvas, arc.lerp(_repaint.value), Colors.blue);
  }

  @override
  bool hitTest(Offset position) {
    return (arc.begin!.center - position).distanceSquared < _kTargetSlop
        || (arc.end!.center - position).distanceSquared < _kTargetSlop;
  }

  @override
  bool shouldRepaint(_RectangleDemoPainter oldPainter) => arc != oldPainter.arc;
}

class _RectangleDemo extends StatefulWidget {
  const _RectangleDemo({ super.key, required this.controller });

  final AnimationController controller;

  @override
  _RectangleDemoState createState() => _RectangleDemoState();
}

class _RectangleDemoState extends State<_RectangleDemo> {
  final GlobalKey _painterKey = GlobalKey();

  late final CurvedAnimation _animation = CurvedAnimation(parent: widget.controller, curve: Curves.fastOutSlowIn);
  _DragTarget? _dragTarget;
  Size? _screenSize;
  Rect? _begin;
  Rect? _end;

  @override
  void dispose() {
    widget.controller.value = 0.0;
    super.dispose();
  }

  Drag _handleOnStart(Offset position) {
    // TODO(hansmuller): allow the user to drag both points at the same time.
    if (_dragTarget != null) {
      return _IgnoreDrag();
    }

    final RenderBox? box = _painterKey.currentContext?.findRenderObject() as RenderBox?;
    final double startOffset = (box!.localToGlobal(_begin!.center) - position).distanceSquared;
    final double endOffset = (box.localToGlobal(_end!.center) - position).distanceSquared;
    setState(() {
      if (startOffset < endOffset && startOffset < _kTargetSlop) {
        _dragTarget = _DragTarget.start;
      } else if (endOffset < _kTargetSlop) {
        _dragTarget = _DragTarget.end;
      } else {
        _dragTarget = null;
      }
    });
    return _DragHandler(_handleDragUpdate, _handleDragCancel, _handleDragEnd);
  }

  void _handleDragUpdate(DragUpdateDetails details) {
    switch (_dragTarget!) {
      case _DragTarget.start:
        setState(() {
          _begin = _begin?.shift(details.delta);
        });
        break;
      case _DragTarget.end:
        setState(() {
          _end = _end?.shift(details.delta);
        });
        break;
    }
  }

  void _handleDragCancel() {
    _dragTarget = null;
    widget.controller.value = 0.0;
  }

  void _handleDragEnd(DragEndDetails details) {
    _dragTarget = null;
  }

  @override
  Widget build(BuildContext context) {
    final Size screenSize = MediaQuery.of(context).size;
    if (_screenSize == null || _screenSize != screenSize) {
      _screenSize = screenSize;
      _begin = Rect.fromLTWH(
        screenSize.width * 0.5, screenSize.height * 0.2,
        screenSize.width * 0.4, screenSize.height * 0.2,
      );
      _end = Rect.fromLTWH(
        screenSize.width * 0.1, screenSize.height * 0.4,
        screenSize.width * 0.3, screenSize.height * 0.3,
      );
    }

    final MaterialRectArcTween arc = MaterialRectArcTween(begin: _begin, end: _end);
    return RawGestureDetector(
      behavior: _dragTarget == null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque,
      gestures: <Type, GestureRecognizerFactory>{
        ImmediateMultiDragGestureRecognizer: GestureRecognizerFactoryWithHandlers<ImmediateMultiDragGestureRecognizer>(
          () => ImmediateMultiDragGestureRecognizer(),
          (ImmediateMultiDragGestureRecognizer instance) {
            instance.onStart = _handleOnStart;
          },
        ),
      },
      child: ClipRect(
        child: CustomPaint(
          key: _painterKey,
          foregroundPainter: _RectangleDemoPainter(
            repaint: _animation,
            arc: arc,
          ),
          // Watch out: if this IgnorePointer is left out, then gestures that
          // fail _RectDemoPainter.hitTest() will still be recognized because
          // they do overlap this child, which is as big as the CustomPaint.
          child: IgnorePointer(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Text(
                'Tap the refresh button to run the animation. Drag the rectangles '
                "to change the animation's path.",
                style: Theme.of(context).textTheme.caption!.copyWith(fontSize: 16.0),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

typedef _DemoBuilder = Widget Function(_ArcDemo demo);

class _ArcDemo {
  _ArcDemo(this.title, this.builder, TickerProvider vsync)
    : controller = AnimationController(duration: const Duration(milliseconds: 500), vsync: vsync),
      key = GlobalKey(debugLabel: title);

  final String title;
  final _DemoBuilder builder;
  final AnimationController controller;
  final GlobalKey key;
}

class AnimationDemo extends StatefulWidget {
  const AnimationDemo({ super.key });

  @override
  State<AnimationDemo> createState() => _AnimationDemoState();
}

class _AnimationDemoState extends State<AnimationDemo> with TickerProviderStateMixin {
  late final List<_ArcDemo> _allDemos = <_ArcDemo>[
    _ArcDemo('POINT', (_ArcDemo demo) {
      return _PointDemo(
        key: demo.key,
        controller: demo.controller,
      );
    }, this),
    _ArcDemo('RECTANGLE', (_ArcDemo demo) {
      return _RectangleDemo(
        key: demo.key,
        controller: demo.controller,
      );
    }, this),
  ];

  Future<void> _play(_ArcDemo demo) async {
    await demo.controller.forward();
    if (demo.key.currentState != null && demo.key.currentState!.mounted) {
      demo.controller.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: _allDemos.length,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Animation'),
          bottom: TabBar(
            tabs: _allDemos.map<Tab>((_ArcDemo demo) => Tab(text: demo.title)).toList(),
          ),
        ),
        floatingActionButton: Builder(
          builder: (BuildContext context) {
            return FloatingActionButton(
              child: const Icon(Icons.refresh),
              onPressed: () {
                _play(_allDemos[DefaultTabController.of(context)!.index]);
              },
            );
          },
        ),
        body: TabBarView(
          children: _allDemos.map<Widget>((_ArcDemo demo) => demo.builder(demo)).toList(),
        ),
      ),
    );
  }
}

void main() {
  runApp(const MaterialApp(
    home: AnimationDemo(),
  ));
}
