// Copyright 2016 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/foundation.dart' show defaultTargetPlatform, required;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

import 'package:url_launcher/url_launcher.dart';

import 'theme.dart';

class LinkTextSpan extends TextSpan {

  // Beware!
  //
  // This class is only safe because the TapGestureRecognizer is not
  // given a deadline and therefore never allocates any resources.
  //
  // In any other situation -- setting a deadline, using any of the less trivial
  // recognizers, etc -- you would have to manage the gesture recognizer's
  // lifetime and call dispose() when the TextSpan was no longer being rendered.
  //
  // Since TextSpan itself is @immutable, this means that you would have to
  // manage the recognizer from outside the TextSpan, e.g. in the State of a
  // stateful widget that then hands the recognizer to the TextSpan.

  LinkTextSpan({ TextStyle style, String url, String text }) : super(
    style: style,
    text: text ?? url,
    recognizer: new TapGestureRecognizer()..onTap = () {
      launch(url);
    }
  );
}

class GalleryDrawerHeader extends StatefulWidget {
  const GalleryDrawerHeader({ Key key, this.light }) : super(key: key);

  final bool light;

  @override
  _GalleryDrawerHeaderState createState() => new _GalleryDrawerHeaderState();
}

class _GalleryDrawerHeaderState extends State<GalleryDrawerHeader> {
  bool _logoHasName = true;
  bool _logoHorizontal = true;
  MaterialColor _logoColor = Colors.blue;

  @override
  Widget build(BuildContext context) {
    final double systemTopPadding = MediaQuery.of(context).padding.top;

    return new Semantics(
      label: 'Flutter',
      child: new DrawerHeader(
        decoration: new FlutterLogoDecoration(
          margin: new EdgeInsets.fromLTRB(12.0, 12.0 + systemTopPadding, 12.0, 12.0),
          style: _logoHasName ? _logoHorizontal ? FlutterLogoStyle.horizontal
                                                : FlutterLogoStyle.stacked
                                                : FlutterLogoStyle.markOnly,
          lightColor: _logoColor.shade400,
          darkColor: _logoColor.shade900,
          textColor: widget.light ? const Color(0xFF616161) : const Color(0xFF9E9E9E),
        ),
        duration: const Duration(milliseconds: 750),
        child: new GestureDetector(
          onLongPress: () {
            setState(() {
              _logoHorizontal = !_logoHorizontal;
              if (!_logoHasName)
                _logoHasName = true;
            });
          },
          onTap: () {
            setState(() {
              _logoHasName = !_logoHasName;
            });
          },
          onDoubleTap: () {
            setState(() {
              final List<MaterialColor> options = <MaterialColor>[];
              if (_logoColor != Colors.blue)
                options.addAll(<MaterialColor>[Colors.blue, Colors.blue, Colors.blue, Colors.blue, Colors.blue, Colors.blue, Colors.blue]);
              if (_logoColor != Colors.amber)
                options.addAll(<MaterialColor>[Colors.amber, Colors.amber, Colors.amber]);
              if (_logoColor != Colors.red)
                options.addAll(<MaterialColor>[Colors.red, Colors.red, Colors.red]);
              if (_logoColor != Colors.indigo)
                options.addAll(<MaterialColor>[Colors.indigo, Colors.indigo, Colors.indigo]);
              if (_logoColor != Colors.pink)
                options.addAll(<MaterialColor>[Colors.pink]);
              if (_logoColor != Colors.purple)
                options.addAll(<MaterialColor>[Colors.purple]);
              if (_logoColor != Colors.cyan)
                options.addAll(<MaterialColor>[Colors.cyan]);
              _logoColor = options[new math.Random().nextInt(options.length)];
            });
          }
        ),
      ),
    );
  }
}

class GalleryDrawer extends StatelessWidget {
  const GalleryDrawer({
    Key key,
    this.galleryTheme,
    @required this.onThemeChanged,
    this.timeDilation,
    @required this.onTimeDilationChanged,
    this.textScaleFactor,
    this.onTextScaleFactorChanged,
    this.showPerformanceOverlay,
    this.onShowPerformanceOverlayChanged,
    this.checkerboardRasterCacheImages,
    this.onCheckerboardRasterCacheImagesChanged,
    this.checkerboardOffscreenLayers,
    this.onCheckerboardOffscreenLayersChanged,
    this.onPlatformChanged,
    this.overrideDirection: TextDirection.ltr,
    this.onOverrideDirectionChanged,
    this.onSendFeedback,
  }) : assert(onThemeChanged != null),
       assert(onTimeDilationChanged != null),
       super(key: key);

  final GalleryTheme galleryTheme;
  final ValueChanged<GalleryTheme> onThemeChanged;

  final double timeDilation;
  final ValueChanged<double> onTimeDilationChanged;

  final double textScaleFactor;
  final ValueChanged<double> onTextScaleFactorChanged;

  final bool showPerformanceOverlay;
  final ValueChanged<bool> onShowPerformanceOverlayChanged;

  final bool checkerboardRasterCacheImages;
  final ValueChanged<bool> onCheckerboardRasterCacheImagesChanged;

  final bool checkerboardOffscreenLayers;
  final ValueChanged<bool> onCheckerboardOffscreenLayersChanged;

  final ValueChanged<TargetPlatform> onPlatformChanged;

  final TextDirection overrideDirection;
  final ValueChanged<TextDirection> onOverrideDirectionChanged;

  final VoidCallback onSendFeedback;

  @override
  Widget build(BuildContext context) {
    final ThemeData themeData = Theme.of(context);
    final TextStyle aboutTextStyle = themeData.textTheme.body2;
    final TextStyle linkStyle = themeData.textTheme.body2.copyWith(color: themeData.accentColor);

    final List<Widget> themeItems = kAllGalleryThemes.map<Widget>((GalleryTheme theme) {
      return new RadioListTile<GalleryTheme>(
        title: new Text(theme.name),
        secondary: new Icon(theme.icon),
        value: theme,
        groupValue: galleryTheme,
        onChanged: onThemeChanged,
        selected: galleryTheme == theme,
      );
    }).toList();

    final Widget mountainViewItem = new RadioListTile<TargetPlatform>(
      // on iOS, we don't want to show an Android phone icon
      secondary: new Icon(defaultTargetPlatform == TargetPlatform.iOS ? Icons.star : Icons.phone_android),
      title: new Text(defaultTargetPlatform == TargetPlatform.iOS ? 'Mountain View' : 'Android'),
      value: TargetPlatform.android,
      groupValue: Theme.of(context).platform,
      onChanged: onPlatformChanged,
      selected: Theme.of(context).platform == TargetPlatform.android,
    );

    final Widget cupertinoItem = new RadioListTile<TargetPlatform>(
      // on iOS, we don't want to show the iPhone icon
      secondary: new Icon(defaultTargetPlatform == TargetPlatform.iOS ? Icons.star_border : Icons.phone_iphone),
      title: new Text(defaultTargetPlatform == TargetPlatform.iOS ? 'Cupertino' : 'iOS'),
      value: TargetPlatform.iOS,
      groupValue: Theme.of(context).platform,
      onChanged: onPlatformChanged,
      selected: Theme.of(context).platform == TargetPlatform.iOS,
    );

    final List<Widget> textSizeItems = <Widget>[];
    final Map<double, String> textSizes = <double, String>{
      null: 'System Default',
      0.8: 'Small',
      1.0: 'Normal',
      1.3: 'Large',
      2.0: 'Huge',
    };
    for (double size in textSizes.keys) {
      textSizeItems.add(new RadioListTile<double>(
        secondary: const Icon(Icons.text_fields),
        title: new Text(textSizes[size]),
        value: size,
        groupValue: textScaleFactor,
        onChanged: onTextScaleFactorChanged,
        selected: textScaleFactor == size,
      ));
    }

    final Widget animateSlowlyItem = new CheckboxListTile(
      title: const Text('Animate Slowly'),
      value: timeDilation != 1.0,
      onChanged: (bool value) {
        onTimeDilationChanged(value ? 20.0 : 1.0);
      },
      secondary: const Icon(Icons.hourglass_empty),
      selected: timeDilation != 1.0,
    );

    final Widget overrideDirectionItem = new CheckboxListTile(
      title: const Text('Force RTL'),
      value: overrideDirection == TextDirection.rtl,
      onChanged: (bool value) {
        onOverrideDirectionChanged(value ? TextDirection.rtl : TextDirection.ltr);
      },
      secondary: const Icon(Icons.format_textdirection_r_to_l),
      selected: overrideDirection == TextDirection.rtl,
    );

    final Widget sendFeedbackItem = new ListTile(
      leading: const Icon(Icons.report),
      title: const Text('Send feedback'),
      onTap: onSendFeedback ?? () {
        launch('https://github.com/flutter/flutter/issues/new');
      },
    );

    final Widget aboutItem = new AboutListTile(
      icon: const FlutterLogo(),
      applicationVersion: 'April 2018 Preview',
      applicationIcon: const FlutterLogo(),
      applicationLegalese: '© 2017 The Chromium Authors',
      aboutBoxChildren: <Widget>[
        new Padding(
          padding: const EdgeInsets.only(top: 24.0),
          child: new RichText(
            text: new TextSpan(
              children: <TextSpan>[
                new TextSpan(
                  style: aboutTextStyle,
                  text: 'Flutter is an early-stage, open-source project to help developers '
                        'build high-performance, high-fidelity, mobile apps for '
                        '${defaultTargetPlatform == TargetPlatform.iOS ? 'multiple platforms' : 'iOS and Android'} '
                        'from a single codebase. This gallery is a preview of '
                        "Flutter's many widgets, behaviors, animations, layouts, "
                        'and more. Learn more about Flutter at '
                ),
                new LinkTextSpan(
                  style: linkStyle,
                  url: 'https://flutter.io'
                ),
                new TextSpan(
                  style: aboutTextStyle,
                  text: '.\n\nTo see the source code for this app, please visit the '
                ),
                new LinkTextSpan(
                  style: linkStyle,
                  url: 'https://goo.gl/iv1p4G',
                  text: 'flutter github repo'
                ),
                new TextSpan(
                  style: aboutTextStyle,
                  text: '.'
                )
              ]
            )
          )
        )
      ]
    );

    final List<Widget> allDrawerItems = <Widget>[
      new GalleryDrawerHeader(
        light: galleryTheme.theme.brightness == Brightness.light,
      ),
    ]
    ..addAll(themeItems)
    ..addAll(<Widget>[
      const Divider(),
      mountainViewItem,
      cupertinoItem,
      const Divider(),
    ])
    ..addAll(textSizeItems)
    ..addAll(<Widget>[
      overrideDirectionItem,
      const Divider(),
      animateSlowlyItem,
      const Divider(),
    ]);

    bool addedOptionalItem = false;
    if (onCheckerboardOffscreenLayersChanged != null) {
      allDrawerItems.add(new CheckboxListTile(
        title: const Text('Checkerboard Offscreen Layers'),
        value: checkerboardOffscreenLayers,
        onChanged: onCheckerboardOffscreenLayersChanged,
        secondary: const Icon(Icons.assessment),
        selected: checkerboardOffscreenLayers,
      ));
      addedOptionalItem = true;
    }

    if (onCheckerboardRasterCacheImagesChanged != null) {
      allDrawerItems.add(new CheckboxListTile(
        title: const Text('Checkerboard Raster Cache Images'),
        value: checkerboardRasterCacheImages,
        onChanged: onCheckerboardRasterCacheImagesChanged,
        secondary: const Icon(Icons.assessment),
        selected: checkerboardRasterCacheImages,
      ));
      addedOptionalItem = true;
    }

    if (onShowPerformanceOverlayChanged != null) {
      allDrawerItems.add(new CheckboxListTile(
        title: const Text('Performance Overlay'),
        value: showPerformanceOverlay,
        onChanged: onShowPerformanceOverlayChanged,
        secondary: const Icon(Icons.assessment),
        selected: showPerformanceOverlay,
      ));
      addedOptionalItem = true;
    }

    if (addedOptionalItem)
      allDrawerItems.add(const Divider());

    allDrawerItems.addAll(<Widget>[
      sendFeedbackItem,
      aboutItem,
    ]);

    return new Drawer(child: new ListView(primary: false, children: allDrawerItems));
  }
}