// 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';

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;
}
