// Copyright (c) 2018, 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 'compiler.dart';
import 'operating_system.dart';
import 'runtime.dart';

/// The platform on which a test suite is loaded.
final class SuitePlatform {
  /// The runtime that hosts the suite.
  final Runtime runtime;

  /// The operating system on which the suite is running.
  ///
  /// This will always be [OperatingSystem.none] if `runtime.isBrowser` is
  /// true.
  final OperatingSystem os;

  /// Whether we're running on Google-internal infrastructure.
  final bool inGoogle;

  /// The compiler that should used for this platform.
  final Compiler compiler;

  /// Creates a new platform with the given [runtime] and [os], which defaults
  /// to [OperatingSystem.none].
  ///
  /// Throws an [ArgumentError] if [runtime] is a browser and [os] is not
  /// `null` or [OperatingSystem.none].
  ///
  /// If [compiler] is `null`, then the default compiler for [runtime] will be
  /// used.
  SuitePlatform(this.runtime,
      {
      // TODO(https://github.com/dart-lang/test/issues/1935): make required
      Compiler? compiler,
      this.os = OperatingSystem.none,
      this.inGoogle = false})
      : compiler = compiler ?? runtime.defaultCompiler {
    if (runtime.isBrowser && os != OperatingSystem.none) {
      throw ArgumentError('No OS should be passed for runtime "$runtime".');
    }
    if (!runtime.supportedCompilers.contains(this.compiler)) {
      throw ArgumentError(
          'The platform $runtime does not support the compiler ${this.compiler}');
    }
  }

  /// Converts a JSON-safe representation generated by [serialize] back into a
  /// [SuitePlatform].
  factory SuitePlatform.deserialize(Object serialized) {
    var map = serialized as Map;
    return SuitePlatform(Runtime.deserialize(map['runtime'] as Object),
        compiler: map.containsKey('compiler')
            ? Compiler.deserialize(map['compiler'] as Object)
            : null,
        os: OperatingSystem.find(map['os'] as String),
        inGoogle: map['inGoogle'] as bool);
  }

  /// Converts [this] into a JSON-safe object that can be converted back to a
  /// [SuitePlatform] using [SuitePlatform.deserialize].
  Object serialize() => {
        'runtime': runtime.serialize(),
        'compiler': compiler.serialize(),
        'os': os.identifier,
        'inGoogle': inGoogle
      };
}
