#include "PacketFilter.h"
#include "Logger/Logger.h"

PacketFilter::PacketFilter(const string& sFilter) 
  :m_left(0),
   m_right(0),
   m_expr(0),
   m_operator(FO_NONE),
   m_valid(false) {
  int level = 0;
  string::const_iterator it = sFilter.end();
  string::const_iterator rightIt = sFilter.end();
  string::const_iterator leftIt = sFilter.begin();

  //Remove left space
  while((leftIt != sFilter.end()) && *leftIt == ' ')
    leftIt++;

  Logger::Instance().LogDebug(sFilter);

  while (it > sFilter.begin()) {
    switch (*it) {

    case ' ':
      if(!m_right) {
	//remove right space
	rightIt = it;
      }
      --it;
      break;

    case ')':
      level = 0;
      for(--it; (it != sFilter.begin()) && !((*it == '(') && (level == 0)); --it) {
	switch (*it) {
	case '(':
	  level --;
	  break;
	case ')': 
	  level ++;
	  break;
	default:
	  break;
	}
      }
      m_right = new PacketFilter(sFilter.substr(it - leftIt + 1,
						rightIt - it - 2));
      rightIt = --it;
      break;

    case '(':
      Logger::Instance().LogError("No matching parenthesis for '('");
      return;

    case '&':
      if( *(--it) != '&') {
	Logger::Instance().LogError("Unknown operator '&'");
	return;
      }
      m_operator = FO_AND;
      m_left = new PacketFilter(sFilter.substr(0, it - leftIt));
      if(!m_right) {
	m_right = new PacketFilter(sFilter.substr(it - leftIt + 2,
						  string::npos));
      }
      it = sFilter.begin();
      break;

    case '|':
      if( *(--it) != '|') {
	Logger::Instance().LogError("Unknown operator '|'");
	return;
      }
      m_operator = FO_OR;
      m_left = new PacketFilter(sFilter.substr(0, it - leftIt));
      if(!m_right) {
	m_right = new PacketFilter(sFilter.substr(it - leftIt + 2,
						  string::npos));
      }
      it = sFilter.begin();
      break;


    default:
      --it;
    }
  }

  if(!m_right) {
    // simple expression
    m_expr = new PacketFilterExpression(sFilter);
  }
  m_valid = true;
}

PacketFilter::~PacketFilter() {
  delete m_left;
  delete m_right;
  delete m_expr;
}

const string& PacketFilter::GetFilter() const {
  string *s = new string("");

  if(m_left) {
    if(m_operator != FO_NONE) 
      *s += "("; 
    *s += m_left->GetFilter();
    if(m_operator != FO_NONE) 
      *s += ")";
  }

  if(m_operator == FO_AND) 
    *s += "&&";

  if(m_operator == FO_OR) 
    *s += "||";

  if(m_right) {
    if(m_operator != FO_NONE) 
      *s += "("; 
    *s += m_right->GetFilter();
    if(m_operator != FO_NONE) 
      *s += ")";
  }
  else
    *s += m_expr->GetExpression();

  return *s;
}

bool PacketFilter::Match(const PacketDissector& packet) const {

  if(m_operator == FO_NONE) {
    if(m_right)
      return m_right->Match(packet);
    else {
      if(m_expr) {
	return m_expr->Match(packet);
      }	
    }
  }

  if(m_operator == FO_AND)
    return m_left->Match(packet) && m_right->Match(packet);

  if(m_operator == FO_OR)
    return m_left->Match(packet) || m_right->Match(packet);
}
