// Copyright (c) 2016, 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 '../common.dart';
import '../elements/jumps.dart';
import '../io/source_information.dart';

import 'builder.dart';
import 'locals_handler.dart';
import 'nodes.dart';

/// A single break/continue instruction.
class _JumpHandlerEntry {
  final HJump jumpInstruction;
  final LocalsHandler locals;
  bool isBreak() => jumpInstruction is HBreak;
  bool isContinue() => jumpInstruction is HContinue;
  _JumpHandlerEntry(this.jumpInstruction, this.locals);
}

abstract class JumpHandler {
  factory JumpHandler(KernelSsaGraphBuilder builder, JumpTarget target) {
    return TargetJumpHandler(builder, target);
  }

  void generateBreak(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]);
  void generateContinue(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]);
  void forEachBreak(
    void Function(HBreak instruction, LocalsHandler locals) action,
  );
  void forEachContinue(
    void Function(HContinue instruction, LocalsHandler locals) action,
  );
  bool hasAnyContinue();
  bool hasAnyBreak();
  void close();
  JumpTarget? get target;
  List<LabelDefinition> get labels;
}

/// Jump handler used to avoid null checks when a target isn't used as the
/// target of a break, and therefore doesn't need a break handler associated
/// with it.
class NullJumpHandler implements JumpHandler {
  final DiagnosticReporter reporter;

  NullJumpHandler(this.reporter);

  @override
  void generateBreak(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]) {
    reporter.internalError(
      currentElementSpannable,
      'NullJumpHandler.generateBreak should not be called.',
    );
  }

  @override
  void generateContinue(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]) {
    reporter.internalError(
      currentElementSpannable,
      'NullJumpHandler.generateContinue should not be called.',
    );
  }

  @override
  void forEachBreak(Function ignored) {}
  @override
  void forEachContinue(Function ignored) {}
  @override
  void close() {}
  @override
  bool hasAnyContinue() => false;
  @override
  bool hasAnyBreak() => false;

  @override
  List<LabelDefinition> get labels => const [];
  @override
  JumpTarget? get target => null;
}

/// Jump handler that records breaks until a target block is available.
///
/// Breaks are always forward jumps. Continues in loops are implemented as
/// breaks of the body. Continues in switches is currently not handled.
class TargetJumpHandler implements JumpHandler {
  final KernelSsaGraphBuilder builder;
  @override
  final JumpTarget target;
  final List<_JumpHandlerEntry> _jumps = [];

  TargetJumpHandler(this.builder, this.target) {
    assert(builder.jumpTargets[target] == null);
    builder.jumpTargets[target] = this;
  }

  @override
  void generateBreak(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]) {
    HInstruction breakInstruction;
    if (label == null) {
      breakInstruction = HBreak(target, sourceInformation);
    } else {
      breakInstruction = HBreak.toLabel(label, sourceInformation);
    }
    LocalsHandler locals = LocalsHandler.from(builder.localsHandler);
    builder.close(breakInstruction as HJump);
    _jumps.add(_JumpHandlerEntry(breakInstruction, locals));
  }

  @override
  void generateContinue(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]) {
    HInstruction continueInstruction;
    if (label == null) {
      continueInstruction = HContinue(target, sourceInformation);
    } else {
      continueInstruction = HContinue.toLabel(label, sourceInformation);
      // Switch case continue statements must be handled by the
      // [SwitchCaseJumpHandler].
      assert(!label.target.isSwitchCase);
    }
    LocalsHandler locals = LocalsHandler.from(builder.localsHandler);
    builder.close(continueInstruction as HJump);
    _jumps.add(_JumpHandlerEntry(continueInstruction, locals));
  }

  @override
  void forEachBreak(
    void Function(HBreak instruction, LocalsHandler locals) action,
  ) {
    for (_JumpHandlerEntry entry in _jumps) {
      final jumpInstruction = entry.jumpInstruction;
      if (jumpInstruction is HBreak) action(jumpInstruction, entry.locals);
    }
  }

  @override
  void forEachContinue(
    void Function(HContinue instruction, LocalsHandler locals) action,
  ) {
    for (_JumpHandlerEntry entry in _jumps) {
      final jumpInstruction = entry.jumpInstruction;
      if (jumpInstruction is HContinue) action(jumpInstruction, entry.locals);
    }
  }

  @override
  bool hasAnyContinue() {
    for (_JumpHandlerEntry entry in _jumps) {
      if (entry.isContinue()) return true;
    }
    return false;
  }

  @override
  bool hasAnyBreak() {
    for (_JumpHandlerEntry entry in _jumps) {
      if (entry.isBreak()) return true;
    }
    return false;
  }

  @override
  void close() {
    // The mapping from TargetElement to JumpHandler is no longer needed.
    builder.jumpTargets.remove(target);
  }

  @override
  List<LabelDefinition> get labels {
    List<LabelDefinition>? result;
    for (LabelDefinition element in target.labels) {
      result ??= <LabelDefinition>[];
      result.add(element);
    }
    return result ?? const <LabelDefinition>[];
  }
}

/// Special [JumpHandler] implementation used to handle continue statements
/// targeting switch cases.
abstract class SwitchCaseJumpHandler extends TargetJumpHandler {
  /// Map from switch case targets to indices used to encode the flow of the
  /// switch case loop.
  final Map<JumpTarget, int> targetIndexMap = {};

  SwitchCaseJumpHandler(super.builder, super.target);

  @override
  void generateBreak(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]) {
    if (label == null) {
      // Creates a special break instruction for the synthetic loop generated
      // for a switch statement with continue statements. See
      // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.

      HInstruction breakInstruction = HBreak(
        target,
        sourceInformation,
        breakSwitchContinueLoop: true,
      );
      LocalsHandler locals = LocalsHandler.from(builder.localsHandler);
      builder.close(breakInstruction as HJump);
      _jumps.add(_JumpHandlerEntry(breakInstruction, locals));
    } else {
      super.generateBreak(sourceInformation, label);
    }
  }

  bool isContinueToSwitchCase(LabelDefinition? label) {
    return label != null && targetIndexMap.containsKey(label.target);
  }

  @override
  void generateContinue(
    SourceInformation? sourceInformation, [
    LabelDefinition? label,
  ]) {
    if (isContinueToSwitchCase(label)) {
      // Creates the special instructions 'label = i; continue l;' used in
      // switch statements with continue statements. See
      // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.

      HInstruction value = builder.graph.addConstantInt(
        targetIndexMap[label!.target]!,
        builder.closedWorld,
      );
      builder.localsHandler.updateLocal(target, value);

      assert(label.target.labels.contains(label));
      HInstruction continueInstruction = HContinue(target, sourceInformation);
      LocalsHandler locals = LocalsHandler.from(builder.localsHandler);
      builder.close(continueInstruction as HJump);
      _jumps.add(_JumpHandlerEntry(continueInstruction, locals));
    } else {
      super.generateContinue(sourceInformation, label);
    }
  }

  @override
  void close() {
    // The mapping from TargetElement to JumpHandler is no longer needed.
    for (JumpTarget target in targetIndexMap.keys) {
      builder.jumpTargets.remove(target);
    }
    super.close();
  }
}
