// 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 'dart:math' as math;

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

const double kTwoPi = 2 * math.pi;

class SectorConstraints extends Constraints {
  const SectorConstraints({
    this.minDeltaRadius = 0.0,
    this.maxDeltaRadius = double.infinity,
    this.minDeltaTheta = 0.0,
    this.maxDeltaTheta = kTwoPi,
  }) : assert(maxDeltaRadius >= minDeltaRadius),
       assert(maxDeltaTheta >= minDeltaTheta);

  const SectorConstraints.tight({ double deltaRadius = 0.0, double deltaTheta = 0.0 })
    : minDeltaRadius = deltaRadius,
      maxDeltaRadius = deltaRadius,
      minDeltaTheta = deltaTheta,
      maxDeltaTheta = deltaTheta;

  final double minDeltaRadius;
  final double maxDeltaRadius;
  final double minDeltaTheta;
  final double maxDeltaTheta;

  double constrainDeltaRadius(double deltaRadius) {
    return deltaRadius.clamp(minDeltaRadius, maxDeltaRadius);
  }

  double constrainDeltaTheta(double deltaTheta) {
    return deltaTheta.clamp(minDeltaTheta, maxDeltaTheta);
  }

  @override
  bool get isTight => minDeltaTheta >= maxDeltaTheta && minDeltaTheta >= maxDeltaTheta;

  @override
  bool get isNormalized => minDeltaRadius <= maxDeltaRadius && minDeltaTheta <= maxDeltaTheta;

  @override
  bool debugAssertIsValid({
    bool isAppliedConstraint = false,
    InformationCollector? informationCollector,
  }) {
    assert(isNormalized);
    return isNormalized;
  }
}

class SectorDimensions {
  const SectorDimensions({ this.deltaRadius = 0.0, this.deltaTheta = 0.0 });

  factory SectorDimensions.withConstraints(
    SectorConstraints constraints, {
    double deltaRadius = 0.0,
    double deltaTheta = 0.0,
  }) {
    return SectorDimensions(
      deltaRadius: constraints.constrainDeltaRadius(deltaRadius),
      deltaTheta: constraints.constrainDeltaTheta(deltaTheta),
    );
  }

  final double deltaRadius;
  final double deltaTheta;
}

class SectorParentData extends ParentData {
  double radius = 0.0;
  double theta = 0.0;
}

/// Base class for [RenderObject]s that live in a polar coordinate space.
///
/// In a polar coordinate system each point on a plane is determined by a
/// distance from a reference point ("radius") and an angle from a reference
/// direction ("theta").
///
/// See also:
///
///  * <https://en.wikipedia.org/wiki/Polar_coordinate_system>, which defines
///    the polar coordinate space.
///  * [RenderBox], which is the base class for [RenderObject]s that live in a
///    Cartesian coordinate space.
abstract class RenderSector extends RenderObject {

  @override
  void setupParentData(RenderObject child) {
    if (child.parentData is! SectorParentData)
      child.parentData = SectorParentData();
  }

  // RenderSectors always use SectorParentData subclasses, as they need to be
  // able to read their position information for painting and hit testing.
  @override
  SectorParentData? get parentData => super.parentData as SectorParentData?;

  SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
    return SectorDimensions.withConstraints(constraints);
  }

  @override
  SectorConstraints get constraints => super.constraints as SectorConstraints;

  @override
  void debugAssertDoesMeetConstraints() {
    assert(constraints != null);
    assert(deltaRadius != null);
    assert(deltaRadius < double.infinity);
    assert(deltaTheta != null);
    assert(deltaTheta < double.infinity);
    assert(constraints.minDeltaRadius <= deltaRadius);
    assert(deltaRadius <= math.max(constraints.minDeltaRadius, constraints.maxDeltaRadius));
    assert(constraints.minDeltaTheta <= deltaTheta);
    assert(deltaTheta <= math.max(constraints.minDeltaTheta, constraints.maxDeltaTheta));
  }

  @override
  void performResize() {
    // default behavior for subclasses that have sizedByParent = true
    deltaRadius = constraints.constrainDeltaRadius(0.0);
    deltaTheta = constraints.constrainDeltaTheta(0.0);
  }

  @override
  void performLayout() {
    // descendants have to either override performLayout() to set both
    // the dimensions and lay out children, or, set sizedByParent to
    // true so that performResize()'s logic above does its thing.
    assert(sizedByParent);
  }

  @override
  Rect get paintBounds => Rect.fromLTWH(0.0, 0.0, 2.0 * deltaRadius, 2.0 * deltaRadius);

  @override
  Rect get semanticBounds => Rect.fromLTWH(-deltaRadius, -deltaRadius, 2.0 * deltaRadius, 2.0 * deltaRadius);

  bool hitTest(SectorHitTestResult result, { required double radius, required double theta }) {
    if (radius < parentData!.radius || radius >= parentData!.radius + deltaRadius ||
        theta < parentData!.theta || theta >= parentData!.theta + deltaTheta)
      return false;
    hitTestChildren(result, radius: radius, theta: theta);
    result.add(SectorHitTestEntry(this, radius: radius, theta: theta));
    return true;
  }
  void hitTestChildren(SectorHitTestResult result, { required double radius, required double theta }) { }

  late double deltaRadius;
  late double deltaTheta;
}

abstract class RenderDecoratedSector extends RenderSector {

  RenderDecoratedSector(BoxDecoration? decoration) : _decoration = decoration;

  BoxDecoration? _decoration;
  BoxDecoration? get decoration => _decoration;
  set decoration(BoxDecoration? value) {
    if (value == _decoration)
      return;
    _decoration = value;
    markNeedsPaint();
  }

  // offset must point to the center of the circle
  @override
  void paint(PaintingContext context, Offset offset) {
    assert(deltaRadius != null);
    assert(deltaTheta != null);
    assert(parentData is SectorParentData);

    if (_decoration == null)
      return;

    if (_decoration!.color != null) {
      final Canvas canvas = context.canvas;
      final Paint paint = Paint()..color = _decoration!.color!;
      final Path path = Path();
      final double outerRadius = parentData!.radius + deltaRadius;
      final Rect outerBounds = Rect.fromLTRB(offset.dx-outerRadius, offset.dy-outerRadius, offset.dx+outerRadius, offset.dy+outerRadius);
      path.arcTo(outerBounds, parentData!.theta, deltaTheta, true);
      final double innerRadius = parentData!.radius;
      final Rect innerBounds = Rect.fromLTRB(offset.dx-innerRadius, offset.dy-innerRadius, offset.dx+innerRadius, offset.dy+innerRadius);
      path.arcTo(innerBounds, parentData!.theta + deltaTheta, -deltaTheta, false);
      path.close();
      canvas.drawPath(path, paint);
    }
  }

}

class SectorChildListParentData extends SectorParentData with ContainerParentDataMixin<RenderSector> { }

class RenderSectorWithChildren extends RenderDecoratedSector with ContainerRenderObjectMixin<RenderSector, SectorChildListParentData> {
  RenderSectorWithChildren(BoxDecoration? decoration) : super(decoration);

  @override
  void hitTestChildren(SectorHitTestResult result, { required double radius, required double theta }) {
    RenderSector? child = lastChild;
    while (child != null) {
      if (child.hitTest(result, radius: radius, theta: theta))
        return;
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.previousSibling;
    }
  }

  @override
  void visitChildren(RenderObjectVisitor visitor) {
    RenderSector? child = lastChild;
    while (child != null) {
      visitor(child);
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.previousSibling;
    }
  }
}

class RenderSectorRing extends RenderSectorWithChildren {
  // lays out RenderSector children in a ring

  RenderSectorRing({
    BoxDecoration? decoration,
    double deltaRadius = double.infinity,
    double padding = 0.0,
  }) : _padding = padding,
       assert(deltaRadius >= 0.0),
       _desiredDeltaRadius = deltaRadius,
       super(decoration);

  double _desiredDeltaRadius;
  double get desiredDeltaRadius => _desiredDeltaRadius;
  set desiredDeltaRadius(double value) {
    assert(value != null);
    assert(value >= 0);
    if (_desiredDeltaRadius != value) {
      _desiredDeltaRadius = value;
      markNeedsLayout();
    }
  }

  double _padding;
  double get padding => _padding;
  set padding(double value) {
    // TODO(ianh): avoid code duplication
    assert(value != null);
    if (_padding != value) {
      _padding = value;
      markNeedsLayout();
    }
  }

  @override
  void setupParentData(RenderObject child) {
    // TODO(ianh): avoid code duplication
    if (child.parentData is! SectorChildListParentData)
      child.parentData = SectorChildListParentData();
  }

  @override
  SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
    final double outerDeltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
    final double innerDeltaRadius = math.max(0.0, outerDeltaRadius - padding * 2.0);
    final double childRadius = radius + padding;
    final double paddingTheta = math.atan(padding / (radius + outerDeltaRadius));
    double innerTheta = paddingTheta; // increments with each child
    double remainingDeltaTheta = math.max(0.0, constraints.maxDeltaTheta - (innerTheta + paddingTheta));
    RenderSector? child = firstChild;
    while (child != null) {
      final SectorConstraints innerConstraints = SectorConstraints(
        maxDeltaRadius: innerDeltaRadius,
        maxDeltaTheta: remainingDeltaTheta,
      );
      final SectorDimensions childDimensions = child.getIntrinsicDimensions(innerConstraints, childRadius);
      innerTheta += childDimensions.deltaTheta;
      remainingDeltaTheta -= childDimensions.deltaTheta;
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.nextSibling;
      if (child != null) {
        innerTheta += paddingTheta;
        remainingDeltaTheta -= paddingTheta;
      }
    }
    return SectorDimensions.withConstraints(constraints,
                                                deltaRadius: outerDeltaRadius,
                                                deltaTheta: innerTheta);
  }

  @override
  void performLayout() {
    assert(parentData is SectorParentData);
    deltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
    assert(deltaRadius < double.infinity);
    final double innerDeltaRadius = deltaRadius - padding * 2.0;
    final double childRadius = parentData!.radius + padding;
    final double paddingTheta = math.atan(padding / (parentData!.radius + deltaRadius));
    double innerTheta = paddingTheta; // increments with each child
    double remainingDeltaTheta = constraints.maxDeltaTheta - (innerTheta + paddingTheta);
    RenderSector? child = firstChild;
    while (child != null) {
      final SectorConstraints innerConstraints = SectorConstraints(
        maxDeltaRadius: innerDeltaRadius,
        maxDeltaTheta: remainingDeltaTheta,
      );
      assert(child.parentData is SectorParentData);
      child.parentData!.theta = innerTheta;
      child.parentData!.radius = childRadius;
      child.layout(innerConstraints, parentUsesSize: true);
      innerTheta += child.deltaTheta;
      remainingDeltaTheta -= child.deltaTheta;
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.nextSibling;
      if (child != null) {
        innerTheta += paddingTheta;
        remainingDeltaTheta -= paddingTheta;
      }
    }
    deltaTheta = innerTheta;
  }

  // offset must point to the center of our circle
  // each sector then knows how to paint itself at its location
  @override
  void paint(PaintingContext context, Offset offset) {
    // TODO(ianh): avoid code duplication
    super.paint(context, offset);
    RenderSector? child = firstChild;
    while (child != null) {
      context.paintChild(child, offset);
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.nextSibling;
    }
  }

}

class RenderSectorSlice extends RenderSectorWithChildren {
  // lays out RenderSector children in a stack

  RenderSectorSlice({
    BoxDecoration? decoration,
    double deltaTheta = kTwoPi,
    double padding = 0.0,
  }) : _padding = padding, _desiredDeltaTheta = deltaTheta, super(decoration);

  double _desiredDeltaTheta;
  double get desiredDeltaTheta => _desiredDeltaTheta;
  set desiredDeltaTheta(double value) {
    assert(value != null);
    if (_desiredDeltaTheta != value) {
      _desiredDeltaTheta = value;
      markNeedsLayout();
    }
  }

  double _padding;
  double get padding => _padding;
  set padding(double value) {
    // TODO(ianh): avoid code duplication
    assert(value != null);
    if (_padding != value) {
      _padding = value;
      markNeedsLayout();
    }
  }

  @override
  void setupParentData(RenderObject child) {
    // TODO(ianh): avoid code duplication
    if (child.parentData is! SectorChildListParentData)
      child.parentData = SectorChildListParentData();
  }

  @override
  SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
    assert(parentData is SectorParentData);
    final double paddingTheta = math.atan(padding / parentData!.radius);
    final double outerDeltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
    final double innerDeltaTheta = outerDeltaTheta - paddingTheta * 2.0;
    double childRadius = parentData!.radius + padding;
    double remainingDeltaRadius = constraints.maxDeltaRadius - (padding * 2.0);
    RenderSector? child = firstChild;
    while (child != null) {
      final SectorConstraints innerConstraints = SectorConstraints(
        maxDeltaRadius: remainingDeltaRadius,
        maxDeltaTheta: innerDeltaTheta,
      );
      final SectorDimensions childDimensions = child.getIntrinsicDimensions(innerConstraints, childRadius);
      childRadius += childDimensions.deltaRadius;
      remainingDeltaRadius -= childDimensions.deltaRadius;
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.nextSibling;
      childRadius += padding;
      remainingDeltaRadius -= padding;
    }
    return SectorDimensions.withConstraints(constraints,
                                                deltaRadius: childRadius - parentData!.radius,
                                                deltaTheta: outerDeltaTheta);
  }

  @override
  void performLayout() {
    assert(parentData is SectorParentData);
    deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
    assert(deltaTheta <= kTwoPi);
    final double paddingTheta = math.atan(padding / parentData!.radius);
    final double innerTheta = parentData!.theta + paddingTheta;
    final double innerDeltaTheta = deltaTheta - paddingTheta * 2.0;
    double childRadius = parentData!.radius + padding;
    double remainingDeltaRadius = constraints.maxDeltaRadius - (padding * 2.0);
    RenderSector? child = firstChild;
    while (child != null) {
      final SectorConstraints innerConstraints = SectorConstraints(
        maxDeltaRadius: remainingDeltaRadius,
        maxDeltaTheta: innerDeltaTheta,
      );
      child.parentData!.theta = innerTheta;
      child.parentData!.radius = childRadius;
      child.layout(innerConstraints, parentUsesSize: true);
      childRadius += child.deltaRadius;
      remainingDeltaRadius -= child.deltaRadius;
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.nextSibling;
      childRadius += padding;
      remainingDeltaRadius -= padding;
    }
    deltaRadius = childRadius - parentData!.radius;
  }

  // offset must point to the center of our circle
  // each sector then knows how to paint itself at its location
  @override
  void paint(PaintingContext context, Offset offset) {
    // TODO(ianh): avoid code duplication
    super.paint(context, offset);
    RenderSector? child = firstChild;
    while (child != null) {
      assert(child.parentData is SectorChildListParentData);
      context.paintChild(child, offset);
      final SectorChildListParentData childParentData = child.parentData! as SectorChildListParentData;
      child = childParentData.nextSibling;
    }
  }

}

class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChildMixin<RenderSector> {

  RenderBoxToRenderSectorAdapter({ double innerRadius = 0.0, RenderSector? child })
    : _innerRadius = innerRadius {
    this.child = child;
  }

  double _innerRadius;
  double get innerRadius => _innerRadius;
  set innerRadius(double value) {
    _innerRadius = value;
    markNeedsLayout();
  }

  @override
  void setupParentData(RenderObject child) {
    if (child.parentData is! SectorParentData)
      child.parentData = SectorParentData();
  }

  @override
  double computeMinIntrinsicWidth(double height) {
    if (child == null)
      return 0.0;
    return getIntrinsicDimensions(height: height).width;
  }

  @override
  double computeMaxIntrinsicWidth(double height) {
    if (child == null)
      return 0.0;
    return getIntrinsicDimensions(height: height).width;
  }

  @override
  double computeMinIntrinsicHeight(double width) {
    if (child == null)
      return 0.0;
    return getIntrinsicDimensions(width: width).height;
  }

  @override
  double computeMaxIntrinsicHeight(double width) {
    if (child == null)
      return 0.0;
    return getIntrinsicDimensions(width: width).height;
  }

  Size getIntrinsicDimensions({
    double width = double.infinity,
    double height = double.infinity,
  }) {
    assert(child is RenderSector);
    assert(child!.parentData is SectorParentData);
    assert(width != null);
    assert(height != null);
    if (!width.isFinite && !height.isFinite)
      return Size.zero;
    final double maxChildDeltaRadius = math.max(0.0, math.min(width, height) / 2.0 - innerRadius);
    final SectorDimensions childDimensions = child!.getIntrinsicDimensions(SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius);
    final double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0;
    return Size.square(dimension);
  }

  @override
  void performLayout() {
    if (child == null || (!constraints.hasBoundedWidth && !constraints.hasBoundedHeight)) {
      size = constraints.constrain(Size.zero);
      child?.layout(SectorConstraints(maxDeltaRadius: innerRadius), parentUsesSize: true);
      return;
    }
    assert(child is RenderSector);
    assert(child!.parentData is SectorParentData);
    final double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius;
    child!.parentData!.radius = innerRadius;
    child!.parentData!.theta = 0.0;
    child!.layout(SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), parentUsesSize: true);
    final double dimension = (innerRadius + child!.deltaRadius) * 2.0;
    size = constraints.constrain(Size(dimension, dimension));
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    super.paint(context, offset);
    if (child != null) {
      final Rect bounds = offset & size;
      // we move the offset to the center of the circle for the RenderSectors
      context.paintChild(child!, bounds.center);
    }
  }

  @override
  bool hitTest(BoxHitTestResult result, { required Offset position }) {
    if (child == null)
      return false;
    double x = position.dx;
    double y = position.dy;
    // translate to our origin
    x -= size.width / 2.0;
    y -= size.height / 2.0;
    // convert to radius/theta
    final double radius = math.sqrt(x * x + y * y);
    final double theta = (math.atan2(x, -y) - math.pi / 2.0) % kTwoPi;
    if (radius < innerRadius)
      return false;
    if (radius >= innerRadius + child!.deltaRadius)
      return false;
    if (theta > child!.deltaTheta)
      return false;
    child!.hitTest(SectorHitTestResult.wrap(result), radius: radius, theta: theta);
    result.add(BoxHitTestEntry(this, position));
    return true;
  }

}

class RenderSolidColor extends RenderDecoratedSector {
  RenderSolidColor(
    this.backgroundColor, {
    this.desiredDeltaRadius = double.infinity,
    this.desiredDeltaTheta = kTwoPi,
  }) : super(BoxDecoration(color: backgroundColor));

  double desiredDeltaRadius;
  double desiredDeltaTheta;
  final Color backgroundColor;

  @override
  SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
    return SectorDimensions.withConstraints(constraints, deltaTheta: desiredDeltaTheta);
  }

  @override
  void performLayout() {
    deltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
    deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
  }

  @override
  void handleEvent(PointerEvent event, HitTestEntry entry) {
    if (event is PointerDownEvent) {
      decoration = const BoxDecoration(color: Color(0xFFFF0000));
    } else if (event is PointerUpEvent) {
      decoration = BoxDecoration(color: backgroundColor);
    }
  }
}

/// The result of performing a hit test on [RenderSector]s.
class SectorHitTestResult extends HitTestResult {
  /// Creates an empty hit test result for hit testing on [RenderSector].
  SectorHitTestResult() : super();

  /// Wraps `result` to create a [HitTestResult] that implements the
  /// [SectorHitTestResult] protocol for hit testing on [RenderSector]s.
  ///
  /// This method is used by [RenderObject]s that adapt between the
  /// [RenderSector]-world and the non-[RenderSector]-world to convert a (subtype of)
  /// [HitTestResult] to a [SectorHitTestResult] for hit testing on [RenderSector]s.
  ///
  /// The [HitTestEntry]s added to the returned [SectorHitTestResult] are also
  /// added to the wrapped `result` (both share the same underlying data
  /// structure to store [HitTestEntry]s).
  ///
  /// See also:
  ///
  ///  * [HitTestResult.wrap], which turns a [SectorHitTestResult] back into a
  ///    generic [HitTestResult].
  SectorHitTestResult.wrap(HitTestResult result) : super.wrap(result);

  // TODO(goderbauer): Add convenience methods to transform hit test positions
  //    once we have RenderSector implementations that move the origin of their
  //    children (e.g. RenderSectorTransform analogs to RenderTransform).
}

/// A hit test entry used by [RenderSector].
class SectorHitTestEntry extends HitTestEntry {
  /// Creates a box hit test entry.
  ///
  /// The [radius] and [theta] argument must not be null.
  SectorHitTestEntry(RenderSector target, { required this.radius,  required this.theta })
      : assert(radius != null),
        assert(theta != null),
        super(target);

  @override
  RenderSector get target => super.target as RenderSector;

  /// The radius component of the hit test position in the local coordinates of
  /// [target].
  final double radius;

  /// The theta component of the hit test position in the local coordinates of
  /// [target].
  final double theta;
}
