#include "event/EventProcessingRule.h"
#include "expression/Expression.h"
#include "expression/function/Functions.h"
#include "context/ContextUtils.h"
#include "context/Contexts.h"
#include "datatable/DataTable.h"
#include "datatable/TableFormat.h"
#include "util/TimeHelper.h"
#include "server/UtilitiesContextConstants.h"
#include "GlobalVars.h"
#include "data/Data.h"

#include <limits>

TableFormatPtr EventProcessingRule::FORMAT_;

EventProcessingRule::EventProcessingRule() : period(0)
{

}

EventProcessingRule::EventProcessingRule(const AgString& mask, const AgString& event) : period(0)
{
    this->mask = mask;
    this->event = event;
}

TableFormatPtr EventProcessingRule::FORMAT()
{
    if (FORMAT_.get() == NULL) {
        FORMAT_->addTableValidator(TableKeyFieldsValidatorPtr(new TableKeyFieldsValidator()));

        FORMAT_->addField(FieldFormat::create( "<" + FIELD_MASK() + "><S><F=NK><D=" + Cres::get()->getString("conContextMask")
                                               + "><E=contextmask>"));
        FORMAT_->addField(FieldFormat::create( "<" + FIELD_EVENT() + "><S><F=EK><V=<L=1 "+  AgString::fromInt(INT_MAX)
                                                + ">><D=" + Cres::get()->getString("efEventName") + ">"));
        FORMAT_->addField(FieldFormat::create( "<" + FIELD_PREFILTER() + "><S><D=" + Cres::get()->getString("efPrefilter")
                                               + "><H=" + Cres::get()->getString("efPrefilterHelp") + "><E="
                                               + AGG_GLOBAL.EDITOR_EXPRESSION + ">"));
        FORMAT_->addField(FieldFormat::create( "<" + FIELD_DEDUPLICATOR() + "><S><D=" + Cres::get()->getString("efDeduplicator")
                                               + "><E=" + AGG_GLOBAL.EDITOR_EXPRESSION + ">"));
        FORMAT_->addField(FieldFormat::create( "<" + FIELD_QUEUE() + "><I><A=100><D="
                                                              + Cres::get()->getString("efMemoryQueue") +">"));
        FORMAT_->addField(FieldFormat::create( "<" + FIELD_DUPLICATE_DISPATCHING() + "><B><D="
                                                              + Cres::get()->getString("efDuplicateDispatching") + ">"));
        FORMAT_->addField(FieldFormat::create( "<" + FIELD_PERIOD() + "><L><A=" + AgString::fromInt64(Event::DEFAULT_EVENT_EXPIRATION_PERIOD())
                                               + "><D=" + Cres::get()->getString("confExpirationPeriod") + "><E="
                                               + AGG_GLOBAL.EDITOR_PERIOD + "><O="
                                               + LongFieldFormat::encodePeriodEditorOptions(TimeHelper::HOUR(), TimeHelper::YEAR())+ ">") );

        FieldFormat* ff = FieldFormat::create( "<" + FIELD_ENRICHMENTS() + "><T><D="
                                                + Cres::get()->getString("enrichments") + ">");
        ff->setDefault(DataTablePtr(new DataTable(EventEnrichmentRule::FORMAT())));
        FORMAT_->addField( ff );

        AgString ref = FIELD_EVENT() + "#" + DataTableBindingProvider::PROPERTY_CHOICES();
        AgString exp = "{"+ Contexts::CTX_UTILITIES + ":" + UtilitiesContextConstants::F_EVENTS_BY_MASK + "('{" + FIELD_MASK() + "}')}";
        FORMAT_->addBinding(ref, exp);

        ref = FIELD_PREFILTER() + "#" + DataTableBindingProvider::PROPERTY_OPTIONS();
        exp = Functions::EXPRESSION_EDITOR_OPTIONS + "({" + FIELD_MASK() + "}, {" + FIELD_EVENT()
                        + "}, " + ContextUtils::ENTITY_EVENT + ")";
        FORMAT_->addBinding(ref, exp);

        ref = FIELD_DEDUPLICATOR() + "#" + DataTableBindingProvider::PROPERTY_OPTIONS();
        exp = Functions::EXPRESSION_EDITOR_OPTIONS + "({" + FIELD_MASK()  + "}, {" + FIELD_EVENT()
                         + "}, " + ContextUtils::ENTITY_EVENT + ")";
        FORMAT_->addBinding(ref, exp);

        ref = FIELD_QUEUE() + "#" + DataTableBindingProvider::PROPERTY_ENABLED();
        exp = "length({" + FIELD_DEDUPLICATOR() + "}) > 0";
        FORMAT_->addBinding(ref, exp);

        FORMAT_->setReorderable(true);

        DataTableConversion::instance().registerFormatConverter(
                    boost::shared_ptr<DefaultFormatConverter>(new DefaultFormatConverter(getClass().c_str(), FORMAT())));
    }

    return FORMAT_;
}

AgString EventProcessingRule::getEvent()
{
    return event;
}

AgString EventProcessingRule::getMask()
{
    return mask;
}

int64_t EventProcessingRule::getPeriod()
{
    return period;
}

void EventProcessingRule::setEvent(const AgString& event)
{
    this->event = event;
}

void EventProcessingRule::setMask(const AgString& mask)
{
    this->mask = mask;
}

void EventProcessingRule::setPeriod(int64_t period)
{
    this->period = period;
}

AgString EventProcessingRule::getPrefilter()
{
    return  prefilter;
}

void EventProcessingRule::setPrefilter(const AgString& prefilter)
{
    this->prefilter = prefilter;
    this->prefilterExpression.reset();
}

ExpressionPtr EventProcessingRule::getPrefilterExpression()
{
    if (prefilterExpression.get() == NULL)
    {
        prefilterExpression = (prefilter.length() > 0) ? ExpressionPtr(new Expression(prefilter)) : ExpressionPtr();
    }

    return prefilterExpression;
}

AgString EventProcessingRule::getDeduplicator()
{
    return deduplicator;
}

void EventProcessingRule::setDeduplicator(const AgString& deduplicator)
{
    this->deduplicator = deduplicator;
    this->deduplicatorExpression.reset();
}

ExpressionPtr EventProcessingRule::getDeduplicatorExpression()
{
    if (deduplicatorExpression.get() == NULL)
    {
        deduplicatorExpression = (deduplicator.length() > 0) ? ExpressionPtr(new Expression(deduplicator)) : ExpressionPtr();
    }

    return deduplicatorExpression;
}

std::list<EventEnrichmentRulePtr >& EventProcessingRule::getEnrichments()
{
    return enrichments;
}

void EventProcessingRule::setEnrichments(std::list<EventEnrichmentRulePtr> enrichments)
{
    this->enrichments = enrichments;
}

int EventProcessingRule::getQueue()
{
    return queue;
}

void EventProcessingRule::setQueue(int queue)
{
    this->queue = queue;
}

bool EventProcessingRule::isDuplicateDispatching()
{
    return duplicateDispatching;
}

void EventProcessingRule::setDuplicateDispatching(bool duplicateDispatching)
{
    this->duplicateDispatching = duplicateDispatching;
}

void EventProcessingRule::addFiltered()
{
    this->filtered++;
}

void EventProcessingRule::addSaved()
{
    this->saved++;
}

void EventProcessingRule::addDuplicate()
{
    this->duplicates++;
}

int64_t EventProcessingRule::getFiltered()
{
    return filtered;
}

int64_t EventProcessingRule::getSaved()
{
    return saved;
}

int64_t EventProcessingRule::getDuplicates()
{
    return duplicates;
}

AgString EventProcessingRule::toString()
{
    return AgString("EventProcessingRule [event=") + event + AgString(", mask=") + mask + AgString("]");
}


int EventProcessingRule::hashCode()
{
    assert(0);
    return 0;
}


bool EventProcessingRule::equals(AgObject *obj)
{
    EventProcessingRule* other = static_cast<EventProcessingRule*>(obj);
    if (this == other)
        return true;

    if (other == NULL)
        return false;

    if (event != other->event)
        return false;

    if (mask != other->mask)
        return false;

    return true;
}

std::string EventProcessingRule::getClass()
{
    return typeid(Data).name();
}
