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

// VMOptions=
// VMOptions=--short_socket_read
// VMOptions=--short_socket_write
// VMOptions=--short_socket_read --short_socket_write
//
// Test socket close events.

import 'dart:async';
import 'dart:io';
import 'dart:isolate';

import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";

const SERVERSHUTDOWN = -1;
const ITERATIONS = 10;

Future sendReceive(SendPort port, message) {
  ReceivePort receivePort = new ReceivePort();
  port.send([message, receivePort.sendPort]);
  return receivePort.first;
}

class SocketClose {
  SocketClose.start(this._mode, this._done)
      : _sendPort = null,
        _readBytes = 0,
        _dataEvents = 0,
        _closeEvents = 0,
        _errorEvents = 0,
        _iterations = 0 {
    initialize();
  }

  void proceed() {
    if (_iterations < ITERATIONS) {
      Timer.run(sendData);
    } else {
      shutdown();
    }
  }

  void sendData() {
    void dataHandler(bytes) {
      switch (_mode) {
        case 0:
        case 1:
        case 2:
          Expect.fail("No data expected");
          break;
        case 3:
        case 4:
        case 5:
        case 6:
          _readBytes += bytes.length;
          if ((_readBytes % 5) == 0) {
            _dataEvents++;
          }
          break;
        default:
          Expect.fail("Unknown test mode");
      }
    }

    void closeHandler(socket) {
      _closeEvents++;
      switch (_mode) {
        case 0:
        case 1:
          socket.close();
          break;
        case 2:
        case 3:
          socket.close();
          proceed();
          break;
        case 4:
          proceed();
          break;
        case 5:
          socket.close();
          proceed();
          break;
        case 6:
          proceed();
          break;
        default:
          Expect.fail("Unknown test mode");
      }
    }

    void errorHandler(Socket socket) {
      _errorEvents++;
      socket.close();
    }

    void connectHandler(socket) {
      socket.listen(dataHandler,
          onDone: () => closeHandler(socket),
          onError: (error) => errorHandler(socket));

      void writeHello() {
        socket.write("Hello");
      }

      _iterations++;
      switch (_mode) {
        case 0:
          socket.destroy();
          proceed();
          break;
        case 1:
          writeHello();
          socket.destroy();
          proceed();
          break;
        case 2:
        case 3:
          writeHello();
          break;
        case 4:
          writeHello();
          socket.close(); // Half close.
          break;
        case 5:
          writeHello();
          break;
        case 6:
          writeHello();
          socket.close(); // Half close.
          break;
        default:
          Expect.fail("Unknown test mode");
      }
    }

    Socket.connect(SocketCloseServer.HOST, _port).then(connectHandler);
  }

  void initialize() {
    ReceivePort receivePort = new ReceivePort();
    var remote = Isolate.spawn(startSocketCloseServer, receivePort.sendPort);

    receivePort.first.then((message) {
      this._sendPort = message;
      sendReceive(_sendPort, _mode).then((port) {
        this._port = port;
        proceed();
      });
    });
  }

  void shutdown() {
    sendReceive(_sendPort, SERVERSHUTDOWN).then((_) {
      _done();
    });

    switch (_mode) {
      case 0:
      case 1:
        Expect.equals(0, _dataEvents);
        Expect.equals(ITERATIONS, _closeEvents);
        break;
      case 2:
        Expect.equals(0, _dataEvents);
        Expect.equals(ITERATIONS, _closeEvents);
        break;
      case 3:
      case 4:
        Expect.isTrue(_dataEvents <= ITERATIONS);
        Expect.isTrue(_dataEvents >= 0);
        Expect.equals(ITERATIONS, _closeEvents);
        break;
      case 5:
      case 6:
        Expect.equals(ITERATIONS, _dataEvents);
        Expect.equals(ITERATIONS, _closeEvents);
        break;
      default:
        Expect.fail("Unknown test mode");
    }
    Expect.equals(0, _errorEvents);
  }

  int _port;
  SendPort _sendPort;
  List<int> _buffer;
  int _readBytes;
  int _dataEvents;
  int _closeEvents;
  int _errorEvents;
  int _iterations;
  int _mode;
  Function _done;
}

class ConnectionData {
  ConnectionData(Socket this.connection) : readBytes = 0;
  Socket connection;
  int readBytes;
}

void startSocketCloseServer(Object replyToObj) {
  SendPort replyTo = replyToObj;
  var server = new SocketCloseServer();
  replyTo.send(server.dispatchSendPort);
}

class SocketCloseServer {
  static const HOST = "127.0.0.1";

  SocketCloseServer() : _dispatchPort = new ReceivePort() {
    _dispatchPort.listen(dispatch);
  }

  void connectionHandler(ConnectionData data) {
    var connection = data.connection;

    void readBytes(bytes, whenFiveBytes) {
      data.readBytes += bytes.length;
      Expect.isTrue(data.readBytes <= 5);
      if (data.readBytes == 5) {
        whenFiveBytes();
      }
    }

    void writeHello() {
      connection.write("Hello");
    }

    void dataHandler(bytes) {
      switch (_mode) {
        case 0:
          Expect.fail("No data expected");
          break;
        case 1:
          readBytes(bytes, () {
            _dataEvents++;
          });
          break;
        case 2:
          readBytes(bytes, () {
            _dataEvents++;
            connection.destroy();
          });
          break;
        case 3:
          readBytes(bytes, () {
            _dataEvents++;
            writeHello();
            connection.destroy();
          });
          break;
        case 4:
          readBytes(bytes, () {
            _dataEvents++;
            writeHello();
          });
          break;
        case 5:
        case 6:
          readBytes(bytes, () {
            _dataEvents++;
            writeHello();
            connection.close(); // Half close.
          });
          break;
        default:
          Expect.fail("Unknown test mode");
      }
    }

    void closeHandler() {
      _closeEvents++;
      connection.close();
    }

    void errorHandler(e) {
      Expect.fail("Socket error $e");
    }

    _iterations++;

    connection.listen(dataHandler, onDone: closeHandler, onError: errorHandler);
  }

  void errorHandlerServer(e) {
    Expect.fail("Server socket error");
  }

  waitForResult() {
    // Make sure all iterations have been run. In multiple of these
    // scenarios it is possible to get the SERVERSHUTDOWN message
    // before we have received the last close event on the
    // server. In these cases we wait for the correct number of
    // close events.
    if (_iterations == ITERATIONS &&
        (_closeEvents == ITERATIONS || (_mode == 2 || _mode == 3))) {
      switch (_mode) {
        case 0:
          Expect.equals(0, _dataEvents);
          Expect.equals(ITERATIONS, _closeEvents);
          break;
        case 1:
          Expect.isTrue(_dataEvents <= ITERATIONS);
          Expect.isTrue(_dataEvents >= 0);
          Expect.equals(ITERATIONS, _closeEvents);
          break;
        case 2:
        case 3:
          Expect.equals(ITERATIONS, _dataEvents);
          Expect.equals(ITERATIONS, _closeEvents);
          break;
        case 4:
        case 5:
        case 6:
          Expect.equals(ITERATIONS, _dataEvents);
          Expect.equals(ITERATIONS, _closeEvents);
          break;
        default:
          Expect.fail("Unknown test mode");
      }
      Expect.equals(0, _errorEvents);
      _server.close();
      _dispatchPort.close();
      _donePort.send(null);
    } else {
      new Timer(new Duration(milliseconds: 100), waitForResult);
    }
  }

  SendPort get dispatchSendPort => _dispatchPort.sendPort;

  void dispatch(message) {
    var command = message[0];
    SendPort replyTo = message[1];
    _donePort = replyTo;
    if (command != SERVERSHUTDOWN) {
      _readBytes = 0;
      _errorEvents = 0;
      _dataEvents = 0;
      _closeEvents = 0;
      _iterations = 0;
      _mode = command;
      ServerSocket.bind("127.0.0.1", 0).then((server) {
        _server = server;
        _server.listen((socket) {
          var data = new ConnectionData(socket);
          connectionHandler(data);
        }, onError: errorHandlerServer);
        replyTo.send(_server.port);
      });
    } else {
      Timer.run(waitForResult);
    }
  }

  ServerSocket _server;
  final ReceivePort _dispatchPort;
  SendPort _donePort;
  int _readBytes;
  int _errorEvents;
  int _dataEvents;
  int _closeEvents;
  int _iterations;
  int _mode;
}

main() {
  // Run the close test in these different "modes".
  // 0: Client closes without sending at all.
  // 1: Client sends and destroys.
  // 2: Client sends. Server destroys.
  // 3: Client sends. Server responds and destroys.
  // 4: Client sends and half-closes. Server responds and destroys.
  // 5: Client sends. Server responds and half closes.
  // 6: Client sends and half-closes. Server responds and half closes.
  var tests = 7;
  for (var i = 0; i < tests; i++) {
    asyncStart();
    new SocketClose.start(i, asyncEnd);
  }
}
