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

// @dart = 2.7

// Output provider that collects the output in string buffers.

library output_collector;

import 'package:compiler/compiler.dart';

class BufferedOutputSink implements OutputSink {
  StringBuffer sb = new StringBuffer();
  String text;

  @override
  void add(String event) {
    sb.write(event);
  }

  @override
  void close() {
    text = sb.toString();
    sb = null;
  }

  @override
  String toString() {
    return text ?? sb.toString();
  }
}

class BufferedBinaryOutputSink implements BinaryOutputSink {
  final Uri uri;

  List<int> list = <int>[];

  BufferedBinaryOutputSink(this.uri);

  @override
  void write(List<int> buffer, [int start = 0, int end]) {
    list.addAll(buffer.sublist(start, end));
  }

  @override
  void close() {}

  @override
  String toString() {
    return 'BufferedBinaryOutputSink($uri)';
  }
}

class CloningOutputSink implements OutputSink {
  final List<OutputSink> sinks;

  CloningOutputSink(this.sinks);

  @override
  void add(String event) {
    sinks.forEach((OutputSink sink) => sink.add(event));
  }

  @override
  void close() {
    sinks.forEach((OutputSink sink) => sink.close());
  }
}

class OutputCollector implements CompilerOutput {
  Map<OutputType, Map<String, BufferedOutputSink>> outputMap = {};
  Map<Uri, BufferedBinaryOutputSink> binaryOutputMap = {};

  String getOutput(String name, OutputType type) {
    Map<String, BufferedOutputSink> sinkMap = outputMap[type];
    if (sinkMap == null) {
      print("No output available for $type.");
      return null;
    }
    BufferedOutputSink sink = sinkMap[name];
    if (sink == null) {
      print("Output '$name' not found for $type. Available: ${sinkMap.keys}");
      return null;
    } else {
      return sink.text;
    }
  }

  @override
  BinaryOutputSink createBinarySink(Uri uri) {
    return binaryOutputMap.putIfAbsent(
        uri, () => new BufferedBinaryOutputSink(uri));
  }

  /// `true` if any output has been collected.
  bool get hasOutput => outputMap.isNotEmpty || binaryOutputMap.isNotEmpty;

  /// `true` if any output other than main output has been collected.
  bool get hasExtraOutput {
    for (OutputType type in outputMap.keys) {
      for (String name in outputMap[type].keys) {
        if (name != '') return true;
      }
    }
    return binaryOutputMap.isNotEmpty;
  }

  @override
  OutputSink createOutputSink(String name, String extension, OutputType type) {
    Map<String, BufferedOutputSink> sinkMap =
        outputMap.putIfAbsent(type, () => {});
    return sinkMap.putIfAbsent(name, () => new BufferedOutputSink());
  }

  Map<OutputType, Map<String, String>> clear() {
    Map<OutputType, Map<String, String>> outputMapResult = {};
    outputMap.forEach(
        (OutputType outputType, Map<String, BufferedOutputSink> sinkMap) {
      Map<String, String> sinkMapResult = outputMapResult[outputType] = {};
      sinkMap.forEach((String name, BufferedOutputSink sink) {
        sinkMapResult[name] = sink.toString();
      });
    });
    outputMap.clear();
    binaryOutputMap.clear();
    return outputMapResult;
  }
}
