#include "Filter.h"
#include <sstream>
#ifndef DISPATCH_DEBUG
#include "LowerTestAdapter/LowerTestAdapter.h"
#endif

Filter::Filter() :
	m_matchType(EFilterMatch_None),
	m_pNextLayer(0),
	m_bAcceptAll(false)
{
}

Filter::Filter(const Filter & src) :
	m_matchType(src.m_matchType),
	m_pNextLayer(src.m_pNextLayer ? new FilterSet(*src.m_pNextLayer) : 0),
	m_bAcceptAll(src.m_bAcceptAll)
{
}

Filter::~Filter()
{
	delete m_pNextLayer;
}

EFilterMatch Filter::GetMatchType() const
{
	return m_matchType;
}

void Filter::SetMatchType(EFilterMatch matchType)
{
	m_matchType = matchType;
	if (m_pNextLayer)
		m_pNextLayer->SetMatchType(matchType);
}

void Filter::AddNextLayerFilter(const Filter & filter)
{
	if (!m_pNextLayer)
		m_pNextLayer = new FilterSet();
	m_pNextLayer->AddFilter(filter);
}

void Filter::ClearNextLayerFilters()
{
	delete m_pNextLayer;
	m_pNextLayer = 0;
}

std::string Filter::GetSourcePcapFilter() const
{
	return "";
}

std::string Filter::GetDestinationPcapFilter() const
{
	return "";
}

void Filter::SetAllPacketsAccepted(bool bAccept)
{
	m_bAcceptAll = bAccept;
}

bool Filter::AreAllPacketsAccepted()
{
	return m_bAcceptAll;
}

FilterSet * Filter::DetachFilterSet()
{
	FilterSet * pRes = m_pNextLayer;
	m_pNextLayer = 0;
	return pRes;
}

FilterSet::FilterSet()
{
}

FilterSet::FilterSet(const FilterSet & src)
{
	for (const_iterator it = src.begin(); it != src.end(); ++it)
		push_back((*it)->Clone());
}

FilterSet::~FilterSet()
{
	for (iterator it = begin(); it != end(); ++it)
		delete *it;
}

void FilterSet::AddFilter(const Filter & filter)
{
	push_back(filter.Clone());
}

bool FilterSet::Match(const ProtocolInfoElement * pProtocolInfo)
{
	bool bSenderMatch = false;
	bool bRcvMatch = false;
	iterator it = begin();
	bool bEmptyFilterSet = true;

	std::clog << ">>> FilterSet::Match " << pProtocolInfo->ToString() << " - " << pProtocolInfo->GetId() << std::endl;

	while (it != end())
	{
	  bEmptyFilterSet = false;
		if (!(*it)->Match(pProtocolInfo)) // remove filter element
		{
		  	delete (*it);
		  	it = erase(it);
			std::cerr << "FilterSet::Match: no match" << std::endl;
		}
		else
		{
			EFilterMatch matchType = (*it)->GetMatchType();
			bSenderMatch |= matchType == EFilterMatch_Sender;
			bRcvMatch |= matchType == EFilterMatch_Receiver;
			++it;
			std::clog << "FilterSet::Match: match: bSenderMatch:" << bSenderMatch << " - bRcvMatch:" << bRcvMatch << std::endl;
		}
	}
	std::clog << "FilterSet::Match: match after loop: bSenderMatch:" << bSenderMatch << " - bRcvMatch:" << bRcvMatch << " - bEmptyFilterSet:" << bEmptyFilterSet << std::endl;
	if( (pProtocolInfo->GetId() == EProtocolType_Udp) 
	    || (pProtocolInfo->GetId() == EProtocolType_Tcp) || (pProtocolInfo->GetId() == EProtocolType_IPv6)) {
	  if ((bSenderMatch || bRcvMatch) || bEmptyFilterSet) // TODO: To be removed
			std::clog << "<<< FilterSet::Match: true" << std::endl;
	  else
			std::clog << "<<< FilterSet::Match: false" << std::endl;
	  return (bSenderMatch || bRcvMatch) || bEmptyFilterSet; 
	}
	
  if ((bSenderMatch && bRcvMatch) || bEmptyFilterSet) // TODO: To be removed
		std::clog << "<<< FilterSet::Match: true" << std::endl;
  else
		std::clog << "<<< FilterSet::Match: false" << std::endl;
	return (bSenderMatch && bRcvMatch) || bEmptyFilterSet; 
}

void FilterSet::MoveToNextLayer()
{
	std::vector<FilterSet *> tmp;
	for (iterator it = begin(); it != end(); ++it)
		tmp.push_back((*it)->DetachFilterSet());

	clear();
	for (unsigned int i = 0; i < tmp.size(); ++i)
	{
		FilterSet * pFs = tmp[i];
		if (pFs)
		{
			for (iterator it = pFs->begin(); it != pFs->end(); ++it)
				push_back(*it);
			pFs->clear();
			delete pFs;
		}
	}
}

void FilterSet::SetMatchType(EFilterMatch matchType)
{
	for (iterator it = begin(); it != end(); ++it)
		(*it)->SetMatchType(matchType);
}

std::string FilterSet::GetPcapFilter() const
{
	std::clog << ">>> FilterSet::GetPcapFilter" << std::endl;

	std::stringstream ss;
	for (const_iterator it = begin(); it != end(); ++it)
	{
		std::string sSource = (*it)->GetSourcePcapFilter();
		int nDestCount = 0;
		for (const_iterator it2 = begin(); it2 != end(); ++it2)
		{
			if (it2 == it)
				continue;
			std::string sDest = (*it2)->GetDestinationPcapFilter();
			if (!sDest.empty())
			{
				++nDestCount;
				if (ss.tellp() > 0)
					ss << " or ";
				ss << "(";
				if (sSource.empty())
					ss << sDest;
				else
					ss << "(" << sSource << ") and (" << sDest << ")";
				ss << ")";
			}
		}
		if (nDestCount == 0 && !sSource.empty())
		{
			if (ss.tellp() > 0)
				ss << " or ";
			ss << "(" << sSource << ")";
		}
	}
	
	std::clog << "<<< FilterSet::GetPcapFilter: " << ss.str() << std::endl;
	return ss.str();
}


ComponentFilter::ComponentFilter()
{
}

ComponentFilter::ComponentFilter(const ComponentFilter & src)
{
	for (const_iterator it = src.begin(); it != src.end(); ++it)
		RegisterComponent(it->first, *it->second);
}

ComponentFilter::~ComponentFilter()
{
	for (iterator it = begin(); it != end(); ++it)
		delete it->second;
}

void ComponentFilter::RegisterItem(const t3devlib::ComponentId * pId, const FilterSet & filter)
{
	push_back(std::pair<const t3devlib::ComponentId *, FilterSet *>(pId, new FilterSet(filter)));
}

void ComponentFilter::RegisterComponent(const t3devlib::ComponentId * pId, const FilterSet & filter)
{
	UnregisterComponent(pId);
	RegisterItem(pId, filter);
}

void ComponentFilter::UnregisterComponent(const t3devlib::ComponentId * pId)
{
	iterator it = begin();
	while (it != end())
	{
		if (it->first == pId)
		{
			delete it->second;
			it = erase(it);
		}
		else
			++it;
	}
}

bool ComponentFilter::Match(const ProtocolInfoElement * pProtocolInfo)
{
	iterator it = begin();
	while (it != end())
	{
		if (!it->second->Match(pProtocolInfo)) // remove element
		{
			delete it->second;
			it = erase(it);
		}
		else
			++it;
	}
	return begin() != end();	
}
void ComponentFilter::MoveToNextLayer()
{
	for (iterator it = begin(); it != end(); ++it)
		it->second->MoveToNextLayer();
}
void ComponentFilter::Clear()
{
	for (iterator it = begin(); it != end(); ++it)
		delete it->second;
	clear();
}
void ComponentFilter::EnqueueMessage(const unsigned char * pData, int nDataLength)
{
#ifndef DISPATCH_DEBUG
	for (iterator it = begin(); it != end(); ++it)
		LowerTestAdapter::Instance().EnqueueMessage(it->first, pData, nDataLength);
#endif
}

std::string ComponentFilter::GetPcapFilter() const
{
	std::stringstream ss;
	for (const_iterator it = begin(); it != end(); ++it)
	{
		std::string sTmp = it->second->GetPcapFilter();
		if (!sTmp.empty())
		{
			if (ss.tellp() > 0)
				ss << " or ";
			ss << "(" << sTmp << ")";
		}
	}
	return ss.str();
}
