// Copyright (c) 2012, 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.

// @dart = 2.10

library dart2js.code_output;

import '../../compiler.dart' as api show OutputSink;
import 'code_output_listener.dart';
export 'code_output_listener.dart';
import 'source_information.dart';

/// Interface for a mapping of target offsets to source locations and for
/// tracking inlining frame data.
///
/// Source-location mapping is used to build standard source-maps files.
/// Inlining frames is used to attach an extension to source-map files to
/// improve deobfuscation of production stack traces.
abstract class SourceLocations {
  /// The name identifying this source mapping.
  String get name;

  /// Adds a [sourceLocation] at the specified [targetOffset].
  void addSourceLocation(int targetOffset, SourceLocation sourcePosition);

  /// Record an inlining call at the [targetOffset].
  ///
  /// The inlining call-site was made from [pushLocation] and calls
  /// [inlinedMethodName].
  void addPush(
      int targetOffset, SourceLocation pushPosition, String inlinedMethodName);

  /// Record a return of an inlining call at the [targetOffset].
  ///
  /// [isEmpty] indicates that this return also makes the inlining stack empty.
  void addPop(int targetOffset, bool isEmpty);

  /// Applies [f] to every target offset and associated source location.
  void forEachSourceLocation(
      void f(int targetOffset, SourceLocation sourceLocation));

  /// Recorded inlining data per target-offset.
  Map<int, List<FrameEntry>> get frameMarkers;
}

class _SourceLocationsImpl implements SourceLocations {
  @override
  final String name;
  final AbstractCodeOutput codeOutput;
  Map<int, List<SourceLocation>> markers = {};
  @override
  Map<int, List<FrameEntry>> frameMarkers = {};

  _SourceLocationsImpl(this.name, this.codeOutput);

  @override
  void addSourceLocation(int targetOffset, SourceLocation sourceLocation) {
    assert(targetOffset <= codeOutput.length);
    List<SourceLocation> sourceLocations =
        markers.putIfAbsent(targetOffset, () => []);
    sourceLocations.add(sourceLocation);
  }

  @override
  void addPush(int targetOffset, SourceLocation sourceLocation,
      String inlinedMethodName) {
    assert(targetOffset <= codeOutput.length);
    List<FrameEntry> frames = frameMarkers[targetOffset] ??= [];
    frames.add(FrameEntry.push(sourceLocation, inlinedMethodName));
  }

  @override
  void addPop(int targetOffset, bool isEmpty) {
    assert(targetOffset <= codeOutput.length);
    List<FrameEntry> frames = frameMarkers[targetOffset] ??= [];
    frames.add(FrameEntry.pop(isEmpty));
  }

  @override
  void forEachSourceLocation(
      void f(int targetOffset, SourceLocation sourceLocation)) {
    markers.forEach((int targetOffset, List<SourceLocation> sourceLocations) {
      for (SourceLocation sourceLocation in sourceLocations) {
        f(targetOffset, sourceLocation);
      }
    });
  }

  void _merge(_SourceLocationsImpl other) {
    assert(name == other.name);
    int length = codeOutput.length;
    if (other.markers.length > 0) {
      other.markers
          .forEach((int targetOffset, List<SourceLocation> sourceLocations) {
        (markers[length + targetOffset] ??= []).addAll(sourceLocations);
      });
    }

    if (other.frameMarkers.length > 0) {
      other.frameMarkers.forEach((int targetOffset, List<FrameEntry> frames) {
        (frameMarkers[length + targetOffset] ??= []).addAll(frames);
      });
    }
  }
}

abstract class SourceLocationsProvider {
  /// Creates a [SourceLocations] mapping identified by [name] and associates
  /// it with this code output.
  SourceLocations createSourceLocations(String name);

  /// Returns the source location mappings associated with this code output.
  Iterable<SourceLocations> get sourceLocations;
}

abstract class CodeOutput implements SourceLocationsProvider {
  /// Write [text] to this output.
  ///
  /// If the output is closed, a [StateError] is thrown.
  void add(String text);

  /// Adds the content of [buffer] to the output and adds its markers to
  /// [markers].
  ///
  /// If the output is closed, a [StateError] is thrown.
  void addBuffer(CodeBuffer buffer);

  /// Returns the number of characters currently written to this output.
  int get length;

  /// Returns `true` if this output has been closed.
  bool get isClosed;

  /// Closes the output. Further writes will cause a [StateError].
  void close();
}

abstract class AbstractCodeOutput extends CodeOutput {
  final List<CodeOutputListener> _listeners;

  AbstractCodeOutput([this._listeners]);

  Map<String, _SourceLocationsImpl> sourceLocationsMap =
      <String, _SourceLocationsImpl>{};
  @override
  bool isClosed = false;

  void _addInternal(String text);

  void _add(String text) {
    _addInternal(text);
    _listeners?.forEach((listener) => listener.onText(text));
  }

  @override
  void add(String text) {
    if (isClosed) {
      throw StateError("Code output is closed. Trying to write '$text'.");
    }
    _add(text);
  }

  @override
  void addBuffer(CodeBuffer other) {
    other.sourceLocationsMap.forEach((String name, _SourceLocationsImpl other) {
      createSourceLocations(name)._merge(other);
    });
    if (!other.isClosed) {
      other.close();
    }
    _add(other.getText());
  }

  @override
  void close() {
    if (isClosed) {
      throw StateError("Code output is already closed.");
    }
    isClosed = true;
    _listeners?.forEach((listener) => listener.onDone(length));
  }

  @override
  Iterable<SourceLocations> get sourceLocations => sourceLocationsMap.values;

  @override
  _SourceLocationsImpl createSourceLocations(String name) {
    return sourceLocationsMap[name] ??= _SourceLocationsImpl(name, this);
  }
}

abstract class BufferedCodeOutput {
  String getText();
}

/// [CodeOutput] using a [StringBuffer] as backend.
class CodeBuffer extends AbstractCodeOutput implements BufferedCodeOutput {
  StringBuffer buffer = StringBuffer();

  CodeBuffer([List<CodeOutputListener> listeners]) : super(listeners);

  @override
  void _addInternal(String text) {
    buffer.write(text);
  }

  @override
  int get length => buffer.length;

  @override
  String getText() {
    return buffer.toString();
  }

  @override
  String toString() {
    throw "Don't use CodeBuffer.toString() since it drops sourcemap data.";
  }
}

/// [CodeOutput] using a [CompilationOutput] as backend.
class StreamCodeOutput extends AbstractCodeOutput {
  @override
  int length = 0;
  final api.OutputSink output;

  StreamCodeOutput(this.output, [List<CodeOutputListener> listeners])
      : super(listeners);

  @override
  void _addInternal(String text) {
    output.add(text);
    length += text.length;
  }

  @override
  void close() {
    output.close();
    super.close();
  }
}
