// 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.

import 'dart:convert' show utf8;
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';

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

const int _maxCombinedTags = 5;
const int _maxTagLength = 63;
const int _socketBufferLength = 2032;
const int _unexpectedLoggingLevel = 100;

const int _zxClockMonotonic = 0;
final Map<Level, int> _enumToFuchsiaLevelMap = <Level, int>{
  Level.FINEST: -4,
  Level.FINER: -3,
  Level.FINE: -2,
  Level.CONFIG: -1,
  Level.INFO: 0,
  Level.WARNING: 1,
  Level.SEVERE: 2,
  Level.SHOUT: 3,
};

/// A wrapper around [LogRecord] which appends additional data. This
/// is what is sent to the log writer when a record is received.
class LogMessage {
  /// The initial log record
  final LogRecord record;

  /// Any additional tags to append to the record.
  final List<String> tags;

  /// The id of the process which this log message is associated with
  final int processId;

  /// The id of the thread which this log message is associated with
  final int threadId;

  /// The time that this message was created
  final int systemTime = Platform.isFuchsia
      ? System.clockGet(_zxClockMonotonic)
      : DateTime.now().microsecondsSinceEpoch * 1000;

  /// The default constructor
  LogMessage({
    @required this.record,
    @required this.processId,
    @required this.threadId,
    this.tags = const [],
  })  : assert(record != null),
        assert(processId != null),
        assert(threadId != null);

  /// Converts this to a ByteData which can be used to send the message to the
  /// log socket.
  ByteData toBytes() {
    ByteData bytes = ByteData(_socketBufferLength)
      ..setUint64(0, processId, Endian.little)
      ..setUint64(8, threadId, Endian.little)
      ..setUint64(16, systemTime, Endian.little)
      ..setInt32(24, _convertLogLevel(record.level), Endian.little)
      ..setUint32(28, 0, Endian.little); // TODO(120860552) droppedLogs
    int byteOffset = 32;

    // Write global tags
    int totalTagCount = 0;
    for (final tag in tags) {
      if (tag != null && totalTagCount < _maxCombinedTags) {
        byteOffset = _setTag(bytes, byteOffset, tag);
        totalTagCount++;
      }
    }

    // We need to skip the local tags section since we do not support them
    bytes.setUint8(byteOffset++, 0);

    // Write message
    byteOffset = _setString(bytes, byteOffset, record.message,
        _socketBufferLength - byteOffset - 1);
    if (record.error != null) {
      byteOffset = _setString(
          bytes, byteOffset, ': ', _socketBufferLength - byteOffset - 1);
      byteOffset = _setString(bytes, byteOffset, record.error.toString(),
          _socketBufferLength - byteOffset - 1);
    }
    if (record.stackTrace != null) {
      byteOffset = _setString(
          bytes, byteOffset, '\n', _socketBufferLength - byteOffset - 1);
      byteOffset = _setString(bytes, byteOffset, record.stackTrace.toString(),
          _socketBufferLength - byteOffset - 1);
    }
    bytes.setUint8(byteOffset++, 0);
    return bytes.buffer.asByteData(0, byteOffset);
  }

  int _convertLogLevel(Level logLevel) =>
      _enumToFuchsiaLevelMap[logLevel] ?? _unexpectedLoggingLevel;

  /// Write a string to ByteData with a leading length byte. Return the
  /// byteOffstet to use for the next value. Wrie a non-terminated string to
  /// ByteData. Return the byteOffset to use for the terminating byte or the
  /// next value.
  int _setString(
      ByteData bytes, int firstByteOffset, String value, int maxLen) {
    if (value == null || value.isEmpty) {
      return firstByteOffset;
    }
    List<int> charBytes = utf8.encode(value);
    int len = min(charBytes.length, maxLen);
    int byteOffset = firstByteOffset;
    for (int i = 0; i < len; i++) {
      bytes.setUint8(byteOffset++, charBytes[i]);
    }
    // If the string was truncated (and there is space), add an elipsis character.
    if (len < charBytes.length && len >= 3) {
      const int period = 46; // UTF8 value for '.'
      for (int i = 1; i <= 3; i++) {
        bytes.setUint8(byteOffset - i, period);
      }
    }
    return byteOffset;
  }

  int _setTag(ByteData bytes, int byteOffset, String tag) {
    if (tag == null || tag == 'null') {
      return byteOffset;
    }
    int nextOffset = _setString(bytes, byteOffset + 1, tag, _maxTagLength);
    bytes.setUint8(byteOffset, nextOffset - byteOffset - 1);
    return nextOffset;
  }
}
