// 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 'package:flutter/widgets.dart';

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

enum ButtonColor { normal, accent }

class ButtonTheme extends InheritedWidget {
  ButtonTheme({
    Key key,
    this.color,
    Widget child
  }) : super(key: key, child: child) {
    assert(child != null);
  }

  final ButtonColor color;

  /// The color from the closest instance of this class that encloses the given context.
  ///
  /// Defaults to [ButtonColor.normal] if none exists.
  static ButtonColor of(BuildContext context) {
    ButtonTheme result = context.inheritFromWidgetOfExactType(ButtonTheme);
    return result?.color ?? ButtonColor.normal;
  }

  bool updateShouldNotify(ButtonTheme old) => color != old.color;
}

/// Base class for buttons in the Material theme.
/// Rather than using this class directly, please use [FlatButton] or [RaisedButton].
///
/// MaterialButtons whose [onPressed] handler is null will be disabled. To have
/// an enabled button, make sure to pass a non-null value for onPressed.
abstract class MaterialButton extends StatefulComponent {
  MaterialButton({
    Key key,
    this.child,
    this.textTheme,
    this.textColor,
    this.disabledTextColor,
    this.onPressed
  }) : super(key: key);

  final Widget child;
  final ButtonColor textTheme;
  final Color textColor;
  final Color disabledTextColor;

  /// The callback that is invoked when the button is tapped or otherwise activated.
  ///
  /// If this is set to null, the button will be disabled.
  final VoidCallback onPressed;

  /// Whether the button is enabled or disabled. Buttons are disabled by default. To
  /// enable a button, set its [onPressed] property to a non-null value.
  bool get enabled => onPressed != null;

  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    if (!enabled)
      description.add('disabled');
  }
}

abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
  bool highlight = false;

  int get elevation;
  Color getColor(BuildContext context);
  ThemeBrightness getColorBrightness(BuildContext context);

  Color getTextColor(BuildContext context) {
    if (config.enabled) {
      if (config.textColor != null)
        return config.textColor;
      switch (config.textTheme ?? ButtonTheme.of(context)) {
        case ButtonColor.accent:
          return Theme.of(context).accentColor;
        case ButtonColor.normal:
          switch (getColorBrightness(context)) {
            case ThemeBrightness.light:
              return Colors.black87;
            case ThemeBrightness.dark:
              return Colors.white;
          }
      }
    }
    if (config.disabledTextColor != null)
      return config.disabledTextColor;
    switch (getColorBrightness(context)) {
      case ThemeBrightness.light:
        return Colors.black26;
      case ThemeBrightness.dark:
        return Colors.white30;
    }
  }

  void _handleHighlightChanged(bool value) {
    setState(() {
      // mostly just used by the RaisedButton subclass to change the elevation
      highlight = value;
    });
  }

  Widget build(BuildContext context) {
    assert(debugCheckHasMaterial(context));
    Widget contents = new InkWell(
      onTap: config.onPressed,
      onHighlightChanged: _handleHighlightChanged,
      child: new Container(
        padding: new EdgeDims.symmetric(horizontal: 8.0),
        child: new Center(
          widthFactor: 1.0,
          child: config.child
        )
      )
    );
    TextStyle style = Theme.of(context).text.button.copyWith(color: getTextColor(context));
    int elevation = this.elevation;
    Color color = getColor(context);
    if (elevation > 0 || color != null) {
      contents = new Material(
        type: MaterialType.button,
        color: getColor(context),
        elevation: elevation,
        textStyle: style,
        child: contents
      );
    } else {
      contents = new DefaultTextStyle(
        style: style,
        child: contents
      );
    }
    return new Container(
      height: 36.0,
      constraints: new BoxConstraints(minWidth: 88.0),
      padding: const EdgeDims.symmetric(horizontal: 8.0),
      margin: const EdgeDims.all(8.0),
      child: contents
    );
  }
}
