// Copyright (c) 2017, 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.

import 'dart:async';

import 'codecs.dart';
import 'common.dart';
import 'recording.dart';
import 'result_reference.dart';

/// Base class for recordable file system invocation events.
///
/// Instances of this class will be aggregated in a [Recording]
abstract class InvocationEvent<T> {
  /// The object on which the invocation occurred. Will always be non-null.
  Object get object;

  /// The return value of the invocation if the invocation completed
  /// successfully.
  ///
  /// This may be null (and will always be `null` for setters).
  ///
  /// If the invocation completed with an error, this value will be `null`,
  /// and [error] will be set.
  T get result;

  /// The error that was thrown by the invocation if the invocation completed
  /// with an error.
  ///
  /// If the invocation completed successfully, this value will be `null`, and
  /// [result] will hold the result of the invocation (which may also be
  /// `null`).
  ///
  /// This field being non-null can be used as an indication that the invocation
  /// completed with an error.
  dynamic get error;

  /// The stopwatch value (in milliseconds) when the invocation occurred.
  ///
  /// This value is recorded when the invocation first occurs, not when the
  /// delegate returns.
  int get timestamp;
}

/// A recordable invocation of a property getter on a file system object.
abstract class PropertyGetEvent<T> extends InvocationEvent<T> {
  /// The property that was retrieved.
  Symbol get property;
}

/// A recordable invocation of a property setter on a file system object.
abstract class PropertySetEvent<T> extends InvocationEvent<Null> {
  /// The property that was set.
  ///
  /// All setter property symbols will have a trailing equals sign. For example,
  /// if the `foo` property was set, this value will be a symbol of `foo=`.
  Symbol get property;

  /// The value to which [property] was set. This is distinct from [result],
  /// which is always `null` for setters.
  T get value;
}

/// A recordable invocation of a method on a file system object.
abstract class MethodEvent<T> extends InvocationEvent<T> {
  /// The method that was invoked.
  Symbol get method;

  /// The positional arguments that were passed to the method.
  List<dynamic> get positionalArguments;

  /// The named arguments that were passed to the method.
  Map<Symbol, dynamic> get namedArguments;
}

/// An [InvocationEvent] that's in the process of being recorded.
abstract class LiveInvocationEvent<T> implements InvocationEvent<T> {
  /// Creates a new [LiveInvocationEvent].
  LiveInvocationEvent(this.object, this._result, this.error, this.timestamp);

  final dynamic _result;

  @override
  final Object object;

  @override
  T get result {
    dynamic result = _result;
    while (result is ResultReference) {
      ResultReference<dynamic> reference = result as ResultReference<dynamic>;
      result = reference.recordedValue;
    }
    return result as T;
  }

  @override
  final dynamic error;

  @override
  final int timestamp;

  /// A [Future] that completes once [result] is ready for serialization.
  ///
  /// If [result] is a [Future], this future completes when [result] completes.
  /// If [result] is a [Stream], this future completes when the stream sends a
  /// "done" event. If [result] is neither a future nor a stream, this future
  /// completes immediately.
  ///
  /// It is legal for [serialize] to be called before this future completes,
  /// but doing so will cause incomplete results to be serialized. Results that
  /// are unfinished futures will be serialized as `null`, and results that are
  /// unfinished streams will be serialized as the data that has been received
  /// thus far.
  Future<void> get done async {
    dynamic result = _result;
    while (result is ResultReference) {
      ResultReference<dynamic> reference = result as ResultReference<dynamic>;
      await reference.complete;
      result = reference.recordedValue;
    }
  }

  /// Returns this event as a JSON-serializable object.
  Map<String, dynamic> serialize() {
    return <String, dynamic>{
      kManifestObjectKey: encode(object),
      kManifestResultKey: encode(_result),
      kManifestErrorKey: encode(error),
      kManifestTimestampKey: timestamp,
    };
  }

  @override
  String toString() => serialize().toString();
}

/// A [PropertyGetEvent] that's in the process of being recorded.
class LivePropertyGetEvent<T> extends LiveInvocationEvent<T>
    implements PropertyGetEvent<T> {
  /// Creates a new [LivePropertyGetEvent].
  LivePropertyGetEvent(
      Object object, this.property, T result, dynamic error, int timestamp)
      : super(object, result, error, timestamp);

  @override
  final Symbol property;

  @override
  Map<String, dynamic> serialize() {
    return <String, dynamic>{
      kManifestTypeKey: kGetType,
      kManifestPropertyKey: getSymbolName(property),
    }..addAll(super.serialize());
  }
}

/// A [PropertySetEvent] that's in the process of being recorded.
class LivePropertySetEvent<T> extends LiveInvocationEvent<Null>
    implements PropertySetEvent<T> {
  /// Creates a new [LivePropertySetEvent].
  LivePropertySetEvent(
      Object object, this.property, this.value, dynamic error, int timestamp)
      : super(object, null, error, timestamp);

  @override
  final Symbol property;

  @override
  final T value;

  @override
  Map<String, dynamic> serialize() {
    return <String, dynamic>{
      kManifestTypeKey: kSetType,
      kManifestPropertyKey: getSymbolName(property),
      kManifestValueKey: encode(value),
    }..addAll(super.serialize());
  }
}

/// A [MethodEvent] that's in the process of being recorded.
class LiveMethodEvent<T> extends LiveInvocationEvent<T>
    implements MethodEvent<T> {
  /// Creates a new [LiveMethodEvent].
  LiveMethodEvent(
    Object object,
    this.method,
    List<dynamic> positionalArguments,
    Map<Symbol, dynamic> namedArguments,
    T result,
    dynamic error,
    int timestamp,
  )   : positionalArguments = List<dynamic>.unmodifiable(positionalArguments),
        namedArguments = Map<Symbol, dynamic>.unmodifiable(namedArguments),
        super(object, result, error, timestamp);

  @override
  final Symbol method;

  @override
  final List<dynamic> positionalArguments;

  @override
  final Map<Symbol, dynamic> namedArguments;

  @override
  Map<String, dynamic> serialize() {
    return <String, dynamic>{
      kManifestTypeKey: kInvokeType,
      kManifestMethodKey: getSymbolName(method),
      kManifestPositionalArgumentsKey: encode(positionalArguments),
      kManifestNamedArgumentsKey: encode(namedArguments),
    }..addAll(super.serialize());
  }
}
