// 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 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(function, 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(
      function, 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;
}

class _SpawnedProcessResourceInfo extends _IOResourceInfo {
  static const String _type = 'SpawnedProcess';
  final 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));
  }
}
