/*
 * 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.
 */

#include <log4cxx/private/aprsocket.h>
#include <log4cxx/private/socket_priv.h>
#include <log4cxx/helpers/bytebuffer.h>
#include <log4cxx/helpers/transcoder.h>

#include "apr_network_io.h"
#include "apr_signal.h"

namespace LOG4CXX_NS
{
namespace helpers
{

struct APRSocket::APRSocketPriv : public Socket::SocketPrivate {
	APRSocketPriv(const InetAddressPtr& address, int port)
		: Socket::SocketPrivate(address, port)
		, socket(nullptr)
	{}

	APRSocketPriv(apr_socket_t* sock, apr_pool_t* p) :
		pool(p, true),
		socket(sock)
	{}

	Pool pool;
	apr_socket_t* socket{ NULL };
	bool connected{ false };
};

#define _priv static_cast<APRSocketPriv*>(m_priv.get())

APRSocket::APRSocket(const InetAddressPtr& address, int port)
	: Socket(std::make_unique<APRSocketPriv>(address, port))
{
	apr_status_t status =
		apr_socket_create(&_priv->socket, APR_INET, SOCK_STREAM,
			APR_PROTO_TCP, _priv->pool.getAPRPool());

	if (status != APR_SUCCESS)
	{
		throw SocketException(status);
	}
	open();
}

void APRSocket::open()
{
	LOG4CXX_ENCODE_CHAR(host, _priv->address->getHostAddress());

	// create socket address (including port)
	apr_sockaddr_t* client_addr;
	apr_status_t status = apr_sockaddr_info_get
		( &client_addr
		, host.c_str()
		, APR_INET
		, _priv->port
		, 0
		, _priv->pool.getAPRPool()
		);

	if (status != APR_SUCCESS)
	{
		throw ConnectException(status);
	}

	// connect the socket
	status =  apr_socket_connect(_priv->socket, client_addr);

	if (status != APR_SUCCESS)
	{
		throw ConnectException(status);
	}
	_priv->connected = true;
}

// Is the socket available for use?
bool APRSocket::is_open()
{
	return _priv->socket && _priv->connected;
}

APRSocket::APRSocket(apr_socket_t* s, apr_pool_t* pool) :
	Socket(std::make_unique<APRSocketPriv>(s, pool)){
	apr_sockaddr_t* sa;
	apr_status_t status = apr_socket_addr_get(&sa, APR_REMOTE, s);

	if (status == APR_SUCCESS)
	{
		_priv->port = sa->port;
		LogString remotename;
		LogString remoteip;

		if (sa->hostname != NULL)
		{
			Transcoder::decode(sa->hostname, remotename);
		}

		char* buf = 0;
		status = apr_sockaddr_ip_get(&buf, sa);

		if (status == APR_SUCCESS)
		{
			Transcoder::decode(buf, remoteip);
		}

		_priv->address = std::make_shared<InetAddress>(remotename, remoteip);
	}
}

size_t APRSocket::write(ByteBuffer& buf)
{
	if (_priv->socket == 0)
	{
		throw ClosedChannelException();
	}

	size_t totalWritten = 0;

	while (buf.remaining() > 0)
	{
		apr_size_t written = buf.remaining();

		// while writing to the socket, we need to ignore the SIGPIPE
		// signal. Otherwise, when the client has closed the connection,
		// the send() function would not return an error but call the
		// SIGPIPE handler.
#if APR_HAVE_SIGACTION
		apr_sigfunc_t* old = apr_signal(SIGPIPE, SIG_IGN);
		apr_status_t status = apr_socket_send(_priv->socket, buf.current(), &written);
		apr_signal(SIGPIPE, old);
#else
		apr_status_t status = apr_socket_send(_priv->socket, buf.current(), &written);
#endif

		buf.increment_position(written);
		totalWritten += written;

		if (status != APR_SUCCESS)
		{
			throw SocketException(status);
		}
	}

	return totalWritten;
}

void APRSocket::setNonBlocking(bool newValue)
{
	auto status = apr_socket_opt_set(_priv->socket, APR_SO_NONBLOCK, newValue);
	if (status != APR_SUCCESS)
		throw SocketException(status);
}

void APRSocket::close()
{
	if (_priv->socket != 0)
	{
		apr_status_t status = apr_socket_close(_priv->socket);

		if (status != APR_SUCCESS)
		{
			throw SocketException(status);
		}

		_priv->socket = 0;
	}
}

apr_socket_t* APRSocket::getSocketPtr() const
{
	return _priv->socket;
}

} //namespace helpers
} //namespace log4cxx
