#include "socket_sender.h"

#include <saas/protos/reply.pb.h>
#include <saas/protos/rtyserver.pb.h>
#include <saas/library/socket_adapter/socket_adapter_factory.h>
#include <saas/util/logging/exception_process.h>

#include <library/cpp/digest/md5/md5.h>
#include <library/cpp/neh/stat.h>

namespace NRTYServer {

    bool TSocketSender::Connect() {
        TRY
            Stop();
            Socket.Reset(new TSocket(TNetworkAddress(Host, Port), Timeout));
            SocketInput.Reset(new TSocketInput(*Socket));
            SocketOutputSlave.Reset(new TSocketOutput(*Socket));
            if (InterByteTimeout.MilliSeconds())
                SocketOutput = new TSlowOutputStream(*SocketOutputSlave, InterByteTimeout);
            else
                SocketOutput = SocketOutputSlave.Release();
            Adapter = TAdapterFactory::GetAdapterByType(ProtocolType, *SocketInput, *SocketOutput, AdapterToken);
        return true;
        CATCH("")
        return false;
    }

    TSocketSender::TSocketSender(const TString& host, const ui16 port, TDuration timeout, TDuration interByteTimeout, const TString& protocolType, const TString& service)
    {
        Host = host;
        Port = port;
        Timeout = timeout;
        InterByteTimeout = interByteTimeout;
        ProtocolType = protocolType;
        if (protocolType.StartsWith("proto2http"))
            AdapterToken = service + " ";
        else if (protocolType.StartsWith("proto2json_ref"))
            AdapterToken = service + " json_ref";
        else if (protocolType.StartsWith("proto2json"))
            AdapterToken = service + " common_json";
        if (!!AdapterToken)
            AdapterToken = MD5::Calc(AdapterToken);
    }

    void TSocketSender::Stop() {
        Adapter.Reset(nullptr);
        SocketOutput.Reset(nullptr);
        SocketOutputSlave.Reset(nullptr);
        SocketInput.Reset(nullptr);
        Socket.Reset(nullptr);
    }

    NRTYServer::IContext::TPtr TSocketSender::Send(const NRTYServer::TMessage& message, const TString& request) const {
        Adapter->WriteMessage(message, request);
        return new TSocketContext(message);
    }

    NRTYServer::IContext::TPtr TSocketSender::Send(const TString& message, const TString& request) const {
        Adapter->WriteMessage(message, request);
        return new TInfoContext(request, 1);
    }

    bool TSocketSender::Recv(NRTYServer::IContext::TPtr /* context */, NRTYServer::TReply& reply, TDuration /*timeout*/) const {
        return Adapter->ReadMessage(reply);
    }

    TSocketSender::~TSocketSender() {
        Stop();
    }
}
