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

library;

import '../elements/entities.dart';
import '../util/util.dart' show Setlet;
import 'use.dart';

/// Describes how an element (e.g. a method) impacts the closed-world
/// semantics of a program.
///
/// A [WorldImpact] contains information about how a program element affects our
/// understanding of what's live in a program. For example, it can indicate
/// that a method uses a certain feature, or allocates a specific type.
///
/// The impact object can be computed locally by inspecting just the resolution
/// information of that element alone. The compiler uses [Universe] and
/// [World] to combine the information discovered in the impact objects of
/// all elements reachable in an application.
class WorldImpact {
  const WorldImpact();

  /// [member] may be `null` when the impact is for something that is not a
  /// member, e.g. a constant, or external or native dependencies.
  MemberEntity? get member => null;

  Iterable<DynamicUse> get dynamicUses => const [];

  Iterable<StaticUse> get staticUses => const [];

  // TODO(johnniwinther): Replace this by called constructors with type
  // arguments.
  // TODO(johnniwinther): Collect all checked types for checked mode separately
  // to support serialization.

  Iterable<TypeUse> get typeUses => const [];

  Iterable<ConstantUse> get constantUses => const [];

  Iterable<ConditionalUse> get conditionalUses => const [];

  void _forEach<U>(Iterable<U> uses, void Function(MemberEntity?, U) visitUse) {
    for (final use in uses) {
      visitUse(member, use);
    }
  }

  void forEachDynamicUse(void Function(MemberEntity?, DynamicUse) visitUse) =>
      _forEach(dynamicUses, visitUse);
  void forEachStaticUse(void Function(MemberEntity?, StaticUse) visitUse) =>
      _forEach(staticUses, visitUse);
  void forEachTypeUse(void Function(MemberEntity?, TypeUse) visitUse) =>
      _forEach(typeUses, visitUse);
  void forEachConstantUse(void Function(MemberEntity?, ConstantUse) visitUse) =>
      _forEach(constantUses, visitUse);
  void forEachConditionalUse(
    void Function(MemberEntity?, ConditionalUse) visitUse,
  ) => _forEach(conditionalUses, visitUse);

  bool get isEmpty => true;

  @override
  String toString() => dump(this);

  static String dump(WorldImpact worldImpact) {
    StringBuffer sb = StringBuffer();
    printOn(sb, worldImpact);
    return sb.toString();
  }

  static void printOn(StringBuffer sb, WorldImpact worldImpact) {
    sb.write('member: ${worldImpact.member}');

    void add(String title, Iterable<Object?> iterable) {
      if (iterable.isNotEmpty) {
        sb.write('\n $title:');
        for (var e in iterable) {
          sb.write('\n  $e');
        }
      }
    }

    add('dynamic uses', worldImpact.dynamicUses);
    add('static uses', worldImpact.staticUses);
    add('type uses', worldImpact.typeUses);
    add('constant uses', worldImpact.constantUses);
  }
}

abstract class WorldImpactBuilder extends WorldImpact {
  void registerDynamicUse(DynamicUse dynamicUse);
  void registerTypeUse(TypeUse typeUse);
  void registerStaticUse(StaticUse staticUse);
  void registerConstantUse(ConstantUse constantUse);
  void registerConditionalUse(ConditionalUse conditionalUse);
}

class WorldImpactBuilderImpl extends WorldImpactBuilder {
  /// The [MemberEntity] associated with this set of impacts. Maybe null.
  @override
  final MemberEntity? member;

  // TODO(johnniwinther): Do we benefit from lazy initialization of the
  // [Setlet]s?
  Set<DynamicUse>? _dynamicUses;
  Set<StaticUse>? _staticUses;
  Set<TypeUse>? _typeUses;
  Set<ConstantUse>? _constantUses;
  List<ConditionalUse>? _conditionalUses;

  WorldImpactBuilderImpl([this.member]);

  WorldImpactBuilderImpl.internal(
    this._dynamicUses,
    this._staticUses,
    this._typeUses,
    this._constantUses, {
    this.member,
  });

  @override
  bool get isEmpty =>
      _dynamicUses == null &&
      _staticUses == null &&
      _typeUses == null &&
      _constantUses == null &&
      _conditionalUses == null;

  /// Copy uses in [impact] to this impact builder.
  void addImpact(WorldImpact impact) {
    if (impact.isEmpty) return;
    impact.dynamicUses.forEach(registerDynamicUse);
    impact.staticUses.forEach(registerStaticUse);
    impact.typeUses.forEach(registerTypeUse);
    impact.constantUses.forEach(registerConstantUse);
    impact.conditionalUses.forEach(registerConditionalUse);
  }

  @override
  void registerDynamicUse(DynamicUse dynamicUse) {
    (_dynamicUses ??= Setlet()).add(dynamicUse);
  }

  @override
  Iterable<DynamicUse> get dynamicUses {
    return _dynamicUses ?? const [];
  }

  @override
  void registerTypeUse(TypeUse typeUse) {
    (_typeUses ??= Setlet()).add(typeUse);
  }

  @override
  Iterable<TypeUse> get typeUses {
    return _typeUses ?? const [];
  }

  @override
  void registerStaticUse(StaticUse staticUse) {
    (_staticUses ??= Setlet()).add(staticUse);
  }

  @override
  Iterable<StaticUse> get staticUses {
    return _staticUses ?? const [];
  }

  @override
  void registerConstantUse(ConstantUse constantUse) {
    (_constantUses ??= Setlet()).add(constantUse);
  }

  @override
  Iterable<ConstantUse> get constantUses {
    return _constantUses ?? const [];
  }

  @override
  void registerConditionalUse(ConditionalUse conditionalUse) {
    (_conditionalUses ??= []).add(conditionalUse);
  }

  @override
  Iterable<ConditionalUse> get conditionalUses {
    return _conditionalUses ?? const [];
  }
}

/// Mutable implementation of [WorldImpact] used to transform
/// [ResolutionImpact] or [CodegenImpact] to [WorldImpact].
class TransformedWorldImpact extends WorldImpactBuilder {
  final WorldImpact worldImpact;

  Setlet<StaticUse>? _staticUses;
  Setlet<TypeUse>? _typeUses;
  Setlet<DynamicUse>? _dynamicUses;
  Setlet<ConstantUse>? _constantUses;

  TransformedWorldImpact(this.worldImpact);

  @override
  MemberEntity? get member => worldImpact.member;

  @override
  bool get isEmpty {
    return worldImpact.isEmpty &&
        _staticUses == null &&
        _typeUses == null &&
        _dynamicUses == null &&
        _constantUses == null;
  }

  @override
  Iterable<DynamicUse> get dynamicUses {
    return _dynamicUses ?? worldImpact.dynamicUses;
  }

  @override
  void registerDynamicUse(DynamicUse dynamicUse) {
    _dynamicUses ??= Setlet.of(worldImpact.dynamicUses);
    _dynamicUses!.add(dynamicUse);
  }

  @override
  void registerTypeUse(TypeUse typeUse) {
    _typeUses ??= Setlet.of(worldImpact.typeUses);
    _typeUses!.add(typeUse);
  }

  @override
  Iterable<TypeUse> get typeUses {
    return _typeUses ?? worldImpact.typeUses;
  }

  @override
  void registerStaticUse(StaticUse staticUse) {
    _staticUses ??= Setlet.of(worldImpact.staticUses);
    _staticUses!.add(staticUse);
  }

  @override
  Iterable<StaticUse> get staticUses {
    return _staticUses ?? worldImpact.staticUses;
  }

  @override
  Iterable<ConstantUse> get constantUses {
    return _constantUses ?? worldImpact.constantUses;
  }

  @override
  void registerConstantUse(ConstantUse constantUse) {
    _constantUses ??= Setlet.of(worldImpact.constantUses);
    _constantUses!.add(constantUse);
  }

  @override
  void registerConditionalUse(ConditionalUse conditionalUse) {}

  @override
  Iterable<ConditionalUse> get conditionalUses => const [];

  @override
  String toString() {
    StringBuffer sb = StringBuffer();
    sb.write('TransformedWorldImpact($worldImpact)');
    WorldImpact.printOn(sb, this);
    return sb.toString();
  }
}
