// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v1.0.8), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name
// @dart = 2.12
import 'dart:async';
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;

import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
import 'package:flutter/services.dart';

class Everything {
  bool? aBool;
  int? anInt;
  double? aDouble;
  String? aString;
  Uint8List? aByteArray;
  Int32List? a4ByteArray;
  Int64List? a8ByteArray;
  Float64List? aFloatArray;
  List<Object?>? aList;
  Map<Object?, Object?>? aMap;
  List<List<bool?>?>? nestedList;
  Map<String?, String?>? mapWithAnnotations;
  Map<String?, Object?>? mapWithObject;

  Object encode() {
    final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
    pigeonMap['aBool'] = aBool;
    pigeonMap['anInt'] = anInt;
    pigeonMap['aDouble'] = aDouble;
    pigeonMap['aString'] = aString;
    pigeonMap['aByteArray'] = aByteArray;
    pigeonMap['a4ByteArray'] = a4ByteArray;
    pigeonMap['a8ByteArray'] = a8ByteArray;
    pigeonMap['aFloatArray'] = aFloatArray;
    pigeonMap['aList'] = aList;
    pigeonMap['aMap'] = aMap;
    pigeonMap['nestedList'] = nestedList;
    pigeonMap['mapWithAnnotations'] = mapWithAnnotations;
    pigeonMap['mapWithObject'] = mapWithObject;
    return pigeonMap;
  }

  static Everything decode(Object message) {
    final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
    return Everything()
      ..aBool = pigeonMap['aBool'] as bool?
      ..anInt = pigeonMap['anInt'] as int?
      ..aDouble = pigeonMap['aDouble'] as double?
      ..aString = pigeonMap['aString'] as String?
      ..aByteArray = pigeonMap['aByteArray'] as Uint8List?
      ..a4ByteArray = pigeonMap['a4ByteArray'] as Int32List?
      ..a8ByteArray = pigeonMap['a8ByteArray'] as Int64List?
      ..aFloatArray = pigeonMap['aFloatArray'] as Float64List?
      ..aList = pigeonMap['aList'] as List<Object?>?
      ..aMap = pigeonMap['aMap'] as Map<Object?, Object?>?
      ..nestedList =
          (pigeonMap['nestedList'] as List<Object?>?)?.cast<List<bool?>?>()
      ..mapWithAnnotations =
          (pigeonMap['mapWithAnnotations'] as Map<Object?, Object?>?)
              ?.cast<String?, String?>()
      ..mapWithObject = (pigeonMap['mapWithObject'] as Map<Object?, Object?>?)
          ?.cast<String?, Object?>();
  }
}

class _HostEverythingCodec extends StandardMessageCodec {
  const _HostEverythingCodec();
  @override
  void writeValue(WriteBuffer buffer, Object? value) {
    if (value is Everything) {
      buffer.putUint8(128);
      writeValue(buffer, value.encode());
    } else {
      super.writeValue(buffer, value);
    }
  }

  @override
  Object? readValueOfType(int type, ReadBuffer buffer) {
    switch (type) {
      case 128:
        return Everything.decode(readValue(buffer)!);

      default:
        return super.readValueOfType(type, buffer);
    }
  }
}

class HostEverything {
  /// Constructor for [HostEverything].  The [binaryMessenger] named argument is
  /// available for dependency injection.  If it is left null, the default
  /// BinaryMessenger will be used which routes to the host platform.
  HostEverything({BinaryMessenger? binaryMessenger})
      : _binaryMessenger = binaryMessenger;

  final BinaryMessenger? _binaryMessenger;

  static const MessageCodec<Object?> codec = _HostEverythingCodec();

  Future<Everything> giveMeEverything() async {
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
        'dev.flutter.pigeon.HostEverything.giveMeEverything', codec,
        binaryMessenger: _binaryMessenger);
    final Map<Object?, Object?>? replyMap =
        await channel.send(null) as Map<Object?, Object?>?;
    if (replyMap == null) {
      throw PlatformException(
        code: 'channel-error',
        message: 'Unable to establish connection on channel.',
        details: null,
      );
    } else if (replyMap['error'] != null) {
      final Map<Object?, Object?> error =
          (replyMap['error'] as Map<Object?, Object?>?)!;
      throw PlatformException(
        code: (error['code'] as String?)!,
        message: error['message'] as String?,
        details: error['details'],
      );
    } else {
      return (replyMap['result'] as Everything?)!;
    }
  }

  Future<Everything> echo(Everything arg_everything) async {
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
        'dev.flutter.pigeon.HostEverything.echo', codec,
        binaryMessenger: _binaryMessenger);
    final Map<Object?, Object?>? replyMap =
        await channel.send(<Object>[arg_everything]) as Map<Object?, Object?>?;
    if (replyMap == null) {
      throw PlatformException(
        code: 'channel-error',
        message: 'Unable to establish connection on channel.',
        details: null,
      );
    } else if (replyMap['error'] != null) {
      final Map<Object?, Object?> error =
          (replyMap['error'] as Map<Object?, Object?>?)!;
      throw PlatformException(
        code: (error['code'] as String?)!,
        message: error['message'] as String?,
        details: error['details'],
      );
    } else {
      return (replyMap['result'] as Everything?)!;
    }
  }
}

class _FlutterEverythingCodec extends StandardMessageCodec {
  const _FlutterEverythingCodec();
  @override
  void writeValue(WriteBuffer buffer, Object? value) {
    if (value is Everything) {
      buffer.putUint8(128);
      writeValue(buffer, value.encode());
    } else {
      super.writeValue(buffer, value);
    }
  }

  @override
  Object? readValueOfType(int type, ReadBuffer buffer) {
    switch (type) {
      case 128:
        return Everything.decode(readValue(buffer)!);

      default:
        return super.readValueOfType(type, buffer);
    }
  }
}

abstract class FlutterEverything {
  static const MessageCodec<Object?> codec = _FlutterEverythingCodec();

  Everything giveMeEverything();
  Everything echo(Everything everything);
  static void setup(FlutterEverything? api,
      {BinaryMessenger? binaryMessenger}) {
    {
      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
          'dev.flutter.pigeon.FlutterEverything.giveMeEverything', codec,
          binaryMessenger: binaryMessenger);
      if (api == null) {
        channel.setMessageHandler(null);
      } else {
        channel.setMessageHandler((Object? message) async {
          // ignore message
          final Everything output = api.giveMeEverything();
          return output;
        });
      }
    }
    {
      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
          'dev.flutter.pigeon.FlutterEverything.echo', codec,
          binaryMessenger: binaryMessenger);
      if (api == null) {
        channel.setMessageHandler(null);
      } else {
        channel.setMessageHandler((Object? message) async {
          assert(message != null,
              'Argument for dev.flutter.pigeon.FlutterEverything.echo was null.');
          final List<Object?> args = (message as List<Object?>?)!;
          final Everything? arg_everything = (args[0] as Everything?);
          assert(arg_everything != null,
              'Argument for dev.flutter.pigeon.FlutterEverything.echo was null, expected non-null Everything.');
          final Everything output = api.echo(arg_everything!);
          return output;
        });
      }
    }
  }
}
