/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. * This project including source code and documentation is protected by * copyright law, and remains the property of nymea GmbH. All rights, including * reproduction, publication, editing and translation, are reserved. The use of * this project is subject to the terms of a license agreement to be concluded * with nymea GmbH in accordance with the terms of use of nymea GmbH, available * under https://nymea.io/license * * GNU General Public License Usage * Alternatively, this project may be redistributed and/or modified under the * terms of the GNU General Public License as published by the Free Software * Foundation, GNU version 3. This project is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with * this project. If not, see . * * For any further details and any questions please contact us under * contact@nymea.io or see our FAQ/Licensing Information on * https://nymea.io/license/faq * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rule.h" #include "eventdescriptor.h" #include "eventdescriptors.h" #include "stateevaluator.h" #include "stateevaluators.h" #include "statedescriptor.h" #include "ruleaction.h" #include "ruleactions.h" #include "timedescriptor.h" #include "timeeventitems.h" #include "timeeventitem.h" #include "calendaritems.h" #include "calendaritem.h" #include "ruleactionparams.h" #include "ruleactionparam.h" #include Rule::Rule(const QUuid &id, QObject *parent) : QObject(parent), m_id(id), m_eventDescriptors(new EventDescriptors(this)), // m_stateEvaluator(new StateEvaluator(this)), m_actions(new RuleActions(this)), m_exitActions(new RuleActions(this)), m_timeDescriptor(new TimeDescriptor(this)) { // qDebug() << "### Creating rule" << this; } Rule::~Rule() { } QUuid Rule::id() const { return m_id; } QString Rule::name() const { return m_name; } void Rule::setName(const QString &name) { if (m_name != name) { m_name = name; emit nameChanged(); } } bool Rule::enabled() const { return m_enabled; } void Rule::setEnabled(bool enabled) { if (m_enabled != enabled) { m_enabled = enabled; emit enabledChanged(); } } bool Rule::active() const { return m_active; } void Rule::setActive(bool active) { if (m_active != active) { m_active = active; emit activeChanged(); } } bool Rule::executable() const { return m_executable; } void Rule::setExecutable(bool executable) { if (m_executable != executable) { m_executable = executable; emit executableChanged(); } } EventDescriptors *Rule::eventDescriptors() const { return m_eventDescriptors; } StateEvaluator *Rule::stateEvaluator() const { return m_stateEvaluator; } RuleActions *Rule::actions() const { return m_actions; } RuleActions *Rule::exitActions() const { return m_exitActions; } TimeDescriptor *Rule::timeDescriptor() const { return m_timeDescriptor; } void Rule::setStateEvaluator(StateEvaluator *stateEvaluator) { if (m_stateEvaluator) { m_stateEvaluator->deleteLater(); } m_stateEvaluator = stateEvaluator; if (m_stateEvaluator) { // Might be a nullptr now if cleared m_stateEvaluator->setParent(this); } emit stateEvaluatorChanged(); } StateEvaluator* Rule::createStateEvaluator() const { return new StateEvaluator(); } Rule *Rule::clone() const { Rule *ret = new Rule(this->id()); ret->setName(this->name()); ret->setEnabled(this->enabled()); ret->setExecutable(this->executable()); for (int i = 0; i < this->eventDescriptors()->rowCount(); i++) { ret->eventDescriptors()->addEventDescriptor(this->eventDescriptors()->get(i)->clone()); } for (int i = 0; i < this->timeDescriptor()->timeEventItems()->rowCount(); i++) { ret->timeDescriptor()->timeEventItems()->addTimeEventItem(this->timeDescriptor()->timeEventItems()->get(i)->clone()); } for (int i = 0; i < this->timeDescriptor()->calendarItems()->rowCount(); i++) { ret->timeDescriptor()->calendarItems()->addCalendarItem(this->timeDescriptor()->calendarItems()->get(i)->clone()); } if (this->stateEvaluator()) { ret->setStateEvaluator(this->stateEvaluator()->clone()); } for (int i = 0; i < this->actions()->rowCount(); i++) { ret->actions()->addRuleAction(this->actions()->get(i)->clone()); } for (int i = 0; i < this->exitActions()->rowCount(); i++) { ret->exitActions()->addRuleAction(this->exitActions()->get(i)->clone()); } return ret; } bool Rule::compare(Rule *other) const { qDebug() << "comparing rule" << this << "to" << other; return this->operator==(other); } #define COMPARE(a, b) if (a != b) { qDebug() << a << "!=" << b; return false; } #define COMPARE_PTR(a, b) if (!a && !b) return true; if (!a || !b) return false; if (!a->operator==(b)) { qDebug() << a << "!=" << b; return false; } bool Rule::operator==(Rule *other) const { COMPARE(m_id, other->id()); COMPARE(m_name, other->name()); COMPARE(m_enabled, other->enabled()); COMPARE(m_executable, other->executable()); COMPARE_PTR(m_eventDescriptors, other->eventDescriptors()); COMPARE_PTR(m_stateEvaluator, other->stateEvaluator()); COMPARE_PTR(m_actions, other->actions()); COMPARE_PTR(m_exitActions, other->exitActions()); COMPARE_PTR(m_timeDescriptor, other->timeDescriptor()); return true; } QDebug operator <<(QDebug &dbg, Rule *rule) { dbg << rule->name() << " (Enabled:" << rule->enabled() << "Active:" << rule->active() << ")" << endl; if (rule->eventDescriptors()->rowCount() > 0) { dbg << "Event descriptors:" << endl; } for (int i = 0; i < rule->eventDescriptors()->rowCount(); i++) { EventDescriptor *ed = rule->eventDescriptors()->get(i); dbg << " " << i << ":"; if (!ed->thingId().isNull() && !ed->eventTypeId().isNull()) { dbg << "Thing ID:" << ed->thingId() << "Event Type ID:" << ed->eventTypeId() << endl; } else { dbg << "Interface Name:" << ed->interfaceName() << "Event Name:" << ed->interfaceEvent() << endl; } for (int j = 0; j < ed->paramDescriptors()->rowCount(); j++) { ParamDescriptor *epd = ed->paramDescriptors()->get(j); QString operatorString; switch (epd->operatorType()) { case ParamDescriptor::ValueOperatorLess: operatorString = "<"; break; case ParamDescriptor::ValueOperatorEquals: operatorString = "="; break; case ParamDescriptor::ValueOperatorGreater: operatorString = ">"; break; case ParamDescriptor::ValueOperatorNotEquals: operatorString = "!="; break; case ParamDescriptor::ValueOperatorLessOrEqual: operatorString = "<="; break; case ParamDescriptor::ValueOperatorGreaterOrEqual: operatorString = ">="; break; } dbg << " Param" << j << ": ID:" << epd->paramTypeId() << operatorString << " Value:" << epd->value() << endl; } } if (rule->stateEvaluator()) { dbg << "State Evaluator:" << endl; printStateEvaluator(dbg, rule->stateEvaluator()); } if (rule->actions()->rowCount() > 0) { dbg << "Actions:" << endl; } for (int i = 0; i < rule->actions()->rowCount(); i++) { RuleAction *ra = rule->actions()->get(i); dbg << " " << i << ":"; if (!ra->thingId().isNull() && !ra->actionTypeId().isNull()) { dbg << "Thing ID:" << ra->thingId() << "Action Type ID:" << ra->actionTypeId() << endl; } else { dbg << "Interface Name:" << ra->interfaceName() << "Action Name:" << ra->interfaceAction() << endl; } for (int j = 0; j < ra->ruleActionParams()->rowCount(); j++) { RuleActionParam *rap = ra->ruleActionParams()->get(j); if (rap->eventTypeId().isNull()) { dbg << " Param" << j << ": ID:" << rap->paramTypeId() << " Value:" << rap->value() << endl; } else { dbg << " Param" << j << ": ID:" << rap->paramTypeId() << " Source Event Type ID:" << rap->eventTypeId() << "Source Event Param ID:" << rap->eventParamTypeId() << endl; } } } if (rule->exitActions()->rowCount() > 0) { dbg << "Exit Actions:" << endl; } for (int i = 0; i < rule->exitActions()->rowCount(); i++) { RuleAction *ra = rule->exitActions()->get(i); dbg << " " << i << ":"; if (!ra->thingId().isNull() && !ra->actionTypeId().isNull()) { dbg << "Thing ID:" << ra->thingId() << "Action Type ID:" << ra->actionTypeId() << endl;; } else { dbg << "Interface Name:" << ra->interfaceName() << "Action Name:" << ra->interfaceAction() << endl;; } for (int j = 0; j < ra->ruleActionParams()->rowCount(); j++) { RuleActionParam *rap = ra->ruleActionParams()->get(j); if (rap->eventTypeId().isNull()) { dbg << " Param" << j << ": ID:" << rap->paramTypeId() << " Value:" << rap->value() << endl; } else { dbg << " Param" << j << ": ID:" << rap->paramTypeId() << " Source Event Type ID:" << rap->eventTypeId() << "Source Event Param ID:" << rap->eventParamTypeId() << endl; } } } return dbg; } QDebug printStateEvaluator(QDebug &dbg, StateEvaluator *stateEvaluator, int indentLevel) { if (stateEvaluator->stateDescriptor()) { for (int i = 0; i < indentLevel; i++) { dbg << " "; } dbg << "State Descriptor:"; if (!stateEvaluator->stateDescriptor()->thingId().isNull() && !stateEvaluator->stateDescriptor()->stateTypeId().isNull()) { dbg << "Thing ID:" << stateEvaluator->stateDescriptor()->thingId().toString() << "State Type ID:" << stateEvaluator->stateDescriptor()->stateTypeId().toString(); } else { dbg << "Interface name:" << stateEvaluator->stateDescriptor()->interfaceName() << "State Name:" << stateEvaluator->stateDescriptor()->interfaceState(); } switch (stateEvaluator->stateDescriptor()->valueOperator()) { case StateDescriptor::ValueOperatorLess: dbg << "<"; break; case StateDescriptor::ValueOperatorEquals: dbg << "="; break; case StateDescriptor::ValueOperatorGreater: dbg << ">"; break; case StateDescriptor::ValueOperatorNotEquals: dbg << "!="; break; case StateDescriptor::ValueOperatorLessOrEqual: dbg << "<="; break; case StateDescriptor::ValueOperatorGreaterOrEqual: dbg << ">="; break; } dbg << stateEvaluator->stateDescriptor()->value() << '/' << stateEvaluator->stateDescriptor()->valueThingId() << stateEvaluator->stateDescriptor()->valueStateTypeId() << endl; } if (stateEvaluator->childEvaluators()->rowCount() > 0) { for (int i = 0; i < indentLevel; i++) { dbg << " "; } dbg << (stateEvaluator->stateOperator() == StateEvaluator::StateOperatorAnd ? "AND" : "OR") << endl; } for (int i = 0; i < stateEvaluator->childEvaluators()->rowCount(); i++) { printStateEvaluator(dbg, stateEvaluator->childEvaluators()->get(i), indentLevel+1); } return dbg; }