/* eCAP ClamAV Adapter                                http://www.e-cap.org/
 * Copyright (C) 2011 The Measurement Factory.
 * Distributed under GPL v2 without any warranty.                        */

#include "Adapter.h"
#include "Antivirus.h"
#include "Async.h"
#include <utility>
#include <cstring>
#include <cassert>
#include <libecap/common/errors.h>

#include "Answer.h"
#include "Timeout.h"

namespace Adapter {
    // The actual type of the Antivirus::AsyncScan(void*) parameter
    typedef std::pair<Antivirus *, Answer *> AsyncScanParam;
}

void Adapter::Antivirus::blockingScan(Answer &answer)
{
    scan(answer);
    answer.deliver();
}

void Adapter::Antivirus::asyncScan(Answer *answer)
{
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    pthread_t id;
    AsyncScanParam *param = new AsyncScanParam(std::make_pair(this, answer));
    const int errNo = pthread_create(&id, &attr, &Adapter::Antivirus::AsyncScan, param);
    pthread_attr_destroy(&attr);
    if (errNo) {
        answer->statusCode = Answer::scError;
        answer->errorMsg = strerror(errNo); // TODO: make thread-safe
        answer->deliver(); // must destroy answer (eventually)
        delete param;
    }
    // else the thread becomes responsible for answer delivery
}

// Warning: This static method runs in a non-host thread!
void *Adapter::Antivirus::AsyncScan(void *param_)
{
    AsyncScanParam *param = static_cast<AsyncScanParam *>(param_);
    assert(param);
    Antivirus *self = param->first;
    Answer *answer = param->second;
    assert(self);
    assert(answer);
    self->scan(*answer);
    answer->deliver(); // must destroy answer (eventually)
    delete param;
    return 0;
}
