// 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.bodySmall?.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.bodySmall!.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(),
  ));
}
