namespace grpc_binder {

class WireReaderImpl : public WireReader {
 public:
  explicit WireReaderImpl(TransportStreamReceiver* transport_stream_receiver,
                          bool is_client);
  ~WireReaderImpl() override;

  // Setup the transport between endpoint binders.
  //
  // The client and the server both call SetupTransport() when constructing
  // transport.
  //
  // High-level overview of transaction setup:
  // 0. Client obtain an |endpoint_binder| from the server.
  // 1. Client creates a binder |client_binder| and hook its on-transaction
  // callback to client's ProcessTransaction(). Client then sends
  // |client_binder| through |endpoint_binder| to server.
  // 2. Server receives |client_binder| via |endpoint_binder|.
  // 3. Server creates a binder |server_binder| and hook its on-transaction
  // callback to server's ProcessTransaction(). Server then sends
  // |server_binder| through |client_binder| back to the client.
  // 4. Client receives |server_binder| via |client_binder|'s on-transaction
  // callback.
  std::unique_ptr<WireWriter> SetupTransport(
      std::unique_ptr<Binder> endpoint_binder) override;

  absl::Status ProcessTransaction(transaction_code_t code,
                                  const ReadableParcel* parcel);

 private:
  void SendSetupTransport(Binder* binder);
  void RecvSetupTransport();
  absl::Status ProcessStreamingTransaction(transaction_code_t code,
                                           const ReadableParcel* parcel);

  TransportStreamReceiver* transport_stream_receiver_;
  absl::Notification connection_noti_;
  std::unique_ptr<Binder> other_end_binder_;
  absl::flat_hash_map<transaction_code_t, int32_t> expected_seq_num_;
  std::unique_ptr<TransactionReceiver> tx_receiver_;
  bool is_client_;
};

}  // namespace grpc_binder

#endif  // GRPC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_IMPL_H
