// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The standard dart logger cannot be extended as the only way to create one is
// via factory methods. Those factory methods cannot return an instance of this
// class, which they know nothing about. To remedy that, this code provides a
// parallel implementation of Logger with extensions required to accommodate
// the extended functionality logger in fuchsia/zircon.
//
// This removes support for the hierarchical logger that is enabled in the dart
// version.

import 'dart:async';
import 'dart:io';

import 'package:logging/logging.dart';
import 'package:zircon/zircon.dart';

import 'fuchsia_log_record.dart';

/// Handler callback to process log entries as they are added to a [Logger].
typedef LoggerHandler = void Function(FuchsiaLogRecord logRecord);

const int _zxClockMonotonic = 0;

/// Use a [FuchsiaLogger] to log debug messages. This class adds fuchsia
/// specific extenstions for logging: time specified in zircon time and local
/// tags in log messages.
class FuchsiaLogger {
  /// Constructor
  FuchsiaLogger(this.level) {
    Logger.root.clearListeners();
    Logger.root.onRecord.listen((LogRecord rec) {
      log(rec.level, rec.message, /* local tag */ null, rec.error,
          rec.stackTrace);
    });
  }

  /// Logging [Level] used for entries generated on this logger.
  Level level;

  /// Controller used to notify when log entries are added to this logger.
  StreamController<FuchsiaLogRecord> _controller;

  /// Returns a stream of messages added to this [FuchsiaLogger].
  ///
  /// You can listen for messages using the standard stream APIs, for instance:
  ///
  /// ```dart
  /// logger.onRecord.listen((record) { ... });
  /// ```
  Stream<FuchsiaLogRecord> get onRecord => _getStream();

  /// Remove the Listener attached to this [FuchsiaLogger].
  void clearListener() {
    if (_controller != null) {
      _controller.close();
      _controller = null;
    }
  }

  /// Log message at level [Level.FINEST].
  // ignore: type_annotate_public_apis, always_specify_types
  void finest(message, [Object error, StackTrace stackTrace]) =>
      log(Level.FINEST, message, null, error, stackTrace);

  /// Log message at level [Level.FINER].
  // ignore: type_annotate_public_apis, always_specify_types
  void finer(message, [Object error, StackTrace stackTrace]) =>
      log(Level.FINER, message, null, error, stackTrace);

  /// Log message at level [Level.FINE].
  // ignore: type_annotate_public_apis, always_specify_types
  void fine(message, [Object error, StackTrace stackTrace]) =>
      log(Level.FINE, message, null, error, stackTrace);

  /// Log message at level [Level.CONFIG].
  // ignore: type_annotate_public_apis, always_specify_types
  void config(message, [Object error, StackTrace stackTrace]) =>
      log(Level.CONFIG, message, null, error, stackTrace);

  /// Log message at level [Level.INFO].
  // ignore: type_annotate_public_apis, always_specify_types
  void info(message, [Object error, StackTrace stackTrace]) =>
      log(Level.INFO, message, null, error, stackTrace);

  /// Log message at level [Level.WARNING].
  // ignore: type_annotate_public_apis, always_specify_types
  void warning(message, [Object error, StackTrace stackTrace]) =>
      log(Level.WARNING, message, null, error, stackTrace);

  /// Log message at level [Level.SEVERE].
  // ignore: type_annotate_public_apis, always_specify_types
  void severe(message, [Object error, StackTrace stackTrace]) =>
      log(Level.SEVERE, message, null, error, stackTrace);

  /// Log message at level [Level.SHOUT].
  // ignore: type_annotate_public_apis, always_specify_types
  void shout(message, [Object error, StackTrace stackTrace]) =>
      log(Level.SHOUT, message, null, error, stackTrace);

  /// Log message at level [Level.FINEST].
  // ignore: type_annotate_public_apis, always_specify_types
  void finestT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.FINEST, message, tag, error, stackTrace);

  /// Log message at level [Level.FINER].
  // ignore: type_annotate_public_apis, always_specify_types
  void finerT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.FINER, message, tag, error, stackTrace);

  /// Log message at level [Level.FINE].
  // ignore: type_annotate_public_apis, always_specify_types
  void fineT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.FINE, message, tag, error, stackTrace);

  /// Log message at level [Level.CONFIG].
  // ignore: type_annotate_public_apis, always_specify_types
  void configT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.CONFIG, message, tag, error, stackTrace);

  /// Log message at level [Level.INFO].
  // ignore: type_annotate_public_apis, always_specify_types
  void infoT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.INFO, message, tag, error, stackTrace);

  /// Log message at level [Level.WARNING].
  // ignore: type_annotate_public_apis, always_specify_types
  void warningT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.WARNING, message, tag, error, stackTrace);

  /// Log message at level [Level.SEVERE].
  // ignore: type_annotate_public_apis, always_specify_types
  void severeT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.SEVERE, message, tag, error, stackTrace);

  /// Log message at level [Level.SHOUT].
  // ignore: type_annotate_public_apis, always_specify_types
  void shoutT(message, {String tag, Object error, StackTrace stackTrace}) =>
      log(Level.SHOUT, message, tag, error, stackTrace);

  /// Whether a message for [value]'s level is loggable in this logger.
  bool isLoggable(Level value) => value >= level;

  /// Adds a log record for a [message] at a particular [logLevel] if
  /// `isLoggable(logLevel)` is true.
  ///
  /// Use this method to create log entries for user-defined levels. To record a
  /// message at a predefined level (e.g. [Level.INFO], [Level.WARNING], etc)
  /// you can use their specialized methods instead (e.g. [info], [warning],
  /// etc).
  ///
  /// If [message] is a [Function], it will be lazy evaluated. Additionally, if
  /// [message] or its evaluated value is not a [String], then 'toString()' will
  /// be called on the object and the result will be logged. The log record will
  /// contain a field holding the original object.
  ///
  /// The log record will also contain a field for the zone in which this call
  /// was made. This can be advantageous if a log listener wants to handler
  /// records of different zones differently (e.g. group log records by HTTP
  /// request if each HTTP request handler runs in it's own zone).
  void log(Level logLevel, Object message, String localTag, Object error,
      StackTrace stackTrace) {
    if (!isLoggable(logLevel)) {
      return;
    }
    int systemTime = Platform.isFuchsia
        ? System.clockGet(_zxClockMonotonic)
        : DateTime.now().microsecondsSinceEpoch * 1000;
    String logMsg;
    if (message is Function) {
      logMsg = message();
    } else if (message is String) {
      logMsg = message;
    } else {
      Object object = message;
      logMsg = object.toString();
    }
    _publish(FuchsiaLogRecord(logLevel, logMsg, systemTime,
        localTag: localTag, error: error, stackTrace: stackTrace));
  }

  Stream<FuchsiaLogRecord> _getStream() {
    _controller ??=
        StreamController<FuchsiaLogRecord>.broadcast(sync: true);
    return _controller.stream;
  }

  void _publish(FuchsiaLogRecord record) {
    if (_controller != null) {
      _controller.add(record);
    }
  }
}
