/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed 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 BOOST_COROUTINES_NO_DEPRECATION_WARNING
// users should define this if they directly include boost/asio/spawn.hpp,
// but by defining it here, warnings won't cause problems with a compile
#define BOOST_COROUTINES_NO_DEPRECATION_WARNING
#endif

#include <boost/asio/async_result.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/callable_traits.hpp>
#include <sdbusplus/asio/detail/async_send_handler.hpp>
#include <sdbusplus/message.hpp>
#include <sdbusplus/utility/read_into_tuple.hpp>
#include <sdbusplus/utility/type_traits.hpp>

#include <chrono>
#include <string>
#include <tuple>

namespace sdbusplus
{

namespace asio
{

/// Root D-Bus IO object
/**
 * A connection to a bus, through which messages may be sent or received.
 */
class connection : public sdbusplus::bus::bus
{
  public:
    // default to system bus
    connection(boost::asio::io_context& io) :
        sdbusplus::bus::bus(sdbusplus::bus::new_default()), io_(io), socket(io_)
    {
        socket.assign(get_fd());
        read_wait();
    }
    connection(boost::asio::io_context& io, sd_bus* bus) :
        sdbusplus::bus::bus(bus), io_(io), socket(io_)
    {
        socket.assign(get_fd());
        read_wait();
    }
    ~connection()
    {
        // The FD will be closed by the socket object, so assign null to the
        // sd_bus object to avoid a double close()  Ignore return codes here,
        // because there's nothing we can do about errors
        socket.release();
    }

    /** @brief Perform an asynchronous send of a message, executing the handler
     *         upon return and return
     *
     *  @param[in] m - A message ready to send
     *  @param[in] handler - handler to execute upon completion; this may be an
     *                       asio::yield_context to execute asynchronously as a
     *                       coroutine
     *
     *  @return If a yield context is passed as the handler, the return type is
     *          a message. If a function object is passed in as the handler,
     *          the return type is the result of the handler registration,
     *          while the resulting message will get passed into the handler.
     */
    template <typename MessageHandler>
    inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
                                         void(boost::system::error_code,
                                              message::message&))
        async_send(message::message& m, MessageHandler&& handler,
                   uint64_t timeout = 0)
    {
        boost::asio::async_completion<
            MessageHandler, void(boost::system::error_code, message::message)>
            init(handler);
        detail::async_send_handler<typename boost::asio::async_result<
            MessageHandler, void(boost::system::error_code,
                                 message::message)>::completion_handler_type>(
            std::move(init.completion_handler))(get(), m, timeout);
        return init.result.get();
    }

    /** @brief Perform an asynchronous method call, with input parameter packing
     *         and return value unpacking.
     *
     *  @param[in] handler - A function object that is to be called as a
     *                       continuation for the async dbus method call. The
     *                       arguments to parse on the return are deduced from
     *                       the handler's signature and then passed in along
     *                       with an error code and optional message::message
     *  @param[in] service - The service to call.
     *  @param[in] objpath - The object's path for the call.
     *  @param[in] interf - The object's interface to call.
     *  @param[in] method - The object's method to call.
     *  @param[in] timeout - The timeout for the method call in usec (0 results
     *                       in using the default value).
     *  @param[in] a... - Optional parameters for the method call.
     *
     *  @return immediate return of the internal handler registration. The
     *          result of the actual asynchronous call will get unpacked from
     *          the message and passed into the handler when the call is
     *          complete.
     */
    template <typename MessageHandler, typename... InputArgs>
    void async_method_call_timed(MessageHandler&& handler,
                                 const std::string& service,
                                 const std::string& objpath,
                                 const std::string& interf,
                                 const std::string& method, uint64_t timeout,
                                 const InputArgs&... a)
    {
        using FunctionTuple = boost::callable_traits::args_t<MessageHandler>;
        using FunctionTupleType =
            typename utility::decay_tuple<FunctionTuple>::type;
        constexpr bool returnWithMsg = []() {
            if constexpr (std::tuple_size_v<FunctionTupleType> > 1)
            {
                return std::is_same_v<
                    std::tuple_element_t<1, FunctionTupleType>,
                    sdbusplus::message::message>;
            }
            return false;
        }();
        using UnpackType =
            typename utility::strip_first_n_args<returnWithMsg ? 2 : 1,
                                                 FunctionTupleType>::type;
        auto applyHandler = [handler = std::forward<MessageHandler>(handler)](
                                boost::system::error_code ec,
                                message::message& r) mutable {
            UnpackType responseData;
            if (!ec)
            {
                try
                {
                    utility::read_into_tuple(responseData, r);
                }
                catch (const std::exception& e)
                {
                    // Set error code if not already set
                    ec = boost::system::errc::make_error_code(
                        boost::system::errc::invalid_argument);
                }
            }
            // Note.  Callback is called whether or not the unpack was
            // successful to allow the user to implement their own handling
            if constexpr (returnWithMsg)
            {
                auto response = std::tuple_cat(std::make_tuple(ec),
                                               std::forward_as_tuple(r),
                                               std::move(responseData));
                std::apply(handler, response);
            }
            else
            {
                auto response = std::tuple_cat(std::make_tuple(ec),
                                               std::move(responseData));
                std::apply(handler, response);
            }
        };
        message::message m;
        boost::system::error_code ec;
        try
        {
            m = new_method_call(service.c_str(), objpath.c_str(),
                                interf.c_str(), method.c_str());
            m.append(a...);
        }
        catch (const exception::SdBusError& e)
        {
            ec = boost::system::errc::make_error_code(
                static_cast<boost::system::errc::errc_t>(e.get_errno()));
            applyHandler(ec, m);
            return;
        }
        async_send(m, std::forward<decltype(applyHandler)>(applyHandler),
                   timeout);
    }

    /** @brief Perform an asynchronous method call, with input parameter packing
     *         and return value unpacking. Uses the default timeout value.
     *
     *  @param[in] handler - A function object that is to be called as a
     *                       continuation for the async dbus method call. The
     *                       arguments to parse on the return are deduced from
     *                       the handler's signature and then passed in along
     *                       with an error code and optional message::message
     *  @param[in] service - The service to call.
     *  @param[in] objpath - The object's path for the call.
     *  @param[in] interf - The object's interface to call.
     *  @param[in] method - The object's method to call.
     *  @param[in] a... - Optional parameters for the method call.
     *
     *  @return immediate return of the internal handler registration. The
     *          result of the actual asynchronous call will get unpacked from
     *          the message and passed into the handler when the call is
     *          complete.
     */
    template <typename MessageHandler, typename... InputArgs>
    void async_method_call(MessageHandler&& handler, const std::string& service,
                           const std::string& objpath,
                           const std::string& interf, const std::string& method,
                           const InputArgs&... a)
    {
        async_method_call_timed(std::forward<MessageHandler>(handler), service,
                                objpath, interf, method, 0, a...);
    }

    /** @brief Perform a yielding asynchronous method call, with input
     *         parameter packing and return value unpacking
     *
     *  @param[in] yield - A yield context to async block upon.
     *  @param[in] ec - an error code that will be set for any errors
     *  @param[in] service - The service to call.
     *  @param[in] objpath - The object's path for the call.
     *  @param[in] interf - The object's interface to call.
     *  @param[in] method - The object's method to call.
     *  @param[in] a... - Optional parameters for the method call.
     *
     *  @return Unpacked value of RetType
     */
    template <typename... RetTypes, typename... InputArgs>
    auto yield_method_call(boost::asio::yield_context yield,
                           boost::system::error_code& ec,
                           const std::string& service,
                           const std::string& objpath,
                           const std::string& interf, const std::string& method,
                           const InputArgs&... a)
    {
        message::message m;
        try
        {
            m = new_method_call(service.c_str(), objpath.c_str(),
                                interf.c_str(), method.c_str());
            m.append(a...);
        }
        catch (const exception::SdBusError& e)
        {
            ec = boost::system::errc::make_error_code(
                static_cast<boost::system::errc::errc_t>(e.get_errno()));
        }
        message::message r;
        if (!ec)
        {
            r = async_send(m, yield[ec]);
        }
        if constexpr (sizeof...(RetTypes) == 0)
        {
            // void return
            return;
        }
        else if constexpr (sizeof...(RetTypes) == 1)
        {
            if constexpr (std::is_same<utility::first_type<RetTypes...>,
                                       void>::value)
            {
                return;
            }
            else
            {
                // single item return
                utility::first_type<RetTypes...> responseData{};
                // before attempting to read, check ec and bail on error
                if (ec)
                {
                    return responseData;
                }
                try
                {
                    r.read(responseData);
                }
                catch (const std::exception& e)
                {
                    ec = boost::system::errc::make_error_code(
                        boost::system::errc::invalid_argument);
                    // responseData will be default-constructed...
                }
                return responseData;
            }
        }
        else
        {
            // tuple of things to return
            std::tuple<RetTypes...> responseData{};
            // before attempting to read, check ec and bail on error
            if (ec)
            {
                return responseData;
            }
            try
            {
                r.read(responseData);
            }
            catch (const std::exception& e)
            {
                ec = boost::system::errc::make_error_code(
                    boost::system::errc::invalid_argument);
                // responseData will be default-constructed...
            }
            return responseData;
        }
    }

    boost::asio::io_context& get_io_context()
    {
        return io_;
    }

  private:
    boost::asio::io_context& io_;
    boost::asio::posix::stream_descriptor socket;

    void read_wait()
    {
        socket.async_read_some(
            boost::asio::null_buffers(),
            [&](const boost::system::error_code& /*ec*/, std::size_t) {
                if (process_discard())
                {
                    read_immediate();
                }
                else
                {
                    read_wait();
                }
            });
    }
    void read_immediate()
    {
        boost::asio::post(io_, [&] {
            if (process_discard())
            {
                read_immediate();
            }
            else
            {
                read_wait();
            }
        });
    }
};

} // namespace asio

} // namespace sdbusplus
