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

import 'package:flutter/widgets.dart';

import 'ink_well.dart';
import 'material.dart';
import 'theme.dart';

const Duration _kMenuDuration = const Duration(milliseconds: 300);
const double _kBaselineOffsetFromBottom = 20.0;
const double _kMenuCloseIntervalEnd = 2.0 / 3.0;
const double _kMenuHorizontalPadding = 16.0;
const double _kMenuItemHeight = 48.0;
const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep;
const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
const double _kMenuVerticalPadding = 8.0;
const double _kMenuWidthStep = 56.0;

class PopupMenuItem<T> extends StatelessComponent {
  PopupMenuItem({
    Key key,
    this.value,
    this.child
  }) : super(key: key);

  final Widget child;
  final T value;

  Widget build(BuildContext context) {
    return new MergeSemantics(
      child: new Container(
        height: _kMenuItemHeight,
        padding: const EdgeDims.symmetric(horizontal: _kMenuHorizontalPadding),
        child: new DefaultTextStyle(
          style: Theme.of(context).text.subhead,
          child: new Baseline(
            baseline: _kMenuItemHeight - _kBaselineOffsetFromBottom,
            child: child
          )
        )
      )
    );
  }
}

class _PopupMenu<T> extends StatelessComponent {
  _PopupMenu({
    Key key,
    this.route
  }) : super(key: key);

  final _PopupMenuRoute<T> route;

  Widget build(BuildContext context) {
    double unit = 1.0 / (route.items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade.
    List<Widget> children = <Widget>[];

    for (int i = 0; i < route.items.length; ++i) {
      double start = (i + 1) * unit;
      double end = (start + 1.5 * unit).clamp(0.0, 1.0);
      CurvedAnimation opacity = new CurvedAnimation(
        parent: route.animation,
        curve: new Interval(start, end)
      );
      children.add(new FadeTransition(
        opacity: opacity,
        child: new InkWell(
          onTap: () => Navigator.pop(context, route.items[i].value),
          child: route.items[i]
        ))
      );
    }

    final CurveTween opacity = new CurveTween(curve: new Interval(0.0, 1.0 / 3.0));
    final CurveTween width = new CurveTween(curve: new Interval(0.0, unit));
    final CurveTween height = new CurveTween(curve: new Interval(0.0, unit * route.items.length));

    Widget child = new ConstrainedBox(
      constraints: new BoxConstraints(
        minWidth: _kMenuMinWidth,
        maxWidth: _kMenuMaxWidth
      ),
      child: new IntrinsicWidth(
        stepWidth: _kMenuWidthStep,
        child: new Block(
          children: children,
          padding: const EdgeDims.symmetric(
            vertical: _kMenuVerticalPadding
          )
        )
      )
    );

    return new AnimatedBuilder(
      animation: route.animation,
      builder: (BuildContext context, Widget child) {
        return new Opacity(
          opacity: opacity.evaluate(route.animation),
          child: new Material(
            type: MaterialType.card,
            elevation: route.elevation,
            child: new Align(
              alignment: const FractionalOffset(1.0, 0.0),
              widthFactor: width.evaluate(route.animation),
              heightFactor: height.evaluate(route.animation),
              child: child
            )
          )
        );
      },
      child: child
    );
  }
}

class _PopupMenuRoute<T> extends PopupRoute<T> {
  _PopupMenuRoute({
    Completer<T> completer,
    this.position,
    this.items,
    this.elevation
  }) : super(completer: completer);

  final ModalPosition position;
  final List<PopupMenuItem<T>> items;
  final int elevation;

  ModalPosition getPosition(BuildContext context) {
    return position;
  }

  Animation<double> createAnimation() {
    return new CurvedAnimation(
      parent: super.createAnimation(),
      reverseCurve: new Interval(0.0, _kMenuCloseIntervalEnd)
    );
  }

  Duration get transitionDuration => _kMenuDuration;
  bool get barrierDismissable => true;
  Color get barrierColor => null;

  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> forwardAnimation) {
    return new _PopupMenu(route: this);
  }
}

Future showMenu({ BuildContext context, ModalPosition position, List<PopupMenuItem> items, int elevation: 8 }) {
  Completer completer = new Completer();
  Navigator.push(context, new _PopupMenuRoute(
    completer: completer,
    position: position,
    items: items,
    elevation: elevation
  ));
  return completer.future;
}
