#include "iphelper.h"

#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

#include <QString>
#include <QDebug>
#include <QNetworkInterface>

namespace Win
{

QList<AdapterInfo> GetEthernetAddress()
{
    QList<AdapterInfo> adapters;
    std::list<std::wstring> addressList;

    PIP_ADAPTER_INFO pAdapterInfo = NULL;
    PIP_ADAPTER_INFO pAdapter = NULL;
    DWORD dwRetVal = 0;
//    UINT i = 0;

    /* variables used to print DHCP time info */
//    struct tm newtime;
//    char buffer[32];
    char macAddress[32] = {0};
//    errno_t error;

    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof(IP_ADAPTER_INFO));
    if (pAdapterInfo == NULL) {
        printf("Error allocating memory needed to call GetAdaptersinfo\n");
        return adapters;
    }

    // Make an initial call to GetAdaptersInfo to get
    // the necessary size into the ulOutBufLen variable
    if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
        FREE(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(ulOutBufLen);
        if (pAdapterInfo == NULL) {
            printf("Error allocating memory needed to call GetAdaptersinfo\n");
            return adapters;
        }
    }

    if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
        pAdapter = pAdapterInfo;
        while (pAdapter) {
//            printf("\tComboIndex: \t%d\n", pAdapter->ComboIndex);
            QString adapterName = QString::fromLocal8Bit(pAdapter->AdapterName);
            qDebug() << "Adapter Name:" << adapterName;
            QString description = QString::fromLocal8Bit(pAdapter->Description);
            qDebug() << "Adapter Desc:" << description;
//            printf("\tAdapter Addr: \t");
//            for (i = 0; i < pAdapter->AddressLength; i++) {
//                if (i == (pAdapter->AddressLength - 1)) {
//                    printf("%.2x\n", (int) pAdapter->Address[i]);
//                } else {
//                    printf("%.2x-", (int) pAdapter->Address[i]);
//                }
//            }
//            printf("\tIndex: \t%d\n", pAdapter->Index);
//            printf("\tType: \t");

            sprintf(macAddress, "%02x:%02x:%02x:%02x:%02x:%02x",
                    pAdapter->Address[0], pAdapter->Address[1],
                    pAdapter->Address[2], pAdapter->Address[3],
                    pAdapter->Address[4], pAdapter->Address[5]);

            addressList.push_back(QString(macAddress).toStdWString());
            qDebug() << "Adapter Addr:" << macAddress;
            qDebug() << "IP Address:" << pAdapter->IpAddressList.IpAddress.String;
            AdapterInfo info;

            // WARING: server need this flag
            info.flags = QNetworkInterface::CanMulticast;

            info.hardwareAddress = macAddress;
            info.name = pAdapter->AdapterName;
            info.description = pAdapter->Description;
            info.addressList =  QStringList() << QString(pAdapter->IpAddressList.IpAddress.String);
            adapters.push_back(info);

//            switch (pAdapter->Type) {
//            case MIB_IF_TYPE_OTHER:
//                printf("Other\n");
//                break;
//            case MIB_IF_TYPE_ETHERNET:
//                printf("Ethernet\n");
//                break;
//            case MIB_IF_TYPE_TOKENRING:
//                printf("Token Ring\n");
//                break;
//            case MIB_IF_TYPE_FDDI:
//                printf("FDDI\n");
//                break;
//            case MIB_IF_TYPE_PPP:
//                printf("PPP\n");
//                break;
//            case MIB_IF_TYPE_LOOPBACK:
//                printf("Lookback\n");
//                break;
//            case MIB_IF_TYPE_SLIP:
//                printf("Slip\n");
//                break;
//            default:
//                printf("Unknown type %ld\n", pAdapter->Type);
//                break;
//            }

//            printf("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);

//            printf("\tGateway: \t%s\n", pAdapter->GatewayList.IpAddress.String);
//            printf("\t***\n");

//            if (pAdapter->DhcpEnabled) {
//                printf("\tDHCP Enabled: Yes\n");
//                printf("\t  DHCP Server: \t%s\n",
//                       pAdapter->DhcpServer.IpAddress.String);

//                printf("\t  Lease Obtained: ");
//                /* Display local time */
//                error = _localtime32_s(&newtime, (__time32_t *) &pAdapter->LeaseObtained);
//                if (error) {
//                    printf("Invalid Argument to _localtime32_s\n");
//                } else {
//                    // Convert to an ASCII representation
//                    error = asctime_s(buffer, 32, &newtime);
//                    if (error) {
//                        printf("Invalid Argument to asctime_s\n");
//                    } else
//                        /* asctime_s returns the string terminated by \n\0 */
//                    {
//                        printf("%s", buffer);
//                    }
//                }

//                printf("\t  Lease Expires:  ");
//                error = _localtime32_s(&newtime, (__time32_t *) &pAdapter->LeaseExpires);
//                if (error) {
//                    printf("Invalid Argument to _localtime32_s\n");
//                } else {
//                    // Convert to an ASCII representation
//                    error = asctime_s(buffer, 32, &newtime);
//                    if (error) {
//                        printf("Invalid Argument to asctime_s\n");
//                    } else
//                        /* asctime_s returns the string terminated by \n\0 */
//                    {
//                        printf("%s", buffer);
//                    }
//                }
//            } else {
//                printf("\tDHCP Enabled: No\n");
//            }

//            if (pAdapter->HaveWins) {
//                printf("\tHave Wins: Yes\n");
//                printf("\t  Primary Wins Server:    %s\n",
//                       pAdapter->PrimaryWinsServer.IpAddress.String);
//                printf("\t  Secondary Wins Server:  %s\n",
//                       pAdapter->SecondaryWinsServer.IpAddress.String);
//            } else {
//                printf("\tHave Wins: No\n");
//            }
            pAdapter = pAdapter->Next;
//            printf("\n");
        }
    } else {
        printf("GetAdaptersInfo failed with error: %ld\n", dwRetVal);
    }
    if (pAdapterInfo) {
        FREE(pAdapterInfo);
    }

    return adapters;
}

}
