// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of dart.async;

/**
 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous
 * callbacks are executed in the zone they have been queued in. For example,
 * the callback of a `future.then` is executed in the same zone as the one where
 * the `then` was invoked.
 */
abstract class _Zone {
  /// The currently running zone.
  static _Zone _current = new _DefaultZone();

  static _Zone get current => _current;

  void handleUncaughtError(error);

  /**
   * Returns true if `this` and [otherZone] are in the same error zone.
   */
  bool inSameErrorZone(_Zone otherZone);

  /**
   * Returns a zone for reentry in the zone.
   *
   * The returned zone is equivalent to `this` (and frequently is indeed
   * `this`).
   *
   * The main purpose of this method is to allow `this` to attach debugging
   * information to the returned zone.
   */
  _Zone fork();

  /**
   * Tells the zone that it needs to wait for one more callback before it is
   * done.
   *
   * Use [executeCallback] or [cancelCallbackExpectation] when the callback is
   * executed (or canceled).
   */
  void expectCallback();

  /**
   * Tells the zone not to wait for a callback anymore.
   *
   * Prefer calling [executeCallback], instead. This method is mostly useful
   * for repeated callbacks (for example with [Timer.periodic]). In this case
   * one should should call [expectCallback] when the repeated callback is
   * initiated, and [cancelCallbackExpectation] when the [Timer] is canceled.
   */
  void cancelCallbackExpectation();

  /**
   * Executes the given callback [f] in this zone.
   *
   * Decrements the number of callbacks this zone is waiting for (see
   * [expectCallback]).
   */
  void executeCallback(void f());

  /**
   * Same as [executeCallback] but catches uncaught errors and gives them to
   * [handleUncaughtError].
   */
  void executeCallbackGuarded(void f());

  /**
   * Same as [executeCallback] but does not decrement the number of
   * callbacks this zone is waiting for (see [expectCallback]).
   */
  void executePeriodicCallback(void f());

  /**
   * Same as [executePeriodicCallback] but catches uncaught errors and gives
   * them to [handleUncaughtError].
   */
  void executePeriodicCallbackGuarded(void f());

  /**
   * Executes [f] in `this` zone.
   *
   * The behavior of this method should be the same as
   * [executePeriodicCallback] except that it can have a return value.
   *
   * Returns the result of the invocation.
   */
  runFromChildZone(f());

  /**
   * Same as [runFromChildZone] but catches uncaught errors and gives them to
   * [handleUncaughtError].
   */
  runFromChildZoneGuarded(f());

  /**
   * Runs [f] asynchronously in [zone].
   */
  void runAsync(void f(), _Zone zone);

  /**
   * Creates a Timer where the callback is executed in this zone.
   */
  Timer createTimer(Duration duration, void callback());

  /**
   * Creates a periodic Timer where the callback is executed in this zone.
   */
  Timer createPeriodicTimer(Duration duration, void callback(Timer timer));

  /**
   * The error zone is the one that is responsible for dealing with uncaught
   * errors. Errors are not allowed to cross zones with different error-zones.
   */
  _Zone get _errorZone;

  /**
   * Adds [child] as a child of `this`.
   *
   * This usually means that the [child] is in the asynchronous dynamic extent
   * of `this`.
   */
  void _addChild(_Zone child);

  /**
   * Removes [child] from `this`' children.
   *
   * This usually means that the [child] has finished executing and is done.
   */
  void _removeChild(_Zone child);
}

/**
 * Basic implementation of a [_Zone]. This class is intended for subclassing.
 */
class _ZoneBase implements _Zone {
  /// The parent zone. [null] if `this` is the default zone.
  final _Zone _parentZone;

  /// The number of children of this zone. A child's [_parentZone] is `this`.
  int _childCount = 0;

  /// The number of outstanding (asynchronous) callbacks. As long as the
  /// number is greater than 0 it means that the zone is not done yet.
  int _openCallbacks = 0;

  bool _isExecutingCallback = false;

  _ZoneBase(this._parentZone) {
    _parentZone._addChild(this);
  }

  _ZoneBase._defaultZone() : _parentZone = null {
    assert(this is _DefaultZone);
  }

  _Zone get _errorZone => _parentZone._errorZone;

  void handleUncaughtError(error) {
    _parentZone.handleUncaughtError(error);
  }

  bool inSameErrorZone(_Zone otherZone) => _errorZone == otherZone._errorZone;

  _Zone fork() => this;

  expectCallback() => _openCallbacks++;

  cancelCallbackExpectation() {
    _openCallbacks--;
    _checkIfDone();
  }

  /**
   * Cleans up this zone when it is done.
   *
   * This releases internal memore structures that are no longer necessary.
   *
   * A zone is done when its dynamic extent has finished executing and
   * there are no outstanding asynchronous callbacks.
   */
  _dispose() {
    if (_parentZone != null) {
      _parentZone._removeChild(this);
    }
  }

  /**
   * Checks if the zone is done and doesn't have any outstanding callbacks
   * anymore.
   *
   * This method is called when an operation has decremented the
   * outstanding-callback count, or when a child has been removed.
   */
  void _checkIfDone() {
    if (!_isExecutingCallback && _openCallbacks == 0 && _childCount == 0) {
      _dispose();
    }
  }

  void executeCallback(void f()) {
    _openCallbacks--;
    this._runUnguarded(f);
  }

  void executeCallbackGuarded(void f()) {
    _openCallbacks--;
    this._runGuarded(f);
  }

  void executePeriodicCallback(void f()) {
    this._runUnguarded(f);
  }

  void executePeriodicCallbackGuarded(void f()) {
    this._runGuarded(f);
  }

  runFromChildZone(f()) => this._runUnguarded(f);
  runFromChildZoneGuarded(f()) => this._runGuarded(f);

  _runInZone(f(), bool handleUncaught) {
    if (identical(_Zone._current, this)
        && !handleUncaught
        && _isExecutingCallback) {
      // No need to go through a try/catch.
      return f();
    }

    _Zone oldZone = _Zone._current;
    _Zone._current = this;
    // While we are executing the function we don't want to have other
    // synchronous calls to think that they closed the zone. By incrementing
    // the _openCallbacks count we make sure that their test will fail.
    // As a side effect it will make nested calls faster since they are
    // (probably) in the same zone and have an _openCallbacks > 0.
    bool oldIsExecuting = _isExecutingCallback;
    _isExecutingCallback = true;
    // TODO(430): remove second try when VM bug is fixed.
    try {
      try {
        return f();
      } catch(e, s) {
        if (handleUncaught) {
          handleUncaughtError(_asyncError(e, s));
        } else {
          rethrow;
        }
      }
    } finally {
      _isExecutingCallback = oldIsExecuting;
      _Zone._current = oldZone;
      _checkIfDone();
    }
  }

  /**
   * Runs the function and catches uncaught errors.
   *
   * Uncaught errors are given to [handleUncaughtError].
   */
  _runGuarded(void f()) {
    return _runInZone(f, true);
  }

  /**
   * Runs the function but doesn't catch uncaught errors.
   */
  _runUnguarded(void f()) {
    return _runInZone(f, false);
  }

  runAsync(void f(), _Zone zone) => _parentZone.runAsync(f, zone);

  // TODO(floitsch): the zone should just forward to the parent zone. The
  // default zone should then create the _ZoneTimer.
  Timer createTimer(Duration duration, void callback()) {
    return new _ZoneTimer(this, duration, callback);
  }

  // TODO(floitsch): the zone should just forward to the parent zone. The
  // default zone should then create the _ZoneTimer.
  Timer createPeriodicTimer(Duration duration, void callback(Timer timer)) {
    return new _PeriodicZoneTimer(this, duration, callback);
  }

  void _addChild(_Zone child) {
    _childCount++;
  }

  void _removeChild(_Zone child) {
    assert(_childCount != 0);
    _childCount--;
    _checkIfDone();
  }
}

/**
 * The default-zone that conceptually surrounds the `main` function.
 */
class _DefaultZone extends _ZoneBase {
  _DefaultZone() : super._defaultZone();

  _Zone get _errorZone => this;

  handleUncaughtError(error) {
    _scheduleAsyncCallback(() {
      print("Uncaught Error: ${error}");
      var trace = getAttachedStackTrace(error);
      _attachStackTrace(error, null);
      if (trace != null) {
        print("Stack Trace:\n$trace\n");
      }
      throw error;
    });
  }

  void runAsync(void f(), _Zone zone) {
    if (identical(this, zone)) {
      // No need to go through the zone when it's the default zone anyways.
      _scheduleAsyncCallback(f);
      return;
    }
    zone.expectCallback();
    _scheduleAsyncCallback(() {
      zone.executeCallbackGuarded(f);
    });
  }
}

typedef void _CompletionCallback();

/**
 * A zone that executes a callback when the zone is dead.
 */
class _WaitForCompletionZone extends _ZoneBase {
  final _CompletionCallback _onDone;

  _WaitForCompletionZone(_Zone parentZone, this._onDone) : super(parentZone);

  /**
   * Runs the given function asynchronously. Executes the [_onDone] callback
   * when the zone is done.
   */
  runWaitForCompletion(void f()) {
    return this._runUnguarded(f);
  }

  _dispose() {
    super._dispose();
    _onDone();
  }

  String toString() => "WaitForCompletion ${super.toString()}";
}

typedef void _HandleErrorCallback(error);

/**
 * A zone that collects all uncaught errors and provides them in a stream.
 * The stream is closed when the zone is done.
 */
class _CatchErrorsZone extends _WaitForCompletionZone {
  final _HandleErrorCallback _handleError;

  _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone())
      : super(parentZone, onDone);

  _Zone get _errorZone => this;

  handleUncaughtError(error) {
    try {
      _handleError(error);
    } catch(e, s) {
      if (identical(e, s)) {
        _parentZone.handleUncaughtError(error);
      } else {
        _parentZone.handleUncaughtError(_asyncError(e, s));
      }
    }
  }

  /**
   * Runs the given function asynchronously. Executes the [_onDone] callback
   * when the zone is done.
   */
  runWaitForCompletion(void f()) {
    return this._runGuarded(f);
  }

  String toString() => "CatchErrors ${super.toString()}";
}

typedef void _RunAsyncInterceptor(void callback());

class _RunAsyncZone extends _ZoneBase {
  final _RunAsyncInterceptor _runAsyncInterceptor;

  _RunAsyncZone(_Zone parentZone, this._runAsyncInterceptor)
      : super(parentZone);

  void runAsync(void callback(), _Zone zone) {
    zone.expectCallback();
    _parentZone.runFromChildZone(() {
      _runAsyncInterceptor(() => zone.executeCallbackGuarded(callback));
    });
  }
}

typedef void _TimerCallback();

/**
 * A [Timer] class that takes zones into account.
 */
class _ZoneTimer implements Timer {
  final _Zone _zone;
  final _TimerCallback _callback;
  Timer _timer;

  _ZoneTimer(this._zone, Duration duration, this._callback) {
    _zone.expectCallback();
    _timer = _createTimer(duration, this._run);
  }

  void _run() {
    _zone.executeCallbackGuarded(_callback);
  }

  void cancel() {
    if (_timer.isActive) _zone.cancelCallbackExpectation();
    _timer.cancel();
  }

  bool get isActive => _timer.isActive;
}

typedef void _PeriodicTimerCallback(Timer timer);

/**
 * A [Timer] class for periodic callbacks that takes zones into account.
 */
class _PeriodicZoneTimer implements Timer {
  final _Zone _zone;
  final _PeriodicTimerCallback _callback;
  Timer _timer;

  _PeriodicZoneTimer(this._zone, Duration duration, this._callback) {
    _zone.expectCallback();
    _timer = _createPeriodicTimer(duration, this._run);
  }

  void _run(Timer timer) {
    assert(identical(_timer, timer));
    _zone.executePeriodicCallbackGuarded(() { _callback(this); });
  }

  void cancel() {
    if (_timer.isActive) _zone.cancelCallbackExpectation();
    _timer.cancel();
  }

  bool get isActive => _timer.isActive;
}

/**
 * Runs [body] in its own zone.
 *
 * If [onError] is non-null the zone is considered an error zone. All uncaught
 * errors, synchronous or asynchronous, in the zone are caught and handled
 * by the callback.
 *
 * The [onDone] handler (if non-null) is invoked when the zone has no more
 * outstanding callbacks. *Deprecated*: this method is less useful than it
 * seems, because it assumes that every registered callback is always invoked.
 * There are, however, many *valid* reasons not to complete futures or to abort
 * a future-chain. In general it is a bad idea to rely on `onDone`.
 *
 * The [onRunAsync] handler (if non-null) is invoked when the [body] executes
 * [runAsync].  The handler is invoked in the outer zone and can therefore
 * execute [runAsync] without recursing. The given callback must be
 * executed eventually. Otherwise the nested zone will not complete. It must be
 * executed only once.
 *
 * Examples:
 *
 *     runZonedExperimental(() {
 *       new Future(() { throw "asynchronous error"; });
 *     }, onError: print);  // Will print "asynchronous error".
 *
 * The following example prints "1", "2", "3", "4" in this order.
 *
 *     runZonedExperimental(() {
 *       print(1);
 *       new Future.value(3).then(print);
 *     }, onDone: () { print(4); });
 *     print(2);
 *
 * Errors may never cross error-zone boundaries. This is intuitive for leaving
 * a zone, but it also applies for errors that would enter an error-zone.
 * Errors that try to cross error-zone boundaries are considered uncaught.
 *
 *     var future = new Future.value(499);
 *     runZonedExperimental(() {
 *       future = future.then((_) { throw "error in first error-zone"; });
 *       runZonedExperimental(() {
 *         future = future.catchError((e) { print("Never reached!"); });
 *       }, onError: (e) { print("unused error handler"); });
 *     }, onError: (e) { print("catches error of first error-zone."); });
 *
 * The following example prints the stack trace whenever a callback is
 * registered using [runAsync] (which is also used by [Completer]s and
 * [StreamController]s.
 *
 *     printStackTrace() { try { throw 0; } catch(e, s) { print(s); } }
 *     runZonedExperimental(body, onRunAsync: (callback) {
 *       printStackTrace();
 *       runAsync(callback);
 *     });
 */
runZonedExperimental(body(),
                     { void onRunAsync(void callback()),
                       void onError(error),
                       void onDone() }) {
  if (onRunAsync != null) {
    _RunAsyncZone zone = new _RunAsyncZone(_Zone._current, onRunAsync);
    return zone._runUnguarded(() {
      return runZonedExperimental(body, onError: onError, onDone: onDone);
    });
  }

  // TODO(floitsch): we probably still want to install a new Zone.
  if (onError == null && onDone == null) return body();
  if (onError == null) {
    _WaitForCompletionZone zone =
        new _WaitForCompletionZone(_Zone._current, onDone);
    return zone.runWaitForCompletion(body);
  }
  if (onDone == null) onDone = _nullDoneHandler;
  _CatchErrorsZone zone = new _CatchErrorsZone(_Zone._current, onError, onDone);
  return zone.runWaitForCompletion(body);
}
