// Copyright (c) 2015, 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.io;

abstract class _IOResourceInfo {
  final String type;
  final int id;
  String get name;
  static int _count = 0;

  static final Stopwatch _sw = Stopwatch()..start();
  static final _startTime = DateTime.now().millisecondsSinceEpoch;

  static int get timestamp => _startTime + _sw.elapsedMicroseconds ~/ 1000;

  _IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();

  /// Get the full set of values for a specific implementation. This is normally
  /// looked up based on an id from a referenceValueMap.
  Map<String, dynamic> get fullValueMap;

  /// The reference map, used to return a list of values, e.g., getting
  /// all open sockets. The structure of this is shared among all subclasses.
  Map<String, dynamic> get referenceValueMap => {
    // The type for a reference object is prefixed with @ in observatory.
    'type': '@$type',
    'id': id,
    'name': name,
  };

  static int getNextID() => _count++;
}

abstract class _ReadWriteResourceInfo extends _IOResourceInfo {
  int readBytes;
  int writeBytes;
  int readCount;
  int writeCount;
  int lastReadTime;
  int lastWriteTime;

  // Not all call sites use this. In some cases, e.g., a socket, a read does
  // not always mean that we actually read some bytes (we may do a read to see
  // if there are some bytes available).
  void addRead(int bytes) {
    readBytes += bytes;
    readCount++;
    lastReadTime = _IOResourceInfo.timestamp;
  }

  // In cases where we read but did not necessarily get any bytes, use this to
  // update the readCount and timestamp. Manually update totalRead if any bytes
  // where actually read.
  void didRead() {
    addRead(0);
  }

  void addWrite(int bytes) {
    writeBytes += bytes;
    writeCount++;
    lastWriteTime = _IOResourceInfo.timestamp;
  }

  _ReadWriteResourceInfo(String type)
    : readBytes = 0,
      writeBytes = 0,
      readCount = 0,
      writeCount = 0,
      lastReadTime = 0,
      lastWriteTime = 0,
      super(type);

  Map<String, dynamic> get fullValueMap => {
    'type': type,
    'id': id,
    'name': name,
    'readBytes': readBytes,
    'writeBytes': writeBytes,
    'readCount': readCount,
    'writeCount': writeCount,
    'lastReadTime': lastReadTime,
    'lastWriteTime': lastWriteTime,
  };
}

class _FileResourceInfo extends _ReadWriteResourceInfo {
  static const String _type = 'OpenFile';

  final RandomAccessFile file;

  static Map<int, _FileResourceInfo> openFiles = {};

  _FileResourceInfo(this.file) : super(_type) {
    fileOpened(this);
  }

  static fileOpened(_FileResourceInfo info) {
    assert(!openFiles.containsKey(info.id));
    openFiles[info.id] = info;
  }

  static fileClosed(_FileResourceInfo info) {
    assert(openFiles.containsKey(info.id));
    openFiles.remove(info.id);
  }

  static Iterable<Map<String, dynamic>> getOpenFilesList() {
    return List.from(openFiles.values.map((e) => e.referenceValueMap));
  }

  static Future<ServiceExtensionResponse> getOpenFiles(
    String function,
    Map<String, String> params,
  ) {
    assert(function == 'ext.dart.io.getOpenFiles');
    final data = {'type': 'OpenFileList', 'files': getOpenFilesList()};
    final jsonValue = json.encode(data);
    return Future.value(ServiceExtensionResponse.result(jsonValue));
  }

  Map<String, dynamic> get fileInfoMap => fullValueMap;

  static Future<ServiceExtensionResponse> getOpenFileInfoMapByID(
    String function,
    Map<String, String> params,
  ) {
    final id = int.parse(params['id']!);
    final result = openFiles.containsKey(id) ? openFiles[id]!.fileInfoMap : {};
    final jsonValue = json.encode(result);
    return Future.value(ServiceExtensionResponse.result(jsonValue));
  }

  String get name => file.path;
}

abstract class _Process implements Process {
  abstract String _path;
  abstract List<String> _arguments;
  abstract String? _workingDirectory;
}

class _SpawnedProcessResourceInfo extends _IOResourceInfo {
  static const String _type = 'SpawnedProcess';
  final _Process process;
  final int startedAt;

  static Map<int, _SpawnedProcessResourceInfo> startedProcesses =
      Map<int, _SpawnedProcessResourceInfo>();

  _SpawnedProcessResourceInfo(this.process)
    : startedAt = _IOResourceInfo.timestamp,
      super(_type) {
    processStarted(this);
  }

  String get name => process._path;

  void stopped() => processStopped(this);

  Map<String, dynamic> get fullValueMap => {
    'type': type,
    'id': id,
    'name': name,
    'pid': process.pid,
    'startedAt': startedAt,
    'arguments': process._arguments,
    'workingDirectory': process._workingDirectory == null
        ? '.'
        : process._workingDirectory,
  };

  static processStarted(_SpawnedProcessResourceInfo info) {
    assert(!startedProcesses.containsKey(info.id));
    startedProcesses[info.id] = info;
  }

  static processStopped(_SpawnedProcessResourceInfo info) {
    assert(startedProcesses.containsKey(info.id));
    startedProcesses.remove(info.id);
  }

  static Iterable<Map<String, dynamic>> getStartedProcessesList() =>
      List.from(startedProcesses.values.map((e) => e.referenceValueMap));

  static Future<ServiceExtensionResponse> getStartedProcesses(
    String function,
    Map<String, String> params,
  ) {
    assert(function == 'ext.dart.io.getSpawnedProcesses');
    final data = {
      'type': 'SpawnedProcessList',
      'processes': getStartedProcessesList(),
    };
    final jsonValue = json.encode(data);
    return Future.value(ServiceExtensionResponse.result(jsonValue));
  }

  static Future<ServiceExtensionResponse> getProcessInfoMapById(
    String function,
    Map<String, String> params,
  ) {
    final id = int.parse(params['id']!);
    final result = startedProcesses.containsKey(id)
        ? startedProcesses[id]!.fullValueMap
        : {};
    final jsonValue = json.encode(result);
    return Future.value(ServiceExtensionResponse.result(jsonValue));
  }
}
