/** * Copyright (c) 2014-2017 by the respective copyright holders. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.scene; import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.SceneStatusListener; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.Device; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.scene.constants.SceneTypes; /** * The {@link InternalScene} represents a digitalSTROM-Scene for the internal model. * * @author Michael Ochel - Initial contribution * @author Matthias Siegele - Initial contribution */ public class InternalScene { private final Short SCENE_ID; private final Short GROUP_ID; private final Integer ZONE_ID; private String SceneName; private final String INTERNAL_SCENE_ID; private boolean active = false; private boolean deviceHasChanged = false; private String sceneType = SceneTypes.GROUP_SCENE; private List<Device> devices = Collections.synchronizedList(new LinkedList<Device>()); private SceneStatusListener listener = null; /** * Creates a new {@link InternalScene} with the given parameters. Only the <i>sceneID</i> must not be null. If the * <i>sceneName</i> is null, the internal scene id will be set as name in format "[zoneID]-[groupID]-[sceneID]". If * the * <i>zoneID</i> and/or the <i> groupID</i> is null, the broadcast address 0 will be set. * * @param zoneID can be null * @param groupID can be null * @param sceneID must not be null * @param sceneName can be null */ public InternalScene(Integer zoneID, Short groupID, Short sceneID, String sceneName) { if (sceneID == null) { throw new IllegalArgumentException("The parameter sceneID can't be null!"); } this.SCENE_ID = sceneID; if (groupID == null) { this.GROUP_ID = 0; } else { this.GROUP_ID = groupID; } if (zoneID == null) { this.ZONE_ID = 0; } else { this.ZONE_ID = zoneID; } this.INTERNAL_SCENE_ID = this.ZONE_ID + "-" + this.GROUP_ID + "-" + this.SCENE_ID; if (StringUtils.isBlank(sceneName)) { this.SceneName = this.INTERNAL_SCENE_ID; } else { this.SceneName = sceneName; } if ((sceneName != this.INTERNAL_SCENE_ID) && !sceneName.contains("Apartment-Scene: ") && !sceneName.contains("Zone-Scene: Zone:") && !(sceneName.contains("Zone: ") && sceneName.contains("Group: ") && sceneName.contains("Scene: "))) { sceneType = SceneTypes.NAMED_SCENE; } else if (this.ZONE_ID == 0) { sceneType = SceneTypes.APARTMENT_SCENE; } else if (this.GROUP_ID == 0) { sceneType = SceneTypes.ZONE_SCENE; } } /** * Activates this Scene. */ public void activateScene() { if (!active) { this.active = true; deviceHasChanged = false; informListener(); if (this.devices != null) { for (Device device : this.devices) { device.callInternalScene(this); } } } } /** * Deactivates this Scene. */ public void deactivateScene() { if (active) { this.active = false; deviceHasChanged = false; informListener(); if (this.devices != null) { for (Device device : this.devices) { device.undoInternalScene(this); } } } } /** * Will be called by a device, if an undo call of an other scene activated this scene. */ public void activateSceneByDevice() { if (!active && !deviceHasChanged) { this.active = true; deviceHasChanged = false; informListener(); } } /** * Will be called by a device, if an call of an other scene deactivated this scene. */ public void deactivateSceneByDevice() { if (active) { this.active = false; deviceHasChanged = false; informListener(); } } /** * This method has a device to call, if this scene was activated and the device state has changed. * * @param sceneNumber */ public void deviceSceneChanged(short sceneNumber) { if (this.SCENE_ID != sceneNumber) { if (active) { deviceHasChanged = true; active = false; informListener(); } } } private void informListener() { if (this.listener != null) { listener.onSceneStateChanged(this.active); } } /** * Returns true, if this scene is active, otherwise false. * * @return Scene is active? (true = yes | false = no) */ public boolean isActive() { return this.active; } /** * Adds an affected {@link Device} to this {@link InternalScene} device list. * * @param device */ public void addDevice(Device device) { if (!this.devices.contains(device)) { this.devices.add(device); } int prio = 0; if (this.listener != null) { prio = 1000; } else { prio = 2000; } device.checkSceneConfig(SCENE_ID, prio); } /** * Overrides the existing device list of this {@link InternalScene} with a new reference to a {@link List} of * affected {@link Device}'s. * * @param deviceList */ public void addReferenceDevices(List<Device> deviceList) { this.devices = deviceList; checkDeviceSceneConfig(); } /** * Proves, if the scene configuration is saved to all {@link Device}'s. If not, the device initials the reading out * of the missing configuration in the following priority steps: * <ul> * <li>low priority, if no listener is added.</li> * <li>medium priority, if a listener is added.</li> * <li>high priority, if this scene has been activated.</li> * </ul> */ public void checkDeviceSceneConfig() { int prio = 0; if (this.listener != null) { prio = 1000; } else { prio = 2000; } if (devices != null) { for (Device device : devices) { device.checkSceneConfig(SCENE_ID, prio); } } } /** * Returns the list of the affected {@link Device}'s. * * @return device list */ public List<Device> getDeviceList() { return this.devices; } /** * Adds a {@link List} of affected {@link Device}'s. * * @param deviceList */ public void addDevices(List<Device> deviceList) { for (Device device : deviceList) { addDevice(device); } } /** * Removes a not anymore affected {@link Device} from the device list. * * @param device */ public void removeDevice(Device device) { this.devices.remove(device); } /** * Updates the affected {@link Device}'s with the given deviceList. * * @param deviceList */ public void updateDeviceList(List<Device> deviceList) { if (!this.devices.equals(deviceList)) { this.devices.clear(); addDevices(deviceList); } } /** * Returns the Scene name. * * @return scene name */ public String getSceneName() { return SceneName; } /** * Sets the scene name. * * @param sceneName */ public void setSceneName(String sceneName) { SceneName = sceneName; } /** * Returns the Scene id of this scene call. * * @return scene id */ public Short getSceneID() { return SCENE_ID; } /** * Returns the group id of this scene call. * * @return group id */ public Short getGroupID() { return GROUP_ID; } /** * Returns the zone id of this scene call. * * @return zone id */ public Integer getZoneID() { return ZONE_ID; } /** * Returns the id of this scene call. * * @return scene call id */ public String getID() { return INTERNAL_SCENE_ID; } /** * Registers a {@link SceneStatusListener} to this {@link InternalScene}. * * @param listener */ public synchronized void registerSceneListener(SceneStatusListener listener) { this.listener = listener; this.listener.onSceneAdded(this); checkDeviceSceneConfig(); } /** * Unregisters the {@link SceneStatusListener} from this {@link InternalScene}. */ public synchronized void unregisterSceneListener() { if (listener != null) { // this.listener.onSceneRemoved(this); this.listener = null; } } /** * Returns the scene type. * <br> * <b>Note:</b> * The valid Scene types can be found at {@link SceneTypes}. * * @return sceneType */ public String getSceneType() { return this.sceneType; } @Override public String toString() { return "NamedScene [SceneName=" + SceneName + ", NAMED_SCENE_ID=" + INTERNAL_SCENE_ID + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((INTERNAL_SCENE_ID == null) ? 0 : INTERNAL_SCENE_ID.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof InternalScene)) { return false; } InternalScene other = (InternalScene) obj; if (INTERNAL_SCENE_ID == null) { if (other.getID() != null) { return false; } } else if (!INTERNAL_SCENE_ID.equals(other.getID())) { return false; } return true; } }