// Copyright 2015 The Chromium 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;
}

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;

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

  @override
  SectorConstraints get constraints => super.constraints;

  @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(HitTestResult result, { double radius, 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(HitTestEntry(this));
    return true;
  }
  void hitTestChildren(HitTestResult result, { double radius, double theta }) { }

  double deltaRadius;
  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(HitTestResult result, { double radius, double theta }) {
    RenderSector child = lastChild;
    while (child != null) {
      if (child.hitTest(result, radius: radius, theta: theta))
        return;
      final SectorChildListParentData childParentData = child.parentData;
      child = childParentData.previousSibling;
    }
  }

  @override
  void visitChildren(RenderObjectVisitor visitor) {
    RenderSector child = lastChild;
    while (child != null) {
      visitor(child);
      final SectorChildListParentData childParentData = child.parentData;
      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;
      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;
      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;
      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;
      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;
      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;
      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);
      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(HitTestResult result, { 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(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);
    }
  }
}
