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

void main() {
  runApp(const MaterialApp(
    title: 'Actions Demo',
    home: FocusDemo(),
  ));
}

/// Undoable Actions

/// An [ActionDispatcher] subclass that manages the invocation of undoable
/// actions.
class UndoableActionDispatcher extends ActionDispatcher implements Listenable {
  /// Constructs a new [UndoableActionDispatcher].
  ///
  /// The [maxUndoLevels] argument must not be null.
  UndoableActionDispatcher({
    int maxUndoLevels = _defaultMaxUndoLevels,
  })  : assert(maxUndoLevels != null),
        _maxUndoLevels = maxUndoLevels;

  // A stack of actions that have been performed. The most recent action
  // performed is at the end of the list.
  final List<UndoableAction> _completedActions = <UndoableAction>[];
  // A stack of actions that can be redone. The most recent action performed is
  // at the end of the list.
  final List<UndoableAction> _undoneActions = <UndoableAction>[];

  static const int _defaultMaxUndoLevels = 1000;

  /// The maximum number of undo levels allowed.
  ///
  /// If this value is set to a value smaller than the number of completed
  /// actions, then the stack of completed actions is truncated to only include
  /// the last [maxUndoLevels] actions.
  int get maxUndoLevels => _maxUndoLevels;
  int _maxUndoLevels;
  set maxUndoLevels(int value) {
    _maxUndoLevels = value;
    _pruneActions();
  }

  final Set<VoidCallback> _listeners = <VoidCallback>{};

  @override
  void addListener(VoidCallback listener) {
    _listeners.add(listener);
  }

  @override
  void removeListener(VoidCallback listener) {
    _listeners.remove(listener);
  }

  /// Notifies listeners that the [ActionDispatcher] has changed state.
  ///
  /// May only be called by subclasses.
  @protected
  void notifyListeners() {
    for (final VoidCallback callback in _listeners) {
      callback();
    }
  }

  @override
  bool invokeAction(Action action, Intent intent, {FocusNode focusNode}) {
    final bool result = super.invokeAction(action, intent, focusNode: focusNode);
    print('Invoking ${action is UndoableAction ? 'undoable ' : ''}$intent as $action: $this ');
    if (action is UndoableAction) {
      _completedActions.add(action);
      _undoneActions.clear();
      _pruneActions();
      notifyListeners();
    }
    return result;
  }

  // Enforces undo level limit.
  void _pruneActions() {
    while (_completedActions.length > _maxUndoLevels) {
      _completedActions.removeAt(0);
    }
  }

  /// Returns true if there is an action on the stack that can be undone.
  bool get canUndo {
    if (_completedActions.isNotEmpty) {
      final Intent lastIntent = _completedActions.last.invocationIntent;
      return lastIntent.isEnabled(primaryFocus.context);
    }
    return false;
  }

  /// Returns true if an action that has been undone can be re-invoked.
  bool get canRedo {
    if (_undoneActions.isNotEmpty) {
      final Intent lastIntent = _undoneActions.last.invocationIntent;
      return lastIntent.isEnabled(primaryFocus?.context);
    }
    return false;
  }

  /// Undoes the last action executed if possible.
  ///
  /// Returns true if the action was successfully undone.
  bool undo() {
    print('Undoing. $this');
    if (!canUndo) {
      return false;
    }
    final UndoableAction action = _completedActions.removeLast();
    action.undo();
    _undoneActions.add(action);
    notifyListeners();
    return true;
  }

  /// Re-invokes a previously undone action, if possible.
  ///
  /// Returns true if the action was successfully invoked.
  bool redo() {
    print('Redoing. $this');
    if (!canRedo) {
      return false;
    }
    final UndoableAction action = _undoneActions.removeLast();
    action.invoke(action.invocationNode, action.invocationIntent);
    _completedActions.add(action);
    _pruneActions();
    notifyListeners();
    return true;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('undoable items', _completedActions.length));
    properties.add(IntProperty('redoable items', _undoneActions.length));
    properties.add(IterableProperty<UndoableAction>('undo stack', _completedActions));
    properties.add(IterableProperty<UndoableAction>('redo stack', _undoneActions));
  }
}

class UndoIntent extends Intent {
  const UndoIntent() : super(kUndoActionKey);

  @override
  bool isEnabled(BuildContext context) {
    final UndoableActionDispatcher manager = Actions.of(context, nullOk: true) as UndoableActionDispatcher;
    return manager.canUndo;
  }
}

class RedoIntent extends Intent {
  const RedoIntent() : super(kRedoActionKey);

  @override
  bool isEnabled(BuildContext context) {
    final UndoableActionDispatcher manager = Actions.of(context, nullOk: true) as UndoableActionDispatcher;
    return manager.canRedo;
  }
}

const LocalKey kUndoActionKey = ValueKey<String>('Undo');
const Intent kUndoIntent = UndoIntent();
final Action kUndoAction = CallbackAction(
  kUndoActionKey,
  onInvoke: (FocusNode node, Intent tag) {
    if (node?.context == null) {
      return;
    }
    final UndoableActionDispatcher manager = Actions.of(node.context, nullOk: true) as UndoableActionDispatcher;
    manager?.undo();
  },
);

const LocalKey kRedoActionKey = ValueKey<String>('Redo');
const Intent kRedoIntent = RedoIntent();
final Action kRedoAction = CallbackAction(
  kRedoActionKey,
  onInvoke: (FocusNode node, Intent tag) {
    if (node?.context == null) {
      return;
    }
    final UndoableActionDispatcher manager = Actions.of(node.context, nullOk: true) as UndoableActionDispatcher;
    manager?.redo();
  },
);

/// An action that can be undone.
abstract class UndoableAction extends Action {
  /// A const constructor to [UndoableAction].
  ///
  /// The [intentKey] parameter must not be null.
  UndoableAction(LocalKey intentKey) : super(intentKey);

  /// The node supplied when this command was invoked.
  FocusNode get invocationNode => _invocationNode;
  FocusNode _invocationNode;

  @protected
  set invocationNode(FocusNode value) => _invocationNode = value;

  /// The [Intent] this action was originally invoked with.
  Intent get invocationIntent => _invocationTag;
  Intent _invocationTag;

  @protected
  set invocationIntent(Intent value) => _invocationTag = value;

  /// Returns true if the data model can be returned to the state it was in
  /// previous to this action being executed.
  ///
  /// Default implementation returns true.
  bool get undoable => true;

  /// Reverts the data model to the state before this command executed.
  @mustCallSuper
  void undo();

  @override
  @mustCallSuper
  void invoke(FocusNode node, Intent intent) {
    invocationNode = node;
    invocationIntent = intent;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<FocusNode>('invocationNode', invocationNode));
  }
}

class UndoableFocusActionBase extends UndoableAction {
  UndoableFocusActionBase(LocalKey name) : super(name);

  FocusNode _previousFocus;

  @override
  void invoke(FocusNode node, Intent intent) {
    super.invoke(node, intent);
    _previousFocus = primaryFocus;
    node.requestFocus();
  }

  @override
  void undo() {
    if (_previousFocus == null) {
      primaryFocus?.unfocus();
      return;
    }
    if (_previousFocus is FocusScopeNode) {
      // The only way a scope can be the _previousFocus is if there was no
      // focusedChild for the scope when we invoked this action, so we need to
      // return to that state.

      // Unfocus the current node to remove it from the focused child list of
      // the scope.
      primaryFocus?.unfocus();
      // and then let the scope node be focused...
    }
    _previousFocus.requestFocus();
    _previousFocus = null;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<FocusNode>('previous', _previousFocus));
  }
}

class UndoableRequestFocusAction extends UndoableFocusActionBase {
  UndoableRequestFocusAction() : super(RequestFocusAction.key);

  @override
  void invoke(FocusNode node, Intent intent) {
    super.invoke(node, intent);
    node.requestFocus();
  }
}

/// Actions for manipulating focus.
class UndoableNextFocusAction extends UndoableFocusActionBase {
  UndoableNextFocusAction() : super(NextFocusAction.key);

  @override
  void invoke(FocusNode node, Intent intent) {
    super.invoke(node, intent);
    node.nextFocus();
  }
}

class UndoablePreviousFocusAction extends UndoableFocusActionBase {
  UndoablePreviousFocusAction() : super(PreviousFocusAction.key);

  @override
  void invoke(FocusNode node, Intent intent) {
    super.invoke(node, intent);
    node.previousFocus();
  }
}

class UndoableDirectionalFocusAction extends UndoableFocusActionBase {
  UndoableDirectionalFocusAction() : super(DirectionalFocusAction.key);

  TraversalDirection direction;

  @override
  void invoke(FocusNode node, DirectionalFocusIntent intent) {
    super.invoke(node, intent);
    final DirectionalFocusIntent args = intent;
    node.focusInDirection(args.direction);
  }
}

/// A button class that takes focus when clicked.
class DemoButton extends StatefulWidget {
  const DemoButton({this.name});

  final String name;

  @override
  _DemoButtonState createState() => _DemoButtonState();
}

class _DemoButtonState extends State<DemoButton> {
  FocusNode _focusNode;

  @override
  void initState() {
    super.initState();
    _focusNode = FocusNode(debugLabel: widget.name);
  }

  void _handleOnPressed() {
    print('Button ${widget.name} pressed.');
    setState(() {
      Actions.invoke(context, const Intent(RequestFocusAction.key), focusNode: _focusNode);
    });
  }

  @override
  void dispose() {
    super.dispose();
    _focusNode.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      focusNode: _focusNode,
      focusColor: Colors.red,
      hoverColor: Colors.blue,
      onPressed: () => _handleOnPressed(),
      child: Text(widget.name),
    );
  }
}

class FocusDemo extends StatefulWidget {
  const FocusDemo({Key key}) : super(key: key);

  @override
  _FocusDemoState createState() => _FocusDemoState();
}

class _FocusDemoState extends State<FocusDemo> {
  FocusNode outlineFocus;
  UndoableActionDispatcher dispatcher;
  bool canUndo;
  bool canRedo;

  @override
  void initState() {
    super.initState();
    outlineFocus = FocusNode(debugLabel: 'Demo Focus Node');
    dispatcher = UndoableActionDispatcher();
    canUndo = dispatcher.canUndo;
    canRedo = dispatcher.canRedo;
    dispatcher.addListener(_handleUndoStateChange);
  }

  void _handleUndoStateChange() {
    if (dispatcher.canUndo != canUndo) {
      setState(() {
        canUndo = dispatcher.canUndo;
      });
    }
    if (dispatcher.canRedo != canRedo) {
      setState(() {
        canRedo = dispatcher.canRedo;
      });
    }
  }

  @override
  void dispose() {
    dispatcher.removeListener(_handleUndoStateChange);
    outlineFocus.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final TextTheme textTheme = Theme.of(context).textTheme;
    return Actions(
      dispatcher: dispatcher,
      actions: <LocalKey, ActionFactory>{
        RequestFocusAction.key: () => UndoableRequestFocusAction(),
        NextFocusAction.key: () => UndoableNextFocusAction(),
        PreviousFocusAction.key: () => UndoablePreviousFocusAction(),
        DirectionalFocusAction.key: () => UndoableDirectionalFocusAction(),
        kUndoActionKey: () => kUndoAction,
        kRedoActionKey: () => kRedoAction,
      },
      child: FocusTraversalGroup(
        policy: ReadingOrderTraversalPolicy(),
        child: Shortcuts(
          shortcuts: <LogicalKeySet, Intent>{
            LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.shift, LogicalKeyboardKey.keyZ): kRedoIntent,
            LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyZ): kUndoIntent,
          },
          child: FocusScope(
            debugLabel: 'Scope',
            autofocus: true,
            child: DefaultTextStyle(
              style: textTheme.headline4,
              child: Scaffold(
                appBar: AppBar(
                  title: const Text('Actions Demo'),
                ),
                body: Center(
                  child: Builder(builder: (BuildContext context) {
                    return Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const <Widget>[
                            DemoButton(name: 'One'),
                            DemoButton(name: 'Two'),
                            DemoButton(name: 'Three'),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const <Widget>[
                            DemoButton(name: 'Four'),
                            DemoButton(name: 'Five'),
                            DemoButton(name: 'Six'),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: const <Widget>[
                            DemoButton(name: 'Seven'),
                            DemoButton(name: 'Eight'),
                            DemoButton(name: 'Nine'),
                          ],
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: RaisedButton(
                                child: const Text('UNDO'),
                                onPressed: canUndo
                                    ? () {
                                        Actions.invoke(context, kUndoIntent);
                                      }
                                    : null,
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: RaisedButton(
                                child: const Text('REDO'),
                                onPressed: canRedo
                                    ? () {
                                        Actions.invoke(context, kRedoIntent);
                                      }
                                    : null,
                              ),
                            ),
                          ],
                        ),
                      ],
                    );
                  }),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
