// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file

/// A version of app.dart built on the new async bindings.

import 'dart:async';
import 'package:fidl/fidl.dart';
import 'package:fuchsia/fuchsia.dart';
import 'package:fidl_fuchsia_sys/fidl_async.dart';
import 'package:zircon/zircon.dart';
import 'package:fidl_fuchsia_io/fidl_async.dart';

import 'app.dart' as sync_app;

/// Deprecated! Use package:fuchsia_services/services.dart instead
class StartupContext {
  static StartupContext _context;

  StartupContext();

  final EnvironmentProxy environment = new EnvironmentProxy();
  final LauncherProxy launcher = new LauncherProxy();
  final ServiceProviderProxy environmentServices = new ServiceProviderProxy();
  final ServiceProviderImpl outgoingServices = new ServiceProviderImpl();

  factory StartupContext.fromStartupInfo() {
    if (_context != null) {
      return _context;
    }

    if (sync_app.StartupContext.initialTrace != null) {
      print(
          "WARNING: app.dart's StartupContext was created at:\n${sync_app.StartupContext.initialTrace}");
    }

    final StartupContext context = new StartupContext();

    final Handle environmentHandle = MxStartupInfo.takeEnvironment();
    if (environmentHandle != null) {
      context.environment
        ..ctrl.bind(
            new InterfaceHandle<Environment>(new Channel(environmentHandle)))
        ..getLauncher(context.launcher.ctrl.request())
        ..getServices(context.environmentServices.ctrl.request());
    }

    final Handle outgoingServicesHandle = MxStartupInfo.takeOutgoingServices();
    if (outgoingServicesHandle != null) {
      context.outgoingServices.bind(new InterfaceRequest<ServiceProvider>(
          new Channel(outgoingServicesHandle)));
    }

    _context = context;

    return context;
  }

  /// Provide an alternative startup context that will then be provided on
  /// through [StartupContext.fromStartupInfo].
  ///
  /// This is primarily used to provide alternative environment services for
  /// testing purposes.
  static void provideStartupContext(StartupContext context) {
    assert(_context != null, 'StartupContext should never be overwritten.');
    _context = context;
  }

  void close() {
    environment.ctrl.close();
    launcher.ctrl.close();
    environmentServices.ctrl.close();
    outgoingServices.close();
  }
}

/// Deprecated! Use package:fuchsia_services/services.dart instead
Future<void> connectToService<T>(
    ServiceProvider serviceProvider, AsyncProxyController<T> controller) async {
  final String serviceName = controller.$serviceName;
  if (serviceName == null) {
    throw new Exception(
        "${controller.$interfaceName}'s controller.\$serviceName"
        ' must not be null. Check the FIDL file for a missing [Discoverable]');
  }
  await serviceProvider.connectToService(
      serviceName, controller.request().passChannel());
}

/// Deprecated! Use package:fuchsia_services/services.dart instead
InterfaceHandle<T> connectToServiceByName<T>(
    ServiceProvider serviceProvider, String serviceName) {
  final ChannelPair pair = new ChannelPair();
  serviceProvider.connectToService(serviceName, pair.first);
  return new InterfaceHandle<T>(pair.second);
}

typedef ServiceConnector<T> = void Function(InterfaceRequest<T> request);
typedef DefaultServiceConnector<T> = void Function(
    String serviceName, InterfaceRequest<T> request);

typedef _ServiceConnectorThunk = void Function(Channel channel);

/// Deprecated! Use package:fuchsia_services/services.dart instead
class ServiceProviderImpl extends ServiceProvider {
  final ServiceProviderBinding _binding = new ServiceProviderBinding();

  void bind(InterfaceRequest<ServiceProvider> interfaceRequest) {
    _binding.bind(this, interfaceRequest);
  }

  void close() {
    _binding.close();
  }

  DefaultServiceConnector<dynamic> defaultConnector;

  final Map<String, _ServiceConnectorThunk> _connectorThunks =
      <String, _ServiceConnectorThunk>{};

  void addServiceForName<T>(ServiceConnector<T> connector, String serviceName) {
    _connectorThunks[serviceName] = (Channel channel) {
      connector(new InterfaceRequest<T>(channel));
    };
  }

  @override
  Future<Null> connectToService(String serviceName, Channel channel) {
    final _ServiceConnectorThunk connectorThunk = _connectorThunks[serviceName];
    if (connectorThunk != null) {
      connectorThunk(channel);
    } else if (defaultConnector != null) {
      defaultConnector(serviceName, new InterfaceRequest<dynamic>(channel));
    } else {
      channel.close();
    }
    return null;
  }
}

/// Deprecated! Use package:fuchsia_services/services.dart instead
class Services {
  DirectoryProxy _proxy;
  static const int _openFlags =
      openRightReadable | openRightWritable; // connect flags for service
  static const int _openMode = 0x1ED; // 0755

  Services();

  Channel request() {
    _proxy = DirectoryProxy();
    return _proxy.ctrl.request().passChannel();
  }

  Future<void> connectToService<T>(AsyncProxyController<T> controller) async {
    final String serviceName = controller.$serviceName;
    if (serviceName == null) {
      throw new Exception(
          "${controller.$interfaceName}'s controller.\$serviceName"
          ' must not be null. Check the FIDL file for a missing [Discoverable]');
    }
    await _proxy.open(_openFlags, _openMode, serviceName,
        InterfaceRequest<Node>(controller.request().passChannel()));
  }

  Future<InterfaceHandle<T>> connectToServiceByName<T>(
      String serviceName) async {
    final ChannelPair pair = new ChannelPair();
    await _proxy.open(
        _openFlags, _openMode, serviceName, InterfaceRequest<Node>(pair.first));
    return new InterfaceHandle<T>(pair.second);
  }

  Future<void> close() async {
    await _proxy.close();
  }
}
