#include "Ipv6Filter.h"
#include "Capture/TcpipDefs.h"

//#ifdef __cplusplus
//extern "C" {
//#endif
//	struct hostent	*gethostbyname2(const char *, int);
//#ifdef __cplusplus
//};
//#endif


Ipv6Filter::Ipv6Filter() :
	m_nAddr(16),
	m_sAddr("")
{
}

Ipv6Filter::Ipv6Filter(const Ipv6Filter & src) :
	Filter(src),
	m_nAddr(src.m_nAddr),
	m_sAddr(src.m_sAddr)
{
}

Ipv6Filter::~Ipv6Filter()
{
}

Filter * Ipv6Filter::Clone() const
{
	return new Ipv6Filter(*this);
}

bool Ipv6Filter::SetAddress(const std::string sAddr)
{	
	std::clog << ">>> Ipv6Filter::SetAddress: " << sAddr << std::endl;

	/*struct sockaddr_in6 tgtAddr;
	memset(&tgtAddr, 0, sizeof tgtAddr);

	struct hostent * host;
	host = gethostbyname2(sAddr.c_str(), AF_INET6);
	if (host == NULL) {
		std::cerr << "Ipv6Filter::SetAddress: gethostbyname2 failure: " << errno << std::endl;
		return false;
	}*/
	// TODO: Q&D. The rigth behavior is using gethostbyname2() function!
	m_sAddr = sAddr;
	std::vector<std::string> results;
	SplitString(sAddr, std::string(":"), results, true);
	std::clog << "Ipv6Filter::SetAddress: results=" << (int)results.size() << std::endl;
	for (int i = 0, idx = 0; i < (int)results.size(); i++)
	{
		std::clog << "Ipv6Filter::SetAddress: results[" << i << "]=" << results[i] << std::endl;
		switch (results[i].length()) {
			case 0:
				m_nAddr[idx++] = 0x00;
				m_nAddr[idx++] = 0x00;
				break;
			case 1:
				m_nAddr[idx++] = 0x00;
				sscanf(results[i].c_str(), "%01x", &m_nAddr[idx++]);
				break;
			case 2:
				m_nAddr[idx++] = 0x00;
				sscanf(results[i].c_str(), "%02x", &m_nAddr[idx++]);
				break;
			case 3:
				sscanf(results[i].c_str(), "%01x%02x", &m_nAddr[idx], &m_nAddr[idx + 1]);
				idx += 2;
				break;
			case 4:
				sscanf(results[i].c_str(), "%02x%02x", &m_nAddr[idx], &m_nAddr[idx + 1]);
				idx += 2;
				break;
			default:
				std::cerr << "Ipv6Filter::SetAddress: Failed to convert the IP address into byte arrray" << std::endl;
		}
	}

	return true;
}

bool Ipv6Filter::Match(const ProtocolInfoElement * pProtocolInfo)
{
	std::clog << ">>> Ipv6Filter::Match: " << pProtocolInfo->ToString() << std::endl;

	if (pProtocolInfo->GetId() != EProtocolType_IPv6)
		return false;
	if (AreAllPacketsAccepted())
		return true;

	const IPv6Info * pIPv6 = dynamic_cast<const IPv6Info *>(pProtocolInfo);

	EFilterMatch matchType = GetMatchType();

	if (matchType == EFilterMatch_Receiver)
		std::clog << " Ipv6Filter::Match: Compare " << m_sAddr << " with " << pIPv6->GetDestinationAddress() << std::endl;
	else if (matchType == EFilterMatch_Sender)
		std::clog << " Ipv6Filter::Match: Compare " << m_sAddr << " with " << pIPv6->GetSourceAddress() << std::endl;
	else
		std::clog << " Ipv6Filter::Match: Compare " << m_sAddr << " with " << pIPv6->GetSourceAddress() << " and " << pIPv6->GetDestinationAddress() << std::endl;
		
	if (matchType == EFilterMatch_Receiver)
		return m_sAddr.compare(pIPv6->GetDestinationAddress()) == 0;
	else if (matchType == EFilterMatch_Sender)
		return m_sAddr.compare(pIPv6->GetSourceAddress()) == 0;
	else
	{
		if (m_sAddr.compare(pIPv6->GetDestinationAddress()) == 0)
			SetMatchType(EFilterMatch_Receiver);
		else if (m_sAddr.compare(pIPv6->GetSourceAddress()) == 0)
			SetMatchType(EFilterMatch_Sender);
		return matchType != GetMatchType();
	}
}

std::string Ipv6Filter::GetSourcePcapFilter() const
{
	std::string sRes = "src host ";
	sRes += m_sAddr;
	return sRes;
}

std::string Ipv6Filter::GetDestinationPcapFilter() const
{
	std::string sRes = "dst host ";
	sRes += m_sAddr;
	return sRes;
}

int Ipv6Filter::SplitString(const std::string& input, const std::string& delimiter, std::vector<std::string>& results, bool includeEmpties)
{
    int iPos = 0;
    int newPos = -1;
    int sizeS2 = (int)delimiter.size();
    int isize = (int)input.size();

    if( 
        ( isize == 0 )
        ||
        ( sizeS2 == 0 )
    )
    {
        return 0;
    }

    std::vector<int> positions;

    newPos = input.find (delimiter, 0);

    if( newPos < 0 )
    { 
        return 0; 
    }

    int numFound = 0;

    while( newPos >= iPos )
    {
        numFound++;
        positions.push_back(newPos);
        iPos = newPos;
        newPos = input.find (delimiter, iPos+sizeS2);
    }

    if( numFound == 0 )
    {
        return 0;
    }

    for( int i=0; i <= (int)positions.size(); ++i )
    {
        std::string s("");
        if( i == 0 ) 
        { 
            s = input.substr( i, positions[i] ); 
        }
        int offset = positions[i-1] + sizeS2;
        if( offset < isize )
        {
            if( i == positions.size() )
            {
                s = input.substr(offset);
            }
            else if( i > 0 )
            {
                s = input.substr( positions[i-1] + sizeS2, 
                      positions[i] - positions[i-1] - sizeS2 );
            }
        }
        if( includeEmpties || ( s.size() > 0 ) )
        {
            results.push_back(s);
        }
    }
    return numFound;
}

