/**
* Copyright (c) 2010-2016 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.openhab.binding.lcn.internal;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import org.openhab.binding.lcn.common.LcnAddr;
import org.openhab.binding.lcn.common.LcnAddrMod;
import org.openhab.binding.lcn.connection.Connection;
import org.openhab.binding.lcn.connection.ConnectionManager;
import org.openhab.binding.lcn.connection.ModInfo;
import org.openhab.binding.lcn.input.Input;
import org.openhab.binding.lcn.mappingtarget.Target;
import org.openhab.binding.lcn.mappingtarget.TargetWithLcnAddr;
import org.openhab.core.binding.BindingConfig;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.Command;
/**
* Holds all data bound to an openHAB item.
* Contains all mappings read from item-configuration.
*
* @author Tobias J�ttner
*/
class LcnBindingConfig implements BindingConfig {
/** Single mapping. */
static class Mapping {
/** OpenHAB Command associated with the mapping. */
private final Command cmd;
/** The target connection's unique identifier. */
private final String connId;
/** The mapping's target. */
private final Target target;
/** Flag to indicate this mapping has already received status data. */
private boolean hasInitialData = false;
/**
* Constructor for a mapping.
*
* @param connId the target connection's unique identifier
* @param cmd the openHAB command this mapping is bound to
* @param lcnTarget the target's configuration
*/
Mapping(Command cmd, String connId, String lcnTarget) {
this.cmd = cmd;
this.connId = connId;
this.target = Target.parse(lcnTarget);
}
/**
* Gets the openHAB command the mapping is bound to.
* Might be an empty dummy for "visualization-mappings".
*
* @return the openHAB command
*/
Command getOpenHabCmd() {
return this.cmd;
}
/**
* Gets the target's connection identifier.
*
* @return the connection identifier
*/
String getConnId() {
return this.connId;
}
/**
* Get the parsed target.
*
* @return the target
*/
Target getTarget() {
return this.target;
}
/**
* Gets the flag that indicates if this mapping has already received status data.
*
* @return true if the mapping has already received status data
*/
boolean hasInitialData() {
return this.hasInitialData;
}
/**
* Sets the flag that indicates if this mapping has already received status data.
*
* @param hasInitialData the flag
*/
void setInitialData(boolean hasInitialData) {
this.hasInitialData = hasInitialData;
}
}
/** The actual underlying openHAB item. */
private final Item item;
/** Mappings for this item. */
private final LinkedList<Mapping> mappings = new LinkedList<Mapping>();
/**
* Constructor for a new LCN item for a given openHAB item.
*
* @param item the source openHAB item
*/
LcnBindingConfig(Item item) {
this.item = item;
}
/**
* Adds a new mapping.
*
* @param mapping the mapping to add
*/
void add(Mapping mapping) {
this.mappings.add(mapping);
}
/**
* Processes received input.
*
* @param pckInput the input
* @param conn the source connection
* @param eventPublisher the {@link EventPublisher} to receive updates
*/
void processInput(Input pckInput, Connection conn, EventPublisher eventPublisher) {
for (Mapping mapping : this.mappings) {
if (pckInput.tryVisualization(mapping.getTarget(), conn, mapping.getOpenHabCmd(), this.item,
eventPublisher)) {
return; // Finish after one mapping has accepted the data
}
}
}
/**
* Sends data bound to the given openHAB command.
*
* @param conns the main {@link ConnectionManager}
* @param cmd the openHAB command to send
*/
void send(ConnectionManager conns, Command cmd) {
for (Mapping mapping : this.mappings) {
boolean ok = false;
if (mapping.getOpenHabCmd() instanceof StringType) {
if (mapping.getOpenHabCmd().toString().equals("%i") && cmd instanceof DecimalType) {
ok = true;
}
}
if (mapping.getOpenHabCmd() == cmd) {
ok = true;
}
if (ok) {
Connection conn = conns.get(mapping.getConnId());
if (conn != null && conn.isReady()) {
mapping.getTarget().send(conn, this.item, cmd);
}
}
}
}
/**
* Returns a set of LCN module addresses related to this item.
* Can be used as a filter to optimize input-processing.
*
* @return the LCN module addresses
*/
Set<LcnAddrMod> getRelatedModules() {
HashSet<LcnAddrMod> ret = new HashSet<LcnAddrMod>();
for (Mapping mapping : this.mappings) {
if (mapping.getTarget() instanceof TargetWithLcnAddr) {
LcnAddr addr = ((TargetWithLcnAddr) mapping.getTarget()).getAddr();
if (!addr.isGroup()) {
ret.add((LcnAddrMod) addr);
}
}
}
return ret;
}
/**
* Called periodically to keep the item active.
*
* @param conn the {@link Connection} to update for
*/
void update(Connection conn) {
// Allows all targets to register their status-requests
for (Mapping mapping : this.mappings) {
if (mapping.connId.equalsIgnoreCase(conn.getSets().getId())) {
// If our mapping is "brand new", it might still need its initial LCN (status) data
if (!mapping.hasInitialData()) {
for (LcnAddrMod addr : this.getRelatedModules()) {
ModInfo info = conn.getModInfo(addr);
if (info != null) { // Only reset already-existing ones
info.resetNotCachedStatusRequests();
}
}
mapping.setInitialData(true);
}
mapping.getTarget().register(conn);
}
}
}
}