// 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 'dart:collection';
import 'dart:sky' as sky;

import 'package:sky/base/hit_test.dart';
import 'package:sky/base/scheduler.dart' as scheduler;
import 'package:sky/mojo/activity.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/rendering/view.dart';

export 'package:sky/base/hit_test.dart' show EventDisposition, combineEventDispositions;
export 'package:sky/rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
export 'package:sky/rendering/flex.dart' show FlexDirection;
export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;

final bool _shouldLogRenderDuration = false; // see also 'enableProfilingLoop' argument to runApp()

typedef Widget Builder();
typedef void WidgetTreeWalker(Widget);

abstract class Key {
  const Key.constructor(); // so that subclasses can call us, since the Key() factory constructor shadows the implicit constructor
  factory Key(String value) => new StringKey(value);
  factory Key.stringify(Object value) => new StringKey(value.toString());
  factory Key.fromObjectIdentity(Object value) => new ObjectKey(value);
}

class StringKey extends Key {
  const StringKey(this.value) : super.constructor();
  final String value;
  String toString() => '[\'${value}\']';
  bool operator==(other) => other is StringKey && other.value == value;
  int get hashCode => value.hashCode;
}

class ObjectKey extends Key {
  const ObjectKey(this.value) : super.constructor();
  final Object value;
  String toString() => '[${value.runtimeType}(${value.hashCode})]';
  bool operator==(other) => other is ObjectKey && identical(other.value, value);
  int get hashCode => identityHashCode(value);
}

typedef void GlobalKeySyncListener(GlobalKey key, Widget widget);
typedef void GlobalKeyRemoveListener(GlobalKey key);

abstract class GlobalKey extends Key {
  const GlobalKey.constructor() : super.constructor(); // so that subclasses can call us, since the Key() factory constructor shadows the implicit constructor
  factory GlobalKey({ String label }) => new LabeledGlobalKey(label);
  factory GlobalKey.fromObjectIdentity(Object value) => new GlobalObjectKey(value);

  static final Map<GlobalKey, Widget> _registry = new Map<GlobalKey, Widget>();
  static final Map<GlobalKey, int> _debugDuplicates = new Map<GlobalKey, int>();
  static final Map<GlobalKey, Set<GlobalKeySyncListener>> _syncListeners = new Map<GlobalKey, Set<GlobalKeySyncListener>>();
  static final Map<GlobalKey, Set<GlobalKeyRemoveListener>> _removeListeners = new Map<GlobalKey, Set<GlobalKeyRemoveListener>>();
  static final Set<GlobalKey> _syncedKeys = new Set<GlobalKey>();
  static final Set<GlobalKey> _removedKeys = new Set<GlobalKey>();

  void _register(Widget widget) {
    assert(() {
      if (_registry.containsKey(this)) {
        int oldCount = _debugDuplicates.putIfAbsent(this, () => 1);
        assert(oldCount >= 1);
        _debugDuplicates[this] = oldCount + 1;
      }
      return true;
    });
    _registry[this] = widget;
  }

  void _unregister(Widget widget) {
    assert(() {
      if (_registry.containsKey(this) && _debugDuplicates.containsKey(this)) {
        int oldCount = _debugDuplicates[this];
        assert(oldCount >= 2);
        if (oldCount == 2) {
          _debugDuplicates.remove(this);
        } else {
          _debugDuplicates[this] = oldCount - 1;
        }
      }
      return true;
    });
    if (_registry[this] == widget) {
      _registry.remove(this);
      _removedKeys.add(this);
    }
  }

  void _didSync() {
    _syncedKeys.add(this);
  }

  static bool _notifyingListeners = false;

  static void registerSyncListener(GlobalKey key, GlobalKeySyncListener listener) {
    assert(!_notifyingListeners);
    assert(key != null);
    Set<GlobalKeySyncListener> listeners =
        _syncListeners.putIfAbsent(key, () => new Set<GlobalKeySyncListener>());
    bool added = listeners.add(listener);
    assert(added);
  }

  static void unregisterSyncListener(GlobalKey key, GlobalKeySyncListener listener) {
    assert(!_notifyingListeners);
    assert(key != null);
    assert(_syncListeners.containsKey(key));
    bool removed = _syncListeners[key].remove(listener);
    if (_syncListeners[key].isEmpty)
      _syncListeners.remove(key);
    assert(removed);
  }

  static void registerRemoveListener(GlobalKey key, GlobalKeyRemoveListener listener) {
    assert(!_notifyingListeners);
    assert(key != null);
    Set<GlobalKeyRemoveListener> listeners =
        _removeListeners.putIfAbsent(key, () => new Set<GlobalKeyRemoveListener>());
    bool added = listeners.add(listener);
    assert(added);
  }

  static void unregisterRemoveListener(GlobalKey key, GlobalKeyRemoveListener listener) {
    assert(!_notifyingListeners);
    assert(key != null);
    assert(_removeListeners.containsKey(key));
    bool removed = _removeListeners[key].remove(listener);
    if (_removeListeners[key].isEmpty)
      _removeListeners.remove(key);
    assert(removed);
  }

  static Widget getWidget(GlobalKey key) {
    assert(key != null);
    return _registry[key];
  }

  static void _notifyListeners() {
    assert(!_inBuildDirtyComponents);
    assert(!Widget._notifyingMountStatus);
    assert(_debugDuplicates.isEmpty);
    if (_syncedKeys.isEmpty && _removedKeys.isEmpty)
      return;
    _notifyingListeners = true;
    try {
      Map<GlobalKey, Set<GlobalKeyRemoveListener>> localRemoveListeners =
          new Map<GlobalKey, Set<GlobalKeyRemoveListener>>.from(_removeListeners);
      Map<GlobalKey, Set<GlobalKeySyncListener>> localSyncListeners =
          new Map<GlobalKey, Set<GlobalKeySyncListener>>.from(_syncListeners);

      for (GlobalKey key in _syncedKeys) {
        Widget widget = _registry[key];
        if (widget != null && localSyncListeners.containsKey(key)) {
          for (GlobalKeySyncListener listener in localSyncListeners[key])
            listener(key, widget);
        }
      }

      for (GlobalKey key in _removedKeys) {
        if (!_registry.containsKey(key) && localRemoveListeners.containsKey(key)) {
          for (GlobalKeyRemoveListener listener in localRemoveListeners[key])
            listener(key);
        }
      }
    } finally {
      _removedKeys.clear();
      _syncedKeys.clear();
      _notifyingListeners = false;
    }
  }

}

class LabeledGlobalKey extends GlobalKey {
  // the label is purely for documentary purposes and does not affect the key
  const LabeledGlobalKey(this._label) : super.constructor();
  final String _label;
  String toString() => '[GlobalKey ${_label != null ? _label : hashCode}]';
}

class GlobalObjectKey extends GlobalKey {
  const GlobalObjectKey(this.value) : super.constructor();
  final Object value;
  String toString() => '[GlobalKey ${value.runtimeType}(${value.hashCode})]';
  bool operator==(other) => other is GlobalObjectKey && identical(other.value, value);
  int get hashCode => identityHashCode(value);
}

/// A base class for elements of the widget tree
abstract class Widget {

  Widget({ Key key }) : _key = key {
    assert(_isConstructedDuringBuild());
  }

  // TODO(jackson): Remove this workaround for limitation of Dart mixins
  Widget._withKey(Key key) : _key = key {
    assert(_isConstructedDuringBuild());
  }

  // you should not build the UI tree ahead of time, build it only during build()
  bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inBuildDirtyComponents || _inLayoutCallbackBuilder > 0;

  Key _key;

  /// A semantic identifer for this widget
  ///
  /// Keys are used to find matches when synchronizing two widget trees, for
  /// example after a [Component] rebuilds. Without keys, two widgets can match
  /// if their runtimeType matches. With keys, the keys must match as well.
  /// Assigning a key to a widget can improve performance by causing the
  /// framework to sync widgets that share a lot of common structure and can
  /// help match stateful components semantically rather than positionally.
  Key get key => _key;

  Widget _parent;

  /// The parent of this widget in the widget tree.
  Widget get parent => _parent;

  bool _mounted = false;
  bool _wasMounted = false;
  bool get mounted => _mounted;
  static bool _notifyingMountStatus = false;
  static List<Widget> _mountedChanged = new List<Widget>();

  /// Called during the synchronizing process to update the widget's parent.
  void setParent(Widget newParent) {
    assert(!_notifyingMountStatus);
    if (_parent == newParent)
      return;
    _parent = newParent;
    if (newParent == null) {
      if (_mounted) {
        _mounted = false;
        _mountedChanged.add(this);
      }
    } else {
      assert(newParent._mounted);
      if (_parent._mounted != _mounted) {
        _mounted = _parent._mounted;
        _mountedChanged.add(this);
      }
    }
  }

  /// Walks the immediate children of this widget
  ///
  /// Override this if you have children and call walker on each child.
  /// Note that you may be called before the child has had its parent
  /// pointer set to point to you. Your walker, and any methods it
  /// invokes on your descendants, should not rely on the ancestor
  /// chain being correctly configured at this point.
  void walkChildren(WidgetTreeWalker walker) { }

  static void _notifyMountStatusChanged() {
    try {
      sky.tracing.begin("Widget._notifyMountStatusChanged");
      _notifyingMountStatus = true;
      for (Widget node in _mountedChanged) {
        if (node._wasMounted != node._mounted) {
          if (node._mounted)
            node.didMount();
          else
            node.didUnmount();
          node._wasMounted = node._mounted;
        }
      }
      _mountedChanged.clear();
    } finally {
      _notifyingMountStatus = false;
      sky.tracing.end("Widget._notifyMountStatusChanged");
    }
    GlobalKey._notifyListeners();
  }

  /// Override this function to learn when this [Widget] enters the widget tree.
  void didMount() {
    if (key is GlobalKey)
      (key as GlobalKey)._register(this); // TODO(ianh): remove cast when analyzer is cleverer
  }

  /// Override this function to learn when this [Widget] leaves the widget tree.
  void didUnmount() {
    if (key is GlobalKey)
      (key as GlobalKey)._unregister(this); // TODO(ianh): remove cast when analyzer is cleverer
  }

  RenderObject _renderObject;

  /// The underlying [RenderObject] associated with this [Widget].
  RenderObject get renderObject => _renderObject;

  // Subclasses which implements Nodes that become stateful may return true
  // if the node has become stateful and should be retained.
  // This is called immediately before _sync().
  // Component.retainStatefulNodeIfPossible() calls syncConstructorArguments().
  bool retainStatefulNodeIfPossible(Widget newNode) => false;

  void _sync(Widget old, dynamic slot) {
    if (key is GlobalKey)
      (key as GlobalKey)._didSync(); // TODO(ianh): Remove the cast once the analyzer is cleverer.
  }
  void updateSlot(dynamic newSlot);
  // 'slot' is the identifier that the ancestor RenderObjectWrapper uses to know
  // where to put this descendant. If you just defer to a child, then make sure
  // to pass them the slot.

  Widget findAncestorRenderObjectWrapper() {
    var ancestor = _parent;
    while (ancestor != null && ancestor is! RenderObjectWrapper)
      ancestor = ancestor._parent;
    return ancestor;
  }

  Set<Type> _dependencies;
  Inherited inheritedOfType(Type targetType) {
    if (_dependencies == null)
      _dependencies = new Set<Type>();
    _dependencies.add(targetType);
    Widget ancestor = parent;
    while (ancestor != null && ancestor.runtimeType != targetType)
      ancestor = ancestor.parent;
    return ancestor;
  }

  void dependenciesChanged() {
    // This is called if you've use inheritedOfType and the Inherited
    // ancestor you were provided was changed. For a widget to use Inherited
    // it needs an implementation of dependenciesChanged. If your widget extends
    // Component or RenderObjectWrapper this is provided for you automatically.
    // If you aren't able to extend one of those classes, you need to
    // provide your own implementation of dependenciesChanged.
    assert(false);
  }

  void remove() {
    walkChildren((Widget child) => child.remove());
    _renderObject = null;
    setParent(null);
  }

  void detachRenderObject();

  // Returns the child which should be retained as the child of this node.
  Widget syncChild(Widget newNode, Widget oldNode, dynamic slot) {

    if (newNode == oldNode) {
      assert(newNode == null || newNode.mounted);
      assert(newNode is! RenderObjectWrapper ||
             (newNode is RenderObjectWrapper && newNode._ancestor != null)); // TODO(ianh): Simplify this once the analyzer is cleverer
      if (newNode != null)
        newNode.setParent(this);
      return newNode; // Nothing to do. Subtrees must be identical.
    }

    if (newNode == null) {
      // the child in this slot has gone away
      assert(oldNode.mounted);
      oldNode.detachRenderObject();
      oldNode.remove();
      assert(!oldNode.mounted);
      return null;
    }

    if (oldNode != null) {
      if (_canSync(newNode, oldNode)) {
        if (oldNode.retainStatefulNodeIfPossible(newNode)) {
          assert(oldNode.mounted);
          assert(!newNode.mounted);
          oldNode.setParent(this);
          oldNode._sync(newNode, slot);
          assert(oldNode.renderObject is RenderObject);
          return oldNode;
        } else {
          oldNode.setParent(null);
        }
      } else {
        assert(oldNode.mounted);
        oldNode.detachRenderObject();
        oldNode.remove();
        oldNode = null;
      }
    }

    assert(oldNode == null || (oldNode.mounted == false && oldNode.parent == null));
    assert(!newNode.mounted);
    newNode.setParent(this);
    newNode._sync(oldNode, slot);
    assert(newNode.renderObject is RenderObject);
    return newNode;
  }

  String _adjustPrefixWithParentCheck(Widget child, String prefix) {
    if (child.parent == this)
      return prefix;
    if (child.parent == null)
      return '$prefix [[DISCONNECTED]] ';
    return '$prefix [[PARENT IS ${child.parent.toStringName()}]] ';
  }

  String toString([String prefix = '', String startPrefix = '']) {
    String childrenString = '';
    List<Widget> children = new List<Widget>();
    walkChildren(children.add);
    if (children.length > 0) {
      Widget lastChild = children.removeLast();
      String nextStartPrefix = prefix + ' +-';
      String nextPrefix = prefix + ' | ';
      for (Widget child in children)
        childrenString += child.toString(nextPrefix, _adjustPrefixWithParentCheck(child, nextStartPrefix));
      nextStartPrefix = prefix + ' \'-';
      nextPrefix = prefix + '   ';
      childrenString += lastChild.toString(nextPrefix, _adjustPrefixWithParentCheck(lastChild, nextStartPrefix));
    }
    return '$startPrefix${toStringName()}\n$childrenString';
  }
  String toStringName() {
    if (key == null)
      return '$runtimeType(unkeyed; hashCode=$hashCode)';
    return '$runtimeType($key; hashCode=$hashCode)';
  }

  // This function can be safely called when the layout is valid.
  // For example Listener or SizeObserver callbacks can safely call
  // globalToLocal().
  Point globalToLocal(Point point) {
    assert(mounted);
    assert(renderObject is RenderBox);
    return (renderObject as RenderBox).globalToLocal(point);
  }

  // See globalToLocal().
  Point localToGlobal(Point point) {
    assert(mounted);
    assert(renderObject is RenderBox);
    return (renderObject as RenderBox).localToGlobal(point);
  }
}

bool _canSync(Widget a, Widget b) {
  return a.runtimeType == b.runtimeType && a.key == b.key;
}


// Descendants of TagNode provide a way to tag RenderObjectWrapper and
// Component nodes with annotations, such as event listeners,
// stylistic information, etc.
abstract class TagNode extends Widget {

  TagNode(Widget child, { Key key })
    : this.child = child, super(key: key);

  // TODO(jackson): Remove this workaround for limitation of Dart mixins
  TagNode._withKey(Widget child, Key key)
    : this.child = child, super._withKey(key);

  Widget child;

  void walkChildren(WidgetTreeWalker walker) {
    if (child != null)
      walker(child);
  }

  void _sync(Widget old, dynamic slot) {
    Widget oldChild = old == null ? null : (old as TagNode).child;
    child = syncChild(child, oldChild, slot);
    if (child != null) {
      assert(child.parent == this);
      assert(child.renderObject != null);
      _renderObject = child.renderObject;
      assert(_renderObject == renderObject); // in case a subclass reintroduces it
    } else {
      _renderObject = null;
    }
    super._sync(old, slot);
  }

  void updateSlot(dynamic newSlot) {
    child.updateSlot(newSlot);
  }

  void detachRenderObject() {
    if (child != null)
      child.detachRenderObject();
  }

}

class ParentDataNode extends TagNode {
  ParentDataNode(Widget child, this.parentData, { Key key })
    : super(child, key: key);
  final ParentData parentData;
}

abstract class Inherited extends TagNode {

  Inherited({ Key key, Widget child }) : super._withKey(child, key);

  void _sync(Widget old, dynamic slot) {
    if (old != null) {
      if (syncShouldNotify(old))
        notifyDescendants();
    }
    super._sync(old, slot);
  }

  void notifyDescendants() {
    final Type ourRuntimeType = runtimeType;
    void notifyChildren(Widget child) {
      if (child._dependencies != null &&
          child._dependencies.contains(ourRuntimeType))
          child.dependenciesChanged();
      if (child.runtimeType != ourRuntimeType)
        child.walkChildren(notifyChildren);
    }
    walkChildren(notifyChildren);
  }

  bool syncShouldNotify(Inherited old);

}

typedef EventDisposition GestureEventListener(sky.GestureEvent e);
typedef EventDisposition PointerEventListener(sky.PointerEvent e);
typedef EventDisposition EventListener(sky.Event e);

class Listener extends TagNode  {

  Listener({
    Key key,
    Widget child,
    EventListener onWheel,
    GestureEventListener onGestureFlingCancel,
    GestureEventListener onGestureFlingStart,
    GestureEventListener onGestureScrollStart,
    GestureEventListener onGestureScrollUpdate,
    GestureEventListener onGestureLongPress,
    GestureEventListener onGestureTap,
    GestureEventListener onGestureTapDown,
    GestureEventListener onGestureShowPress,
    PointerEventListener onPointerCancel,
    PointerEventListener onPointerDown,
    PointerEventListener onPointerMove,
    PointerEventListener onPointerUp,
    Map<String, EventListener> custom
  }) : listeners = _createListeners(
         onWheel: onWheel,
         onGestureFlingCancel: onGestureFlingCancel,
         onGestureFlingStart: onGestureFlingStart,
         onGestureScrollUpdate: onGestureScrollUpdate,
         onGestureScrollStart: onGestureScrollStart,
         onGestureTap: onGestureTap,
         onGestureTapDown: onGestureTapDown,
         onGestureLongPress: onGestureLongPress,
         onGestureShowPress: onGestureShowPress,
         onPointerCancel: onPointerCancel,
         onPointerDown: onPointerDown,
         onPointerMove: onPointerMove,
         onPointerUp: onPointerUp,
         custom: custom
       ),
       super(child, key: key);

  final Map<String, EventListener> listeners;

  static Map<String, EventListener> _createListeners({
    EventListener onWheel,
    GestureEventListener onGestureFlingCancel,
    GestureEventListener onGestureFlingStart,
    GestureEventListener onGestureScrollStart,
    GestureEventListener onGestureScrollUpdate,
    GestureEventListener onGestureTap,
    GestureEventListener onGestureTapDown,
    GestureEventListener onGestureLongPress,
    GestureEventListener onGestureShowPress,
    PointerEventListener onPointerCancel,
    PointerEventListener onPointerDown,
    PointerEventListener onPointerMove,
    PointerEventListener onPointerUp,
    Map<String, EventListener> custom
  }) {
    var listeners = custom != null ?
        new HashMap<String, EventListener>.from(custom) :
        new HashMap<String, EventListener>();

    if (onWheel != null)
      listeners['wheel'] = onWheel;
    if (onGestureFlingCancel != null)
      listeners['gestureflingcancel'] = onGestureFlingCancel;
    if (onGestureFlingStart != null)
      listeners['gestureflingstart'] = onGestureFlingStart;
    if (onGestureScrollStart != null)
      listeners['gesturescrollstart'] = onGestureScrollStart;
    if (onGestureScrollUpdate != null)
      listeners['gesturescrollupdate'] = onGestureScrollUpdate;
    if (onGestureTap != null)
      listeners['gesturetap'] = onGestureTap;
    if (onGestureTapDown != null)
      listeners['gesturetapdown'] = onGestureTapDown;
    if (onGestureLongPress != null)
      listeners['gesturelongpress'] = onGestureLongPress;
    if (onGestureShowPress != null)
      listeners['gestureshowpress'] = onGestureShowPress;
    if (onPointerCancel != null)
      listeners['pointercancel'] = onPointerCancel;
    if (onPointerDown != null)
      listeners['pointerdown'] = onPointerDown;
    if (onPointerMove != null)
      listeners['pointermove'] = onPointerMove;
    if (onPointerUp != null)
      listeners['pointerup'] = onPointerUp;

    return listeners;
  }

  EventDisposition _handleEvent(sky.Event e) {
    EventListener listener = listeners[e.type];
    if (listener != null) {
      return listener(e);
    }
    return EventDisposition.ignored;
  }

}

abstract class Component extends Widget {

  Component({ Key key })
      : _order = _currentOrder + 1,
        super._withKey(key);

  bool _debugIsBuilding = false;
  static String _debugLastComponent;

  bool _dirty = true;

  Widget _child;
  dynamic _slot; // cached slot from the last time we were synced

  void updateSlot(dynamic newSlot) {
    _slot = newSlot;
    if (_child != null)
      _child.updateSlot(newSlot);
  }

  void walkChildren(WidgetTreeWalker walker) {
    if (_child != null)
      walker(_child);
  }

  void remove() {
    assert(_child != null);
    assert(renderObject != null);
    super.remove();
    _child = null;
  }

  void detachRenderObject() {
    assert(_child != null);
    assert(renderObject != null);
    _child.detachRenderObject();
  }

  void dependenciesChanged() {
    // called by Inherited.sync()
    _scheduleBuild();
  }

  // order corresponds to _build_ order, not depth in the tree.
  // All the Components built by a particular other Component will have the
  // same order, regardless of whether one is subsequently inserted
  // into another. The order is used to not tell a Component to
  // rebuild if the Component that it built has itself been rebuilt.
  final int _order;
  static int _currentOrder = 0;

  // There are three cases here:
  // 1) Building for the first time:
  //      assert(_child == null && old == null)
  // 2) Re-building (because a dirty flag got set):
  //      assert(_child != null && old == null)
  // 3) Syncing against an old version
  //      assert(_child == null && old != null)
  void _sync(Component old, dynamic slot) {
    assert(_child == null || old == null);

    updateSlot(slot);

    Widget oldChild;
    if (old == null) {
      oldChild = _child;
    } else {
      assert(_child == null);
      oldChild = old._child;
    }

    String _debugPreviousComponent;
    assert(() {
      _debugIsBuilding = true;
      _debugPreviousComponent = _debugLastComponent;
      if (_debugLastComponent != null)
        _debugLastComponent = "$_debugPreviousComponent -> ${this.toStringName()}";
      else
        _debugLastComponent = "Build chain: ${this.toStringName()}";
      return true;
    });

    int lastOrder = _currentOrder;
    _currentOrder = _order;
    _child = build();
    _currentOrder = lastOrder;
    assert(_child != null);
    _child = syncChild(_child, oldChild, slot);
    assert(_child != null);
    assert(_child.parent == this);

    assert(() {
      _debugIsBuilding = false;
      _debugLastComponent = _debugPreviousComponent;
      return true;
    });

    _dirty = false;
    _renderObject = _child.renderObject;
    assert(_renderObject == renderObject); // in case a subclass reintroduces it
    assert(renderObject != null);
    super._sync(old, slot);
  }

  void _buildIfDirty() {
    if (!_dirty || !_mounted)
      return;
    assert(renderObject != null);
    _sync(null, _slot);
  }

  void _scheduleBuild() {
    assert(!_debugIsBuilding);
    if (_dirty || !_mounted)
      return;
    _dirty = true;
    _scheduleComponentForRender(this);
  }

  static void flushBuild() {
    if (!_dirtyComponents.isEmpty)
      _buildDirtyComponents();
  }

  Widget build();

}

abstract class StatefulComponent extends Component {

  StatefulComponent({ Key key }) : super(key: key);

  bool _disqualifiedFromEverAppearingAgain = false;
  bool _isStateInitialized = false;

  void didMount() {
    assert(!_disqualifiedFromEverAppearingAgain);
    super.didMount();
  }

  void _buildIfDirty() {
    assert(!_disqualifiedFromEverAppearingAgain);
    super._buildIfDirty();
  }

  bool retainStatefulNodeIfPossible(StatefulComponent newNode) {
    assert(!_disqualifiedFromEverAppearingAgain);
    assert(newNode != null);
    assert(_canSync(this, newNode));
    assert(_child != null);
    newNode._disqualifiedFromEverAppearingAgain = true;

    newNode._child = _child;
    _child = null;
    _dirty = true;

    return true;
  }

  // because our retainStatefulNodeIfPossible() method returns true,
  // when _sync is called, our 'old' is actually the new instance that
  // we are to copy state from.
  void _sync(Widget old, dynamic slot) {
    assert(!_disqualifiedFromEverAppearingAgain);
    // TODO(ianh): _sync should only be called once when old == null
    if (old == null && !_isStateInitialized) {
      initState();
      _isStateInitialized = true;
    }
    if (old != null)
      syncConstructorArguments(old);
    super._sync(old, slot);
  }

  // Stateful components can override initState if they want
  // to do non-trivial work to initialize state. This is
  // always called before build().
  void initState() { }

  // This is called by _sync(). Derived classes should override this
  // method to update `this` to account for the new values the parent
  // passed to `source`. Make sure to call super.syncConstructorArguments(source)
  // unless you are extending StatefulComponent directly.
  void syncConstructorArguments(Component source);

  Widget syncChild(Widget node, Widget oldNode, dynamic slot) {
    assert(!_disqualifiedFromEverAppearingAgain);
    return super.syncChild(node, oldNode, slot);
  }

  // Calls function fn immediately and then schedules another build
  // for this Component.
  void setState(void fn()) {
    assert(!_disqualifiedFromEverAppearingAgain);
    fn();
    _scheduleBuild();
  }
}

Set<Component> _dirtyComponents = new Set<Component>();
bool _buildScheduled = false;
bool _inBuildDirtyComponents = false;
int _inLayoutCallbackBuilder = 0;

class LayoutCallbackBuilderHandle { bool _active = true; }
LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() {
  LayoutCallbackBuilderHandle result;
  assert(() {
    _inLayoutCallbackBuilder += 1;
    result = new LayoutCallbackBuilderHandle();
    return true;
  });
  return result;
}
void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) {
  assert(() {
    assert(handle._active);
    handle._active = false;
    _inLayoutCallbackBuilder -= 1;
    return true;
  });
  Widget._notifyMountStatusChanged();
}

List<int> _debugFrameTimes = <int>[];

void _absorbDirtyComponents(List<Component> list) {
  list.addAll(_dirtyComponents);
  _dirtyComponents.clear();
  list.sort((Component a, Component b) => a._order - b._order);
}

void _buildDirtyComponents() {
  assert(!_dirtyComponents.isEmpty);

  Stopwatch sw;
  if (_shouldLogRenderDuration)
    sw = new Stopwatch()..start();

  while (!_dirtyComponents.isEmpty) {
    _inBuildDirtyComponents = true;
    try {
      sky.tracing.begin('Component.flushBuild');
      List<Component> sortedDirtyComponents = new List<Component>();
      _absorbDirtyComponents(sortedDirtyComponents);
      int index = 0;
      while (index < sortedDirtyComponents.length) {
        Component component = sortedDirtyComponents[index];
        component._buildIfDirty();
        if (_dirtyComponents.length > 0) {
          // the following assert verifies that we're not rebuilding anyone twice in one frame
          assert(_dirtyComponents.every((Component component) => !sortedDirtyComponents.contains(component)));
          _absorbDirtyComponents(sortedDirtyComponents);
          index = 0;
        } else {
          index += 1;
        }
      }
    } finally {
      _buildScheduled = false;
      _inBuildDirtyComponents = false;
      sky.tracing.end('Component.flushBuild');
    }

    Widget._notifyMountStatusChanged();
  }

  if (_shouldLogRenderDuration) {
    sw.stop();
    _debugFrameTimes.add(sw.elapsedMicroseconds);
    if (_debugFrameTimes.length >= 1000) {
      _debugFrameTimes.sort();
      const int i = 99;
      print('Component.flushBuild: ${i+1}th fastest frame out of the last ${_debugFrameTimes.length}: ${_debugFrameTimes[i]} microseconds');
      _debugFrameTimes.clear();
    }
  }
}

void _scheduleComponentForRender(Component component) {
  _dirtyComponents.add(component);
  if (!_buildScheduled) {
    _buildScheduled = true;
    scheduler.ensureVisualUpdate();
  }
}

// RenderObjectWrappers correspond to a desired state of a
// RenderObject. They are fully immutable, except that a Widget which
// is a Component which lives within a RenderObjectWrapper's children
// list may be in-place replaced with the "old" instance if it has
// become stateful.
abstract class RenderObjectWrapper extends Widget {

  RenderObjectWrapper({ Key key }) : super(key: key);

  RenderObject createNode();

  static final Map<RenderObject, RenderObjectWrapper> _nodeMap =
      new HashMap<RenderObject, RenderObjectWrapper>();
  static RenderObjectWrapper _getMounted(RenderObject node) => _nodeMap[node];

  static Iterable<Widget> getWidgetsForRenderObject(RenderObject renderObject) sync* {
    Widget target = RenderObjectWrapper._getMounted(renderObject);
    if (target == null)
      return;
    RenderObject targetRenderObject = target.renderObject;
    while (target != null && target.renderObject == targetRenderObject) {
      yield target;
      target = target.parent;
    }
  }

  RenderObjectWrapper _ancestor;
  void insertChildRenderObject(RenderObjectWrapper child, dynamic slot);
  void detachChildRenderObject(RenderObjectWrapper child);

  void retainStatefulRenderObjectWrapper(RenderObjectWrapper newNode) {
    newNode._renderObject = _renderObject;
    newNode._ancestor = _ancestor;
  }

  void _sync(RenderObjectWrapper old, dynamic slot) {
    // TODO(abarth): We should split RenderObjectWrapper into two pieces so that
    //               RenderViewObject doesn't need to inherit all this code it
    //               doesn't need.
    assert(parent != null || this is RenderViewWrapper);
    if (old == null) {
      _renderObject = createNode();
      assert(_renderObject != null);
      _ancestor = findAncestorRenderObjectWrapper();
      if (_ancestor is RenderObjectWrapper)
        _ancestor.insertChildRenderObject(this, slot);
    } else {
      assert(_canSync(this, old));
      _renderObject = old.renderObject;
      _ancestor = old._ancestor;
      assert(_renderObject != null);
    }
    assert(() {
      _renderObject.debugExceptionContext = Component._debugLastComponent;
      return true;
    });
    assert(_renderObject == renderObject); // in case a subclass reintroduces it
    assert(renderObject != null);
    assert(mounted);
    _nodeMap[renderObject] = this;
    syncRenderObject(old);
    super._sync(old, slot);
  }

  void updateSlot(dynamic newSlot) {
    // We never use the slot except during sync(), in which
    // case our parent is handing it to us anyway.
    // We don't need to propagate this to our children, since
    // we give them their own slots for them to fit into us.
  }

  void syncRenderObject(RenderObjectWrapper old) {
    ParentData parentData = null;
    Widget ancestor = parent;
    while (ancestor != null && ancestor is! RenderObjectWrapper) {
      if (ancestor is ParentDataNode && ancestor.parentData != null) {
        if (parentData != null)
          parentData.merge(ancestor.parentData); // this will throw if the types aren't the same
        else
          parentData = ancestor.parentData;
      }
      ancestor = ancestor.parent;
    }
    if (parentData != null) {
      assert(renderObject.parentData != null);
      renderObject.parentData.merge(parentData); // this will throw if the types aren't appropriate
      if (ancestor != null && ancestor.renderObject != null)
        ancestor.renderObject.markNeedsLayout();
    }
  }

  void dependenciesChanged() {
    // called by Inherited.sync()
    syncRenderObject(this);
  }

  void remove() {
    assert(renderObject != null);
    _nodeMap.remove(renderObject);
    super.remove();
  }

  void detachRenderObject() {
    assert(_ancestor != null);
    assert(renderObject != null);
    _ancestor.detachChildRenderObject(this);
  }

}

abstract class LeafRenderObjectWrapper extends RenderObjectWrapper {

  LeafRenderObjectWrapper({ Key key }) : super(key: key);

  void insertChildRenderObject(RenderObjectWrapper child, dynamic slot) {
    assert(false);
  }

  void detachChildRenderObject(RenderObjectWrapper child) {
    assert(false);
  }

}

abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {

  OneChildRenderObjectWrapper({ Key key, Widget child })
    : _child = child, super(key: key);

  Widget _child;
  Widget get child => _child;

  void walkChildren(WidgetTreeWalker walker) {
    if (child != null)
      walker(child);
  }

  void syncRenderObject(RenderObjectWrapper old) {
    super.syncRenderObject(old);
    Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).child;
    Widget newChild = child;
    _child = syncChild(newChild, oldChild, null);
    assert((newChild == null && child == null) || (newChild != null && child.parent == this));
    assert(oldChild == null || child == oldChild || oldChild.parent == null);
  }

  void insertChildRenderObject(RenderObjectWrapper child, dynamic slot) {
    final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
    assert(renderObject is RenderObjectWithChildMixin);
    assert(slot == null);
    renderObject.child = child.renderObject;
    assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
  }

  void detachChildRenderObject(RenderObjectWrapper child) {
    final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
    assert(renderObject is RenderObjectWithChildMixin);
    assert(renderObject.child == child.renderObject);
    renderObject.child = null;
    assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
  }
}

abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {

  // In MultiChildRenderObjectWrapper subclasses, slots are the Widget
  // nodes whose RenderObjects are to be used as the "insert before"
  // sibling in ContainerRenderObjectMixin.add() calls

  MultiChildRenderObjectWrapper({ Key key, List<Widget> children })
    : this.children = children == null ? const [] : children,
      super(key: key) {
    assert(!_debugHasDuplicateIds());
  }

  final List<Widget> children;

  void walkChildren(WidgetTreeWalker walker) {
    for (Widget child in children)
      walker(child);
  }

  void insertChildRenderObject(RenderObjectWrapper child, Widget slot) {
    final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
    RenderObject nextSibling = slot != null ? slot.renderObject : null;
    assert(nextSibling == null || nextSibling is RenderObject);
    assert(renderObject is ContainerRenderObjectMixin);
    renderObject.add(child.renderObject, before: nextSibling);
    assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
  }

  void detachChildRenderObject(RenderObjectWrapper child) {
    final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
    assert(renderObject is ContainerRenderObjectMixin);
    assert(child.renderObject.parent == renderObject);
    renderObject.remove(child.renderObject);
    assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
  }

  bool _debugHasDuplicateIds() {
    var idSet = new HashSet<Key>();
    for (var child in children) {
      assert(child != null);
      if (child.key == null)
        continue; // when these nodes are reordered, we just reassign the data

      if (!idSet.add(child.key)) {
        throw '''If multiple keyed nodes exist as children of another node, they must have unique keys. $this has duplicate child key "${child.key}".''';
      }
    }
    return false;
  }

  void syncRenderObject(MultiChildRenderObjectWrapper old) {
    super.syncRenderObject(old);

    final ContainerRenderObjectMixin renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
    assert(renderObject is ContainerRenderObjectMixin);
    assert(old == null || old.renderObject == renderObject);

    // This attempts to diff the new child list (this.children) with
    // the old child list (old.children), and update our renderObject
    // accordingly.

    // The cases it tries to optimise for are:
    //  - the old list is empty
    //  - the lists are identical
    //  - there is an insertion or removal of one or more widgets in
    //    only one place in the list
    // If a widget with a key is in both lists, it will be synced.
    // Widgets without keys might be synced but there is no guarantee.

    // The general approach is to sync the entire new list backwards, as follows:
    // 1. Walk the lists from the top until you no longer have
    //    matching nodes. We don't sync these yet, but we now know to
    //    skip them below. We do this because at each sync we need to
    //    pass the pointer to the new next widget as the slot, which
    //    we can't do until we've synced the next child.
    // 2. Walk the lists from the bottom, syncing nodes, until you no
    //    longer have matching nodes.
    // At this point we narrowed the old and new lists to the point
    // where the nodes no longer match.
    // 3. Walk the narrowed part of the old list to get the list of
    //    keys and sync null with non-keyed items.
    // 4. Walk the narrowed part of the new list backwards:
    //     * Sync unkeyed items with null
    //     * Sync keyed items with the source if it exists, else with null.
    // 5. Walk the top list again but backwards, syncing the nodes.
    // 6. Sync null with any items in the list of keys that are still
    //    mounted.

    final List<Widget> newChildren = children;
    final List<Widget> oldChildren = old == null ? const <Widget>[] : old.children;
    int childrenTop = 0;
    int newChildrenBottom = newChildren.length-1;
    int oldChildrenBottom = oldChildren.length-1;

    // top of the lists
    while ((childrenTop <= oldChildrenBottom) && (childrenTop <= newChildrenBottom)) {
      Widget oldChild = oldChildren[childrenTop];
      assert(oldChild.mounted);
      Widget newChild = newChildren[childrenTop];
      assert(newChild == oldChild || !newChild.mounted);
      if (!_canSync(oldChild, newChild))
        break;
      childrenTop += 1;
    }

    Widget nextSibling;

    // bottom of the lists
    while ((childrenTop <= oldChildrenBottom) && (childrenTop <= newChildrenBottom)) {
      Widget oldChild = oldChildren[oldChildrenBottom];
      assert(oldChild.mounted);
      Widget newChild = newChildren[newChildrenBottom];
      assert(newChild == oldChild || !newChild.mounted);
      if (!_canSync(oldChild, newChild))
        break;
      newChild = syncChild(newChild, oldChild, nextSibling);
      assert(newChild.mounted);
      assert(oldChild == newChild || !oldChild.mounted);
      newChildren[newChildrenBottom] = newChild;
      nextSibling = newChild;
      oldChildrenBottom -= 1;
      newChildrenBottom -= 1;
    }

    // middle of the lists - old list
    bool haveOldNodes = childrenTop <= oldChildrenBottom;
    Map<Key, Widget> oldKeyedChildren;
    if (haveOldNodes) {
      oldKeyedChildren = new Map<Key, Widget>();
      while (childrenTop <= oldChildrenBottom) {
        Widget oldChild = oldChildren[oldChildrenBottom];
        assert(oldChild.mounted);
        if (oldChild.key != null) {
          oldKeyedChildren[oldChild.key] = oldChild;
        } else {
          syncChild(null, oldChild, null);
        }
        oldChildrenBottom -= 1;
      }
    }

    // middle of the lists - new list
    while (childrenTop <= newChildrenBottom) {
      Widget oldChild;
      Widget newChild = newChildren[newChildrenBottom];
      if (haveOldNodes) {
        Key key = newChild.key;
        if (key != null) {
          oldChild = oldKeyedChildren[newChild.key];
          if (oldChild != null) {
            if (oldChild.runtimeType != newChild.runtimeType)
              oldChild = null;
            oldKeyedChildren.remove(key);
          }
        }
      }
      assert(newChild == oldChild || !newChild.mounted);
      newChild = syncChild(newChild, oldChild, nextSibling);
      assert(newChild.mounted);
      assert(oldChild == newChild || oldChild == null || !oldChild.mounted);
      newChildren[newChildrenBottom] = newChild;
      nextSibling = newChild;
      newChildrenBottom -= 1;
    }
    assert(oldChildrenBottom == newChildrenBottom);
    assert(childrenTop == newChildrenBottom+1);

    // now sync the top of the list
    while (childrenTop > 0) {
      childrenTop -= 1;
      Widget oldChild = oldChildren[childrenTop];
      assert(oldChild.mounted);
      Widget newChild = newChildren[childrenTop];
      assert(newChild == oldChild || !newChild.mounted);
      assert(_canSync(oldChild, newChild));
      newChild = syncChild(newChild, oldChild, nextSibling);
      assert(newChild.mounted);
      assert(oldChild == newChild || oldChild == null || !oldChild.mounted);
      newChildren[childrenTop] = newChild;
      nextSibling = newChild;
    }

    if (haveOldNodes && !oldKeyedChildren.isEmpty) {
      for (Widget oldChild in oldKeyedChildren.values)
        syncChild(null, oldChild, null);
    }

    assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
  }

}

class WidgetSkyBinding extends SkyBinding {

  WidgetSkyBinding({ RenderView renderViewOverride: null })
      : super(renderViewOverride: renderViewOverride);

  static void initWidgetSkyBinding({ RenderView renderViewOverride: null }) {
    if (SkyBinding.instance == null)
      new WidgetSkyBinding(renderViewOverride: renderViewOverride);
    assert(SkyBinding.instance is WidgetSkyBinding);
  }

  EventDisposition dispatchEvent(sky.Event event, HitTestResult result) {
    assert(SkyBinding.instance == this);
    EventDisposition disposition = super.dispatchEvent(event, result);
    if (disposition == EventDisposition.consumed)
      return EventDisposition.consumed;
    for (HitTestEntry entry in result.path.reversed) {
      for (Widget target in RenderObjectWrapper.getWidgetsForRenderObject(entry.target)) {
        if (target is Listener) {
          EventDisposition targetDisposition = target._handleEvent(event);
          if (targetDisposition == EventDisposition.consumed) {
            return targetDisposition;
          } else if (targetDisposition == EventDisposition.processed) {
            disposition = EventDisposition.processed;
          }
        }
        target = target._parent;
      }
    }
    return disposition;
  }

  void beginFrame(double timeStamp) {
    Component.flushBuild();
    super.beginFrame(timeStamp);
  }

}

abstract class App extends StatefulComponent {

  App({ Key key }) : super(key: key);

  void _handleEvent(sky.Event event) {
    if (event.type == 'back')
      onBack();
  }

  void didMount() {
    super.didMount();
    SkyBinding.instance.addEventListener(_handleEvent);
  }

  void didUnmount() {
    super.didUnmount();
    SkyBinding.instance.removeEventListener(_handleEvent);
  }

  void syncConstructorArguments(Component source) { }

  // Override this to handle back button behavior in your app
  // Call super.onBack() to finish the activity
  void onBack() {
    activity.finishCurrentActivity();
  }
}

abstract class AbstractWidgetRoot extends StatefulComponent {

  AbstractWidgetRoot() {
    _mounted = true;
    _scheduleComponentForRender(this);
  }

  void syncConstructorArguments(AbstractWidgetRoot source) {
    assert(false);
    // if we get here, it implies that we have a parent
  }

  void _buildIfDirty() {
    assert(_dirty);
    assert(_mounted);
    assert(parent == null);
    _sync(null, null);
  }

}

class RenderViewWrapper extends OneChildRenderObjectWrapper {
  RenderViewWrapper({ Key key, Widget child }) : super(key: key, child: child);
  RenderView get renderObject => super.renderObject;
  RenderView createNode() => SkyBinding.instance.renderView;
}

class AppContainer extends AbstractWidgetRoot {
  AppContainer(this.app) {
    assert(SkyBinding.instance is WidgetSkyBinding);
  }
  final App app;
  Widget build() => new RenderViewWrapper(child: app);
}

AppContainer _container;
void runApp(App app, { RenderView renderViewOverride, bool enableProfilingLoop: false }) {
  WidgetSkyBinding.initWidgetSkyBinding(renderViewOverride: renderViewOverride);
  _container = new AppContainer(app);
  if (enableProfilingLoop) {
    new Timer.periodic(const Duration(milliseconds: 20), (_) {
      app._scheduleBuild();
    });
  }
}
void debugDumpApp() {
  if (_container != null)
    _container.toString().split('\n').forEach(print);
  else
    print("runApp() not yet called");
}


class RenderBoxToWidgetAdapter extends AbstractWidgetRoot {

  RenderBoxToWidgetAdapter(
    RenderObjectWithChildMixin<RenderBox> container,
    this.builder
  ) : _container = container, super() {
    assert(builder != null);
  }

  RenderObjectWithChildMixin<RenderBox> _container;
  RenderObjectWithChildMixin<RenderBox> get container => _container;
  void set container(RenderObjectWithChildMixin<RenderBox> value) {
    if (_container != value) {
      assert(value.child == null);
      if (renderObject != null) {
        assert(_container.child == renderObject);
        _container.child = null;
      }
      _container = value;
      if (renderObject != null) {
        _container.child = renderObject;
        assert(_container.child == renderObject);
      }
    }
  }

  final Builder builder;

  void _buildIfDirty() {
    super._buildIfDirty();
    if (renderObject.parent == null) {
      // we haven't attached it yet
      assert(_container.child == null);
      _container.child = renderObject;
    }
    assert(renderObject.parent == _container);
  }

  Widget build() => builder();
}
