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

// @dart = 2.9

/// @assertion Stream<RawSocketEvent> distinct([bool equals(T previous, T next)])
/// Skips data events if they are equal to the previous data event.
/// . . .
/// The returned stream is a broadcast stream if this stream is. If a broadcast
/// stream is listened to more than once, each subscription will individually
/// perform the equals test.
///
/// @description Checks that the returned stream is a broadcast stream if this
/// stream is, and if a broadcast stream is listened to more than once, each
/// subscription will individually perform the equals test.
/// @author ngl@unipro.ru

import "dart:async";
import "dart:io";
import "../http_utils.dart";
import "../../../Utils/expect.dart";

var localhost = InternetAddress.loopbackIPv4;

Future<List> checkDistant() async {
  RawDatagramSocket producer = await RawDatagramSocket.bind(localhost, 0);
  RawDatagramSocket receiver = await RawDatagramSocket.bind(localhost, 0);
  List<List<int>> toSend = [[0, 1, 2, 3], [1, 2, 3], [2, 3], [3], [4, 5], [5]];
  List<RawSocketEvent> received1 = [];
  List<RawSocketEvent> received2 = [];
  List<RawSocketEvent> received3 = [];
  List<int> received = [0, 0, 0, 0];
  Completer<List<int>> completer = new Completer<List<int>>();
  Future<List<int>> f = completer.future;
  Duration delay = const Duration(seconds: 2);

  bool wasSent = await sendDatagram(producer, toSend, localhost, receiver.port);
  Expect.isTrue(wasSent, "No datagram was sent");

  Stream bcs = receiver.asBroadcastStream();
  Expect.isTrue(bcs.isBroadcast);
  Stream s = bcs.distinct((previous, next) => previous == next);
  Expect.isTrue(s.isBroadcast);
  s.listen((event) {
    received1.add(event);
  });
  s.listen((event) {
    received2.add(event);
  });
  s.listen((event) {
    received3.add(event);
  });
  bcs.listen((event) {
    receiver.receive();
    received[0]++;
    if (event == RawSocketEvent.closed) {
      if (!completer.isCompleted) {
        completer.complete(received);
      }
    }
  }, onDone: () {
    received[1] = received1.length;
    received[2] = received2.length;
    received[3] = received3.length;
  });

  new Future.delayed(delay, () {
    if (!completer.isCompleted) {
      receiver.close();
    }
  });
  return f;
}

main() async {
  int attempts = 5;
  int expectedLen = 3;

  for (int i = 0; i < attempts; i++) {
    List list = await checkDistant();
    if (list[0] == 0 || list[1] == 0 || list[2] == 0 || list[3] == 0) {
      continue;
    }
    if (list[1] > expectedLen ||
        list[2] > expectedLen ||
        list[3] > expectedLen) {
      Expect.fail(
          "Some distinct events ${list.sublist(1)} is greater then $expectedLen.");
    }
    if (list[0] > list[1] && list[0] > list[2] && list[0] > list[3]) {
      break;
    }
    if (i == attempts - 1) {
      print(
          'Received events ${list[0]}, distinct events ${list.sublist(1)}. Look like test failed.');
    }
  }
}
