// 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 'framework.dart';
import 'inherited_model.dart';

/// The type of the [SharedAppData.getValue] `init` parameter.
///
/// This callback is used to lazily create the initial value for
/// a [SharedAppData] keyword.
typedef SharedAppDataInitCallback<T> = T Function();

/// Enables sharing key/value data with its `child` and all of the
/// child's descendants.
///
/// - `SharedAppData.getValue(context, key, initCallback)` creates a dependency
/// on the key and returns the value for the key from the shared data table.
/// If no value exists for key then the initCallback is used to create
/// the initial value.
///
/// - `SharedAppData.setValue(context, key, value)` changes the value of an entry
/// in the shared data table and forces widgets that depend on that entry
/// to be rebuilt.
///
/// A widget whose build method uses SharedAppData.getValue(context,
/// keyword, initCallback) creates a dependency on the SharedAppData. When
/// the value of keyword changes with SharedAppData.setValue(), the widget
/// will be rebuilt. The values managed by the SharedAppData are expected
/// to be immutable: intrinsic changes to values will not cause
/// dependent widgets to be rebuilt.
///
/// An instance of this widget is created automatically by [WidgetsApp].
///
/// There are many ways to share data with a widget subtree. This
/// class is based on [InheritedModel], which is an [InheritedWidget].
/// It's intended to be used by packages that need to share a modest
/// number of values among their own components.
///
/// SharedAppData is not intended to be a substitute for Provider or any of
/// the other general purpose application state systems. SharedAppData is
/// for situations where a package's custom widgets need to share one
/// or a handful of immutable data objects that can be lazily
/// initialized. It exists so that packages like that can deliver
/// custom widgets without requiring the developer to add a
/// package-specific umbrella widget to their application.
///
/// A good way to create an SharedAppData key that avoids potential
/// collisions with other packages is to use a static `Object()` value.
/// The `SharedObject` example below does this.
///
/// {@tool dartpad}
/// The following sample demonstrates using the automatically created
/// [SharedAppData]. Button presses cause changes to the values for keys
/// 'foo', and 'bar', and those changes only cause the widgets that
/// depend on those keys to be rebuilt.
///
/// ** See code in examples/api/lib/widgets/shared_app_data/shared_app_data.0.dart **
/// {@end-tool}
///
/// {@tool dartpad}
/// The following sample demonstrates how a single lazily computed
/// value could be shared within an app. A Flutter package that
/// provided custom widgets might use this approach to share a (possibly
/// private) value with instances of those widgets.
///
/// ** See code in examples/api/lib/widgets/shared_app_data/shared_app_data.1.dart **
/// {@end-tool}
class SharedAppData extends StatefulWidget {
  /// Creates a widget based on [InheritedModel] that supports build
  /// dependencies qualified by keywords. Descendant widgets create
  /// such dependencies with [SharedAppData.getValue] and they trigger
  /// rebuilds with [SharedAppData.setValue].
  ///
  /// This widget is automatically created by the [WidgetsApp].
  const SharedAppData({ super.key, required this.child });

  /// The widget below this widget in the tree.
  ///
  /// {@macro flutter.widgets.ProxyWidget.child}
  final Widget child;

  @override
  State<StatefulWidget> createState() => _SharedAppDataState();

  /// Returns the app model's value for `key` and ensures that each
  /// time the value of `key` is changed with [SharedAppData.setValue], the
  /// specified context will be rebuilt.
  ///
  /// If no value for `key` exists then the `init` callback is used to
  /// generate an initial value. The callback is expected to return
  /// an immutable value because intrinsic changes to the value will
  /// not cause dependent widgets to be rebuilt.
  ///
  /// A widget that depends on the app model's value for `key` should use
  /// this method in their `build` methods to ensure that they are rebuilt
  /// if the value changes.
  ///
  /// The type parameter `K` is the type of the keyword and `V`
  /// is the type of the value.
  static V getValue<K extends Object, V>(BuildContext context, K key, SharedAppDataInitCallback<V> init) {
    final _SharedAppModel? model = InheritedModel.inheritFrom<_SharedAppModel>(context, aspect: key);
    assert(_debugHasSharedAppData(model, context, 'getValue'));
    return model!.sharedAppDataState.getValue<K, V>(key, init);
  }

  /// Changes the app model's `value` for `key` and rebuilds any widgets
  /// that have created a dependency on `key` with [SharedAppData.getValue].
  ///
  /// If `value` is `==` to the current value of `key` then nothing
  /// is rebuilt.
  ///
  /// The `value` is expected to be immutable because intrinsic
  /// changes to the value will not cause dependent widgets to be
  /// rebuilt.
  ///
  /// Unlike [SharedAppData.getValue], this method does _not_ create a dependency
  /// between `context` and `key`.
  ///
  /// The type parameter `K` is the type of the value's keyword and `V`
  /// is the type of the value.
  static void setValue<K extends Object, V>(BuildContext context, K key, V value) {
    final _SharedAppModel? model = context.getElementForInheritedWidgetOfExactType<_SharedAppModel>()?.widget as _SharedAppModel?;
    assert(_debugHasSharedAppData(model, context, 'setValue'));
    model!.sharedAppDataState.setValue<K, V>(key, value);
  }

  static bool _debugHasSharedAppData(_SharedAppModel? model, BuildContext context, String methodName) {
    assert(() {
      if (model == null) {
        throw FlutterError.fromParts(
          <DiagnosticsNode>[
            ErrorSummary('No SharedAppData widget found.'),
            ErrorDescription('SharedAppData.$methodName requires an SharedAppData widget ancestor.\n'),
            context.describeWidget('The specific widget that could not find an SharedAppData ancestor was'),
            context.describeOwnershipChain('The ownership chain for the affected widget is'),
            ErrorHint(
              'Typically, the SharedAppData widget is introduced by the MaterialApp '
              'or WidgetsApp widget at the top of your application widget tree. It '
              'provides a key/value map of data that is shared with the entire '
              'application.',
            ),
          ],
        );
      }
      return true;
    }());
    return true;
  }
}

class _SharedAppDataState extends State<SharedAppData> {
  late Map<Object, Object?> data = <Object, Object?>{};

  @override
  Widget build(BuildContext context) {
    return _SharedAppModel(sharedAppDataState: this, child: widget.child);
  }

  V getValue<K extends Object, V>(K key, SharedAppDataInitCallback<V> init) {
    data[key] ??= init();
    return data[key] as V;
  }

  void setValue<K extends Object, V>(K key, V value) {
    if (data[key] != value) {
      setState(() {
        data = Map<Object, Object?>.of(data);
        data[key] = value;
      });
    }
  }
}

class _SharedAppModel extends InheritedModel<Object> {
  _SharedAppModel({
    required this.sharedAppDataState,
    required super.child
  }) : data = sharedAppDataState.data;

  final _SharedAppDataState sharedAppDataState;
  final Map<Object, Object?> data;

  @override
  bool updateShouldNotify(_SharedAppModel old) {
    return data != old.data;
  }

  @override
  bool updateShouldNotifyDependent(_SharedAppModel old, Set<Object> keys) {
    for (final Object key in keys) {
      if (data[key] != old.data[key]) {
        return true;
      }
    }
    return false;
  }
}
