#include "match.hpp"
#include <vector>


typedef Match*(*getinst_t)(Match*, const char*, size_t);
static __attribute__((init_priority(101))) std::vector<std::pair<const char*, getinst_t> > matches;
void register_match(const char* type, getinst_t getinst) {
    matches.push_back(std::pair<const char*, getinst_t>(type, getinst));
}


Match::Match(Match* n, size_t mi, size_t ma): next(n), mymin(mi), mymax(ma), min(mi), max(ma) {
}


Match::~Match() {
    if (next) delete next; // bubble up
}


bool Match::runall(packet_t* p, size_t off, NFQ::result_t& result) {
    if (off + p->dlen < min) return true;
    if (off > max) return false; // never again
    Match* inst = this;
    do {
        inst->run(p, off, result);
        inst = inst->next;
    } while (inst);
    return true;
}


Match* Match::parse(Match* list, const char* buf, size_t len) {
    while (len && (*buf == ' ' || *buf == '\t')) {
        buf++;
        len--;
    }

    for (std::vector<std::pair<const char*, getinst_t> >::iterator it = matches.begin(); it != matches.end(); it++) {
        size_t tl = strlen(it->first);
        if (tl <= len && strncmp(buf, it->first, tl) == 0 && (buf[tl] == ' ' || buf[tl] == '\t')) {
            Match* inst = it->second(list, buf+tl+1, len-tl-1);
            if (inst && !inst->is_valid()) {
                LOG("cannot parse '%s' match '%.*s'", it->first, (int)len, buf);
                delete inst;
                inst = NULL;
            } else if (inst && list) {
                inst->min = MIN(inst->min, list->min);
                inst->max = MAX(inst->max, list->max);
            }
            return inst;
        }
    }

    LOG("cannot find match for list line '%.*s'", (int)len, buf);
    return NULL;
}