/** * 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; } }