#include "td/network/Socket.h"

#include "td/network/IPAddress.h"
#include "td/network/Network.h"

#ifdef _WIN32
#define ioctl ioctlsocket
#endif

#include <iostream>

namespace td {
namespace network {

Socket::Socket(Type type)
	: m_Blocking(false),
	m_Type(type),
	m_Status(Disconnected),
	m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)) {

}

Socket::~Socket() {
	Disconnect();
}

bool Socket::SetBlocking(bool block) {
	unsigned long mode = block ? 0 : 1;

	if (ioctl(m_Handle, FIONBIO, &mode) < 0) {
		return false;
	}

	m_Blocking = block;

	return true;
}

bool Socket::IsBlocking() const noexcept {
	return m_Blocking;
}

Socket::Type Socket::GetType() const noexcept {
	return m_Type;
}

SocketHandle Socket::GetHandle() const noexcept {
	return m_Handle;
}

void Socket::SetStatus(Socket::Status status) {
	m_Status = status;
}

Socket::Status Socket::GetStatus() const noexcept {
	return m_Status;
}

bool Socket::Connect(const std::string& ip, uint16_t port) {
	IPAddress addr(ip);
	return Connect(addr, port);
}

std::size_t Socket::Send(const std::string& data) {
	return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
}

std::size_t Socket::Send(DataBuffer& buffer) {
	std::string data = buffer.ToString();
	return this->Send(reinterpret_cast<const unsigned char*>(data.c_str()), data.length());
}

void Socket::Disconnect() {
	if (m_Handle < 0)
		closesocket(m_Handle);
	m_Status = Disconnected;
}

} // ns network
} // ns mc
