/*
 *  
 *  $Id: aetwildcards.cpp $
 *  Ginkgo CADx Project
 *
 *  Copyright 2008-12 MetaEmotion S.L. All rights reserved.
 *  http://ginkgo-cadx.com
 *
 *  This file is licensed under LGPL v3 license.
 *  See License.txt for details
 *
 */
#include "aetwildcards.h"
#include <string.h>
#include <sstream>
#include <iostream>
#include <iomanip>
#if defined(_WINDOWS)
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif


std::string GNC::GCS::AETWildcards::Parse(const std::string& AET)
{
	std::string realAET = AET;
	std::string ip4[4];

	if ( (AET.find("%IP") != std::string::npos) || (AET.find("%HOSTNAME") != std::string::npos))  {
		char bufHostName[256];
		char bufIP4[16];
#if defined(_WINDOWS)
		WSADATA wsaData;
		WSAStartup(MAKEWORD( 2, 2 ), &wsaData);

		unsigned long error = 0;
#else
		int ret = 0;
#endif

		memset(bufHostName, 0, 256 * sizeof(char));

#if defined(_WINDOWS)
		if ( gethostname(bufHostName, 256) != 0)
		{
			error = WSAGetLastError();
			std::cout << "gethostname() Error: " << error << std::endl;
		}
#else
		if ( (ret = gethostname(bufHostName, 256)) != 0)
		{
			std::cout << "gethostname() Error: " << ret << std::endl;
		}
#endif
		else
		{
			struct addrinfo* l_addrInfo = NULL;
			struct addrinfo l_addrInfoHints;

			memset(&l_addrInfoHints, 0, sizeof(addrinfo));

			l_addrInfoHints.ai_socktype = SOCK_STREAM;
			l_addrInfoHints.ai_family = PF_INET;

#if defined(_WINDOWS)
			if ( getaddrinfo(bufHostName, NULL, &l_addrInfoHints, &l_addrInfo) != 0 )
			{
				error = WSAGetLastError();
				std::cout << "getaddrinfo() Error: " << error << std::endl;
			}
#else
			if ( (ret = getaddrinfo(bufHostName, NULL, &l_addrInfoHints, &l_addrInfo)) != 0 )
			{
				std::cout << "getaddrinfo() Error: " << ret << std::endl;
			}
#endif
			else {
				struct sockaddr_in* sockaddr_ipv4 = (struct sockaddr_in *) l_addrInfo->ai_addr;
				const char* ip = inet_ntoa(sockaddr_ipv4->sin_addr);
#if defined(_WINDOWS)
				strcpy_s(bufIP4, ip);
#else
				strcpy(bufIP4, ip);
#endif
				unsigned long* sAddr = (unsigned long*) &sockaddr_ipv4->sin_addr.s_addr;
				{
					std::stringstream ss;
					ss << std::setw(3) << std::setfill('0');
					ss << (int) ( ( (*sAddr) & 0xFF000000) >> 24);
					ip4[3] = ss.str();
				}
				{
					std::stringstream ss;
					ss << std::setw(3) << std::setfill('0');
					ss << (int) ( ( (*sAddr) & 0x00FF0000) >> 16);
					ip4[2] = ss.str();
				}
				{
					std::stringstream ss;
					ss << std::setw(3) << std::setfill('0');
					ss << (int) ( ( (*sAddr) & 0x0000FF00) >> 8);
					ip4[1] = ss.str();
				}
				{
					std::stringstream ss;
					ss << std::setw(3) << std::setfill('0');
					ss << (int) ( ( (*sAddr) & 0x000000FF) );
					ip4[0] = ss.str();
				}
			}
		}
#if defined(_WINDOWS)
		WSACleanup();
#endif
		bool changed = true;

		while(changed) {

			std::string::size_type it0;
			it0 = realAET.find("%IP1");
			if (it0 != std::string::npos) {
				realAET = realAET.replace(it0, 4, ip4[0] );
			}
			else {
				it0 = realAET.find("%IP2");
				if (it0 != std::string::npos) {
					realAET = realAET.replace(it0, 4, ip4[1] );
				}
				else {
					it0 = realAET.find("%IP3");
					if (it0 != std::string::npos) {
						realAET = realAET.replace(it0, 4, ip4[2] );
					}
					else {
						it0 = realAET.find("%IP4");
						if (it0 != std::string::npos) {
							realAET	= realAET.replace(it0, 4, ip4[3] );
						}
						else {
							it0 = realAET.find("%IP");
							if (it0 != std::string::npos) {
								realAET = realAET.replace(it0, 3, bufIP4 );
							}
							else {
								it0 = realAET.find("%HOSTNAME");
								if (it0 != std::string::npos) {
									realAET = realAET.replace(it0, 9, bufHostName );
								}
								else {
									changed = false;
								}
							}
						}
					}
				}
			}

		}
	}

	return realAET;
}
