/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#ifndef GEODE_TCPCONN_H_
#define GEODE_TCPCONN_H_

#include <boost/asio.hpp>
#include <boost/optional.hpp>

#include <geode/internal/geode_globals.hpp>

#include "Connector.hpp"

namespace apache {
namespace geode {
namespace client {
class TcpConn : public Connector {
  size_t receive(char*, size_t, std::chrono::milliseconds) override;
  size_t receive_nothrowiftimeout(char*, size_t,
                                  std::chrono::milliseconds) override;
  size_t send(const char*, size_t, std::chrono::milliseconds) override;

  uint16_t getPort() override final;

  std::string getRemoteEndpoint() override final;

 protected:
  boost::asio::io_context io_context_;
  boost::asio::ip::tcp::socket socket_;

  boost::asio::ip::tcp::resolver::results_type resolve(
      const std::string hostname, uint16_t port);

  void connect(boost::asio::ip::tcp::resolver::results_type r,
               std::chrono::microseconds connect_timeout);

  size_t receive(char*, size_t, std::chrono::milliseconds,
                 bool throwTimeoutException);

  virtual void prepareAsyncRead(
      char* buff, size_t len,
      boost::optional<boost::system::error_code>& read_result,
      std::size_t& bytes_read);

  virtual void prepareAsyncWrite(
      const char* buff, size_t len,
      boost::optional<boost::system::error_code>& write_result,
      std::size_t& bytes_written);

 public:
  TcpConn(const std::string ipaddr, std::chrono::microseconds connect_timeout,
          int32_t maxBuffSizePool);

  TcpConn(const std::string hostname, uint16_t port,
          std::chrono::microseconds connect_timeout, int32_t maxBuffSizePool);

  TcpConn(const std::string ipaddr, std::chrono::microseconds connect_timeout,
          int32_t maxBuffSizePool, std::chrono::microseconds send_timeout,
          std::chrono::microseconds receive_timeout);

  ~TcpConn() override;
};

}  // namespace client
}  // namespace geode
}  // namespace apache

#endif  // GEODE_TCPCONN_H_
