/**
* C-Nery - A home automation web application for C-Bus.
* Copyright (C) 2008,2009,2012 Dave Oxley <dave@daveoxley.co.uk>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.daveoxley.cnery.scenes;
import com.daveoxley.cbus.CGateException;
import com.daveoxley.cbus.Group;
import com.daveoxley.cnery.entities.AbstractCondition;
import com.daveoxley.cnery.entities.ConditionProvider;
import com.daveoxley.cnery.entities.Scene;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author Dave Oxley <dave@daveoxley.co.uk>
*/
public abstract class AbstractRunner<T extends AbstractCondition & ConditionProvider<T>> {
private final static Log log = LogFactory.getLog(AbstractRunner.class);
abstract boolean ignoreCondition(boolean scheduledCheck, T condition);
abstract boolean doAction(T condition);
boolean conditionsMet(ConditionProvider<T> conditionProvider, boolean scheduledCheck) throws CGateException {
return conditionsMet(conditionProvider, scheduledCheck, true);
}
private boolean conditionsMet(ConditionProvider<T> conditionProvider, boolean scheduledCheck, boolean and) throws CGateException {
GregorianCalendar currentTime = new GregorianCalendar();
GregorianCalendar latestAfterActionTime = null;
GregorianCalendar earlisetBeforeActionTime = null;
boolean doActionAfter = false;
boolean doActionBefore = false;
boolean groupSceneConditionMet = true;
boolean logicConditionsMet = true;
for (T sac : conditionProvider.getConditions()) {
if (sac.getActionType() == AbstractCondition.ActionType.LOGIC) {
if (logicConditionsMet) {
logicConditionsMet = logicConditionsMet && conditionsMet(sac, scheduledCheck, sac.getLogic() == AbstractCondition.Logic.AND);
// Satisfy or logic
if (!and && logicConditionsMet)
return true;
}
}
else if (!ignoreCondition(scheduledCheck, sac)) {
if (sac.getActionType() == AbstractCondition.ActionType.TIME) {
if (!and)
throw new IllegalStateException("Time conditions are not valid children of Or logic.");
GregorianCalendar actionTime = sac.getActionGregorian(currentTime);
if (sac.getTimeAfterBefore() == AbstractCondition.TimeAfterBefore.AFTER) {
if ((latestAfterActionTime == null || !actionTime.before(latestAfterActionTime)) && actionTime.before(currentTime)) {
latestAfterActionTime = actionTime;
doActionAfter = doAction(sac);
}
} else if (sac.getTimeAfterBefore() == AbstractCondition.TimeAfterBefore.BEFORE) {
if ((earlisetBeforeActionTime == null || actionTime.before(earlisetBeforeActionTime)) && !actionTime.before(currentTime)) {
earlisetBeforeActionTime = actionTime;
doActionBefore = doAction(sac);
}
}
else
throw new IllegalStateException();
}
else if (sac.getActionType() == AbstractCondition.ActionType.GROUP) {
if (groupSceneConditionMet) {
Group dependGroup = sac.getDependCBusGroup();
log.debug("Checking group condition " + sac.getDependGroup() + " : level=" +
dependGroup.getLevel() + ", groupOnOff=" + sac.getSceneGroupOnOff() +
", doAction=" + doAction(sac));
groupSceneConditionMet = ((dependGroup.getLevel() > 0 && sac.getSceneGroupOnOff() == AbstractCondition.SceneGroupOnOff.GROUP_ON) ||
(dependGroup.getLevel() == 0 && sac.getSceneGroupOnOff() == AbstractCondition.SceneGroupOnOff.GROUP_OFF)) == doAction(sac);
// Satisfy or logic
if (!and && groupSceneConditionMet)
return true;
}
}
else if (sac.getActionType() == AbstractCondition.ActionType.SCENE) {
if (groupSceneConditionMet) {
Scene dependScene = sac.getDependScene();
log.debug("Checking scene condition " + sac.getDependScene() + " : active=" +
dependScene.isActive() + ", groupOnOff=" + sac.getSceneGroupOnOff() +
", doAction=" + doAction(sac));
groupSceneConditionMet = ((dependScene.isActive() && sac.getSceneGroupOnOff() == AbstractCondition.SceneGroupOnOff.SCENE_ACTIVE) ||
(!dependScene.isActive() && sac.getSceneGroupOnOff() == AbstractCondition.SceneGroupOnOff.SCENE_INACTIVE)) ==
doAction(sac);
// Satisfy or logic
if (!and && groupSceneConditionMet)
return true;
}
}
else
throw new IllegalStateException();
}
}
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
String timeLogMessage = "";
if (latestAfterActionTime != null)
timeLogMessage += "doActionAfter: " + doActionAfter + " - " + formatter.format(latestAfterActionTime.getTime());
if (earlisetBeforeActionTime != null)
timeLogMessage += "doActionBefore: " + doActionBefore + " - " + formatter.format(earlisetBeforeActionTime.getTime());
if (latestAfterActionTime != null || earlisetBeforeActionTime != null)
log.debug(timeLogMessage);
boolean timeConditionMet = (latestAfterActionTime == null || doActionAfter) && (earlisetBeforeActionTime == null || doActionBefore);
log.info("timeConditionMet: " + timeConditionMet + ", groupSceneConditionMet: " + groupSceneConditionMet);
return timeConditionMet && groupSceneConditionMet && logicConditionsMet;
}
}