#include "pch.h"
#include "IpHelper.h"
#include <IPTypes.h> 
#include <IPHlpApi.h>

#pragma comment(lib,"Iphlpapi.lib")
#pragma comment (lib,"ws2_32.lib") //加载 ws2_32.dll

std::vector<std::wstring> CAdapterList::gExcludedList;

//枚举网卡列表
//void CAdapterList::Enum(bool excludelist,  bool includelocalhost)
//{
//    //得到结构体大小
//    unsigned long stSize = 0;
//    int nRel = GetAdaptersInfo(0, &stSize);
//
//    //PIP_ADAPTER_INFO结构体指针存储本机网卡信息
//    PIP_ADAPTER_INFO allIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
//    // 指向第一条
//    PIP_ADAPTER_INFO pIpAdapterInfo = allIpAdapterInfo;
//
//    nRel = GetAdaptersInfo(allIpAdapterInfo, &stSize);
//
//    if (ERROR_SUCCESS == nRel)
//    {
//        //输出网卡信息
//         //可能有多网卡,因此通过循环去判断
//        while (pIpAdapterInfo)
//        {
//            sAdapter s(pIpAdapterInfo->AdapterName, pIpAdapterInfo->Description);
//            bool skip = false;
//            if(excludelist) {
//                for (auto& e : Excluded) {
//                    if (s.Description._Starts_with(e)) {
//                        skip = true;
//                        break;
//                    }
//                }
//            }
//            
//            if (!skip) {
//                d.push_back(s);
//                auto last = d.rbegin();
//                //可能网卡有多IP,因此通过循环去判断
//                IP_ADDR_STRING* pIpAddrString = &(pIpAdapterInfo->IpAddressList);
//                do
//                {
//                    last->IpAddr.push_back({ pIpAddrString->IpAddress.String, pIpAddrString->IpMask.String });
//                    pIpAddrString = pIpAddrString->Next;
//                } while (pIpAddrString);
//                
//            }
//            pIpAdapterInfo = pIpAdapterInfo->Next;
//        }
//    }
//    if (includelocalhost) {
//        d.push_back({ "", "localhost" });
//		auto last = d.rbegin();
//		last->IpAddr.push_back({ "127.0.0.1", "255.255.255.0" });
//    }
//    
//
//    //释放内存空间
//
//    delete[] allIpAdapterInfo;
//}


void CAdapterList::Enum(uint32_t exclude_flag)
{
	d.clear();

	std::vector<std::wstring> localExcluedList;
	if(exclude_flag) _SetExcludedList(localExcluedList, exclude_flag);

	DWORD dwRetVal = 0;

	LPVOID lpMsgBuf = NULL;

	PIP_ADAPTER_ADDRESSES pAddresses = NULL;
	ULONG outBufLen = 16384; // Allocate a 16 KB buffer to start with，不够可以递增
	ULONG Iterations = 0;	// 递增次数

	PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
	PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;

	do {
		pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
		if (pAddresses == NULL) {
			//printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
			return;
		}
		/* Set to AF_INET to specify the IPv4 address family */
		// 不要返回 IPv6 任何广播地址。不要返回多播地址。
		dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, NULL, pAddresses, &outBufLen);

		if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
			free(pAddresses);
			pAddresses = NULL;
			Iterations++;
			outBufLen += 16384;//增加缓冲区
		}else {
			break;
		}
	} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 3));

	if (dwRetVal == NO_ERROR) {
		pCurrAddresses = pAddresses;
		while (pCurrAddresses) {
			pUnicast = pCurrAddresses->FirstUnicastAddress;
			if (pUnicast != NULL) {
				bool skip = false;

				std::wstring desc(pCurrAddresses->Description);
				// 比对全局排除列表
				for (auto& e : gExcludedList) {
					if (desc._Starts_with(e)) { skip = true; break; }
				}
				// 比对标志位添加的排除列表
				if (!skip && exclude_flag) {
					for (auto& e : localExcluedList) {
						if (desc._Starts_with(e)) { skip = true; break; }
					}
				}

				if (!skip) {
					sAdapter s;
					s.Description = pCurrAddresses->Description;
					s.FriendlyName = pCurrAddresses->FriendlyName;
					s.OperStatus = pCurrAddresses->OperStatus;

					//printf("%d, %S\n", s.OperStatus, pCurrAddresses->FriendlyName);

					while (pUnicast != NULL) {
						if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) {//限制IPV4
							ipv4addr addr(pUnicast->Address.lpSockaddr);
							// 保留最后一个ip
							// 如果网卡设置了固定IP但未连接，会出现两个ip，第一个是169.254.x.x，第2个才是设置的ip
							s.IpAddr=addr;
							//printf("\tIPv4 Address: %s\n", addr.ipStr().c_str());
						}
						pUnicast = pUnicast->Next;
					}
					d.push_back(s);
				}
			}
			else {
				//printf("\tNo unicast addresses found for this adapter\n");
			}

			pCurrAddresses = pCurrAddresses->Next;
		}
	}
	//else {
	//	printf("Call to GetAdaptersAddresses failed with error: %d\n", dwRetVal);
	//	if (dwRetVal == ERROR_NO_DATA) {
	//		printf("\tNo addresses were found for the requested parameters\n");
	//	}
	//	else {
	//		if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
	//			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
	//			NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
	//			// Default language
	//			(char*)&lpMsgBuf, 0, NULL)) {
	//			printf("\tError: %s", (char*)lpMsgBuf);
	//			LocalFree(lpMsgBuf);
	//		}
	//	}
	//}

	if (pAddresses) {
		free(pAddresses);
	}

}


// 要求已经执行过WSAStartup(MAKEWORD(2, 2), &wsaData);
int getIPFromHostname(const char* hostname, std::vector<ipv4addr>& foundIp) 
{
	struct addrinfo* result_list = NULL;
	struct addrinfo hints = {};
	hints.ai_family = AF_INET; // IPv4
	hints.ai_socktype = SOCK_STREAM;

	int result = getaddrinfo(hostname, nullptr, &hints, &result_list);
	if (result != 0) {
		//std::cerr << "getaddrinfo failed: " << gai_strerror(result) << std::endl;
		//WSACleanup();
		return -1;
	}

	for (struct addrinfo* res = result_list; res != NULL; res = res->ai_next) {
		struct sockaddr_in* ip4 = (struct sockaddr_in*)res->ai_addr;
		ipv4addr addr(ip4);
		foundIp.push_back(addr);
	}

	freeaddrinfo(result_list);
	return int(foundIp.size());
}
