#!mojo mojo:dart_content_handler
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:core';
import 'dart:typed_data';

import 'package:mojo/application.dart';
import 'package:mojo/bindings.dart';
import 'package:mojo/core.dart';
import 'package:mojo/mojo/network_error.mojom.dart';
import 'package:mojo_services/mojo/files/file.mojom.dart' as files;
import 'package:mojo_services/mojo/files/types.mojom.dart' as files;
import 'package:mojo_services/mojo/net_address.mojom.dart';
import 'package:mojo_services/mojo/network_service.mojom.dart';
import 'package:mojo_services/mojo/tcp_bound_socket.mojom.dart';
import 'package:mojo_services/mojo/tcp_connected_socket.mojom.dart';
import 'package:mojo_services/mojo/terminal/terminal_client.mojom.dart';

void ignoreFuture(Future f) {
  f.catchError((e) {});
}

NetAddress makeIPv4NetAddress(List<int> addr, int port) {
  var rv = new NetAddress();
  rv.family = NetAddressFamily.IPV4;
  rv.ipv4 = new NetAddressIPv4();
  rv.ipv4.addr = new List<int>.from(addr);
  rv.ipv4.port = port;
  return rv;
}

void fputs(files.File f, String s) {
  ignoreFuture(f.write((s + '\n').codeUnits, 0, files.Whence.FROM_CURRENT));
}

// Connects the terminal |File| and the socket.
// TODO(vtl):
// * Error handling: both connection/socket errors and terminal errors.
// * Relatedly, we should listen for _socketSender's peer being closed (also
//   _socket, I guess).
// * Handle the socket send pipe being full (currently, we assume it's never
//   full).
class Connector {
  final Application _application;
  files.FileProxy _terminal;
  TcpConnectedSocketProxy _socket;
  MojoDataPipeProducer _socketSender;
  MojoDataPipeConsumer _socketReceiver;
  MojoEventStream _socketReceiverEventStream;
  final ByteData _readBuffer;
  final ByteData _writeBuffer;

  // TODO(vtl): Don't just hard-code buffer sizes.
  Connector(this._application, this._terminal)
      : _readBuffer = new ByteData(16 * 1024),
        _writeBuffer = new ByteData(16 * 1024);

  Future connect(NetAddress remote_address) async {
    try {
      var networkService = new NetworkServiceProxy.unbound();
      _application.connectToService('mojo:network_service', networkService);

      NetAddress local_address = makeIPv4NetAddress([0, 0, 0, 0], 0);
      var boundSocket = new TcpBoundSocketProxy.unbound();
      await networkService.ptr.createTcpBoundSocket(local_address, boundSocket);
      await networkService.close();

      var sendDataPipe = new MojoDataPipe();
      _socketSender = sendDataPipe.producer;
      var receiveDataPipe = new MojoDataPipe();
      _socketReceiver = receiveDataPipe.consumer;
      _socket = new TcpConnectedSocketProxy.unbound();
      await boundSocket.ptr.connect(remote_address, sendDataPipe.consumer,
          receiveDataPipe.producer, _socket);
      await boundSocket.close();

      // Set up reading from the terminal.
      _startReadingFromTerminal();

      // Set up reading from the socket.
      _socketReceiverEventStream = new MojoEventStream(_socketReceiver.handle);
      _socketReceiverEventStream.listen(_onSocketReceiverEvent);
    } catch (e) {
      _shutDown();
    }
  }

  void _startReadingFromTerminal() {
    // TODO(vtl): Do we have to do something on error?
    _terminal.ptr
        .read(_writeBuffer.lengthInBytes, 0, files.Whence.FROM_CURRENT)
        .then(_onReadFromTerminal)
        .catchError((e) { _shutDown(); });
  }

  void _onReadFromTerminal(files.FileReadResponseParams p) {
    if (p.error != files.Error.OK) {
      // TODO(vtl): Do terminal errors.
      return;
    }

    // TODO(vtl): Verify that |bytesRead.length| is within the expected range.
    for (var i = 0, j = 0; i < p.bytesRead.length; i++, j++) {
      // TODO(vtl): Temporary hack: Translate \r to \n, since we don't have
      // built-in support for that.
      if (p.bytesRead[i] == 13) {
        _writeBuffer.setUint8(i, 10);
      } else {
        _writeBuffer.setUint8(i, p.bytesRead[i]);
      }
    }

    // TODO(vtl): Handle the send data pipe being full (or closed).
    _socketSender
        .write(new ByteData.view(_writeBuffer.buffer, 0, p.bytesRead.length));

    _startReadingFromTerminal();
  }

  void _onSocketReceiverEvent(List<int> event) {
    var mojoSignals = new MojoHandleSignals(event[1]);
    var shouldShutDown = false;
    if (mojoSignals.isReadable) {
      var numBytesRead = _socketReceiver.read(_readBuffer);
      if (_socketReceiver.status.isOk) {
        assert(numBytesRead > 0);
        _terminal.ptr.write(_readBuffer.buffer.asUint8List(0, numBytesRead), 0,
                            files.Whence.FROM_CURRENT)
            .catchError((e) { _shutDown(); });
        _socketReceiverEventStream.enableReadEvents();
      } else {
        shouldShutDown = true;
      }
    } else if (mojoSignals.isPeerClosed) {
      shouldShutDown = true;
    } else {
      throw 'Unexpected handle event: $mojoSignals';
    }
    if (shouldShutDown) {
      _shutDown();
    }
  }

  void _shutDown() {
    if (_socketReceiverEventStream != null) {
      ignoreFuture(_socketReceiverEventStream.close());
      _socketReceiverEventStream = null;
    }
    if (_socketSender != null) {
      if (_socketSender.handle.isValid)
        _socketSender.handle.close();
      _socketSender = null;
    }
    if (_socketReceiver != null) {
      if (_socketReceiver.handle.isValid)
        _socketReceiver.handle.close();
      _socketReceiver = null;
    }
    if (_terminal != null) {
      ignoreFuture(_terminal.close());
      _terminal = null;
    }
  }
}

class TerminalClientImpl implements TerminalClient {
  TerminalClientStub _stub;
  Application _application;
  String _resolvedUrl;

  TerminalClientImpl(
      this._application, this._resolvedUrl, MojoMessagePipeEndpoint endpoint) {
    _stub = new TerminalClientStub.fromEndpoint(endpoint, this);
  }

  @override
  void connectToTerminal(files.FileProxy terminal) {
    var url = Uri.parse(_resolvedUrl);
    NetAddress remote_address;
    try {
      remote_address = _getNetAddressFromUrl(url);
    } catch (e) {
      fputs(terminal.ptr, 'HALP: Add a query: ?host=<host>&port=<port>\n'
          '(<host> must be "localhost" or n1.n2.n3.n4)\n\n'
          'Got query parameters:\n' + url.queryParameters.toString());
      ignoreFuture(terminal.close());
      return;
    }

    // TODO(vtl): Currently, we only do IPv4, so this should work.
    fputs(terminal.ptr,
          'Connecting to: ' + remote_address.ipv4.addr.join('.') + ':' +
              remote_address.ipv4.port.toString() + '...');

    var connector = new Connector(_application, terminal);
    // TODO(vtl): Do we have to do something on error?
    connector.connect(remote_address)
        .catchError((e) {});
  }

  // Note: May throw all sorts of things.
  static NetAddress _getNetAddressFromUrl(Uri url) {
    var params = url.queryParameters;
    var host = params['host'];
    return makeIPv4NetAddress(
        (host == 'localhost') ? [127, 0, 0, 1] : Uri.parseIPv4Address(host),
        int.parse(params['port']));
  }
}

class NetcatApplication extends Application {
  NetcatApplication.fromHandle(MojoHandle handle) : super.fromHandle(handle);

  @override
  void acceptConnection(String requestorUrl, String resolvedUrl,
      ApplicationConnection connection) {
    connection.provideService(TerminalClientName,
        (endpoint) => new TerminalClientImpl(this, resolvedUrl, endpoint));
  }
}

main(List args) {
  MojoHandle appHandle = new MojoHandle(args[0]);
  String url = args[1];
  new NetcatApplication.fromHandle(appHandle)
    ..onError = (() {
      assert(MojoHandle.reportLeakedHandles());
    });
}
