/*
 * Copyright (c) 1994, 2021 Alex Leigh, All Rights Reserved
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 *
 * Disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */

#pragma comment(lib, "Ws2_32.lib")

#include <winsock2.h>
#include <windows.h>
#include <Ws2tcpip.h>

#include <stdio.h>
#include <mecha.h>
#include "net_win.h"

static int ws2_write(struct mSnet_con *con, const void *buf, size_t len, size_t *wrote_len);

static int ws2_read(struct mSnet_con *con, void *buf, size_t len, size_t *read_len);

static void ws2_close(struct mSnet_con *con);

static struct mSnet_pt pt = {ws2_close, &ws2_write, &ws2_read};

int mFnet_sock_init() {
    WSADATA wsaData;

    if (WSAStartup(0x202, &wsaData) != 0) {
        return MECHA_ERR;
    }

    return MECHA_OK;
}

static int ws2_write(struct mSnet_con *con, const void *buf, size_t len, size_t *wrote_len) {
    int ret = send(con->ud.wsock, buf, len, 0);
    if (ret < 0) return MECHA_ERR;
    *wrote_len = ret;
    return MECHA_OK;
}

static int ws2_read(struct mSnet_con *con, void *buf, size_t len, size_t *read_len) {
    int ret = recv(con->ud.wsock, buf, len, 0);
    if (ret < 0) return MECHA_ERR;
    *read_len = ret;
    return MECHA_OK;
}

void ws2_close(struct mSnet_con *con) {
    shutdown(con->ud.wsock, SD_BOTH);
    closesocket(con->ud.wsock);
}


int mFnet_sock_connect(struct mSnet_con *con, const struct mSurl *url) {
    int ret;
    struct addrinfo *result = NULL, *ptr = NULL, hints;
    memset(&hints, 0, sizeof(hints)); // <-- MOVED HERE!!!
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    char portbuf[8];

    if (snprintf(portbuf, 8, "%d", url->port) < 0) {
        return MECHA_ERR;
    };

    ret = getaddrinfo(url->host, portbuf, &hints, &result);
    if (ret != 0) return MECHA_ERR;

    con->ud.wsock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (con->ud.wsock == INVALID_SOCKET) {
        freeaddrinfo(result);
        return MECHA_ERR;
    }

    ret = connect(con->ud.wsock, result->ai_addr, (int) result->ai_addrlen);
    if (ret == 0) {
        con->pt = &pt;
        return MECHA_OK;
    }

    closesocket(con->ud.wsock);
    con->ud.wsock = INVALID_SOCKET;

    return MECHA_ERR;
}