org.bidib.wizard.api.model.Accessory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bidibwizard-api Show documentation
Show all versions of bidibwizard-api Show documentation
jBiDiB BiDiB Wizard API POM
package org.bidib.wizard.api.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.bidib.jbidibc.messages.AccessoryState;
import org.bidib.jbidibc.messages.AccessoryStateOptions;
import org.bidib.jbidibc.messages.BidibLibrary;
import org.bidib.jbidibc.messages.enums.AccessoryExecutionState;
import org.bidib.jbidibc.messages.enums.TimeBaseUnitEnum;
import org.bidib.jbidibc.messages.utils.AccessoryStateUtils;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.wizard.api.model.listener.AccessoryListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jgoodies.binding.beans.Model;
public class Accessory extends Model implements LabelAware, TooltipAware {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(Accessory.class);
public static final String PROPERTY_PENDING_CHANGES = "pendingChanges";
public static final String PROPERTY_TOTAL_ASPECTS_OF_ACCESSORY = "totalAspectsOfAccessory";
public static final String PROPERTY_STARTUP_STATE = "startupState";
public static final String PROPERTY_ACCESSORY_STATE = "accessoryState";
public static final String PROPERTY_ACCESSORY_EXECUTION_STATE = "accessoryExecutionState";
public static final String PROPERTY_PARA_SWITCH_TIME = "switchTime";
public static final String PROPERTY_PARA_TIME_BASE_UNIT = "timeBaseUnit";
public static final String PROPERTY_PARA_HAS_EMERGENCY_STOP = "hasEmergencyStop";
public static final String PROPERTY_PARA_USES_STRINGS = "usesStrings";
public static final String PROPERTY_PARA_OPERATION_MODE_ACCESSORY_NUMBER = "operationModeAccessoryNumber";
public static final String PROPERTY_LABEL = "label";
public static final String PROPERTYNAME_ERROR = "error";
public static final Accessory NONE = new Accessory.Builder(null)./* setLabel(""). */build();
private transient final Collection listeners = new LinkedList();
private Integer id;
private String label;
private List aspects = new ArrayList<>();
private int maxMacroMappedAspects;
private transient AccessoryExecutionState accessoryExecutionState;
private transient AccessoryState accessoryState;
private transient AccessoryStateOptions accessoryStateOptions;
private transient AccessoryErrorState accessoryErrorState;
private static enum AccessoryConfigState {
pending, initialized;
}
private static enum AccessoryErrorState {
valid, error;
}
/**
* The accessory startup state
*/
private Integer startupState;
/**
* The accessory switch time
*/
private Integer switchTime;
/**
* The accessory switch time bas unit
*/
private TimeBaseUnitEnum timeBaseUnit = TimeBaseUnitEnum.UNIT_100MS;
/**
* The accessory supports emergency stop para
*/
private Boolean hasEmergencyStop;
/**
* The accessory supports uses strings para
*/
private Boolean usesStrings = Boolean.FALSE;
/**
* The accessory number of the operation mode accessory
*/
private Integer operationModeAccessoryNumber;
private int totalAspects;
private transient AccessoryConfigState accessoryConfigState = AccessoryConfigState.pending;
private transient AccessorySaveState accessorySaveState = AccessorySaveState.PENDING_CHANGES;
private transient boolean editable = true;
public Accessory() {
}
private Accessory(Builder builder) {
setId(builder.id);
setLabel(builder.label);
}
public void addAccessoryListener(AccessoryListener l) {
listeners.add(l);
}
public void removeAccessoryListener(AccessoryListener l) {
listeners.remove(l);
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String getLabel() {
return label;
}
@Override
public void setLabel(String label) {
String oldValue = this.label;
this.label = label;
firePropertyChange(PROPERTY_LABEL, oldValue, label);
}
public void addAspect(MacroRef macro) {
addAspect(aspects.size(), macro);
}
/**
* Add aspect at provided index.
*
* @param index
* the index
* @param macroRef
* the macro mapped aspect
* @return {@code true} add was successful, {@code false} add failed
*/
private boolean addAspect(int index, MacroRef macroRef) {
boolean result = false;
if (macroRef != null && index >= 0 && aspects.size() < maxMacroMappedAspects) {
aspects.add(index, macroRef);
totalAspects = aspects.size();
fireMacrosChanged();
result = true;
}
else {
LOGGER
.warn("This macro is not added because the maximum macro size is reached, index: {}, macroRef: {}",
index, macroRef);
}
return result;
}
public void addAspectAfter(int index, MacroRef macro) {
addAspect(index + 1, macro);
}
public void addAspectsAfter(int index, MacroRef[] macros) {
LOGGER.debug("Add aspects after, index: {}, macros: {}", index, macros);
if (macros != null) {
for (MacroRef macro : macros) {
index++;
addAspect(index, macro);
}
}
}
public void addAspectBefore(int index, MacroRef macro) {
addAspect(index, macro);
}
public void clearAspects() {
aspects.clear();
totalAspects = aspects.size();
fireMacrosChanged();
}
public int getAspectCount() {
return aspects.size();
}
/**
* @return the aspects of the accessory
*/
public List getAspects() {
return Collections.unmodifiableList(aspects);
}
/**
* Set the aspects.
*
* @param aspects
* the aspects
*/
public void setAspects(List aspects) {
this.aspects.clear();
this.aspects.addAll(aspects);
}
/**
* Remove aspect at index.
*
* @param index
* the index
* @return the removed apect
*/
public MacroRef removeAspect(int index) {
MacroRef aspect = aspects.remove(index);
totalAspects = aspects.size();
fireMacrosChanged();
return aspect;
}
/**
* Set the aspect at the provided index.
*
* @param index
* the index
* @param macroId
* the mapped macro id
*/
public void replaceAspectMacro(int index, int macroId) {
MacroRef aspect = aspects.get(index);
if (aspect != null) {
aspect.setId(macroId);
LOGGER.info("Replaced macro on aspect: {}, index: {}", aspect, index);
}
else {
aspect = new MacroRef(macroId);
LOGGER.info("Add new macro-mapped aspect: {}, index: {}", aspect, index);
aspects.set(index, aspect);
}
fireMacrosChanged();
}
/**
* @return the maximum number of macro-mapped accessories available for this accessory.
*/
public int getMaximumMacroMappedAspects() {
return maxMacroMappedAspects;
}
/**
* Set the maximum number of aspects == macros that can be stored in an accessory.
*
* @param maxMacroMappedAspects
* the maximum number of macro-mapped aspects for this accessory
*/
public void setMaximumMacroMappedAspects(int maxMacroMappedAspects) {
this.maxMacroMappedAspects = maxMacroMappedAspects;
// if (this.aspects.size() > maxMacroMappedAspects) {
// this.aspects.setSize(maxMacroMappedAspects);
// }
}
/**
* @return the accessory supports macro-mapped aspects.
*/
public boolean isMacroMapped() {
return (maxMacroMappedAspects > 0);
}
/**
* @return the startupState
*/
public Integer getStartupState() {
return startupState;
}
/**
* @param startupState
* the startupState to set
*/
public void setStartupState(Integer startupState) {
Integer oldValue = this.startupState;
this.startupState = startupState;
firePropertyChange(PROPERTY_STARTUP_STATE, oldValue, startupState);
if (!Objects.equals(oldValue, startupState)) {
firePendingChanges();
}
}
/**
* @return the switchTime
*/
public Integer getSwitchTime() {
return switchTime;
}
/**
* @param switchTime
* the switchTime to set
*/
public void setSwitchTime(Integer switchTime) {
Integer oldValue = this.switchTime;
this.switchTime = switchTime;
firePropertyChange(PROPERTY_PARA_SWITCH_TIME, oldValue, switchTime);
if (!Objects.equals(oldValue, switchTime)) {
firePendingChanges();
}
}
/**
* @return the timeBaseUnit
*/
public TimeBaseUnitEnum getTimeBaseUnit() {
return timeBaseUnit;
}
/**
* @param timeBaseUnit
* the timeBaseUnit to set
*/
public void setTimeBaseUnit(TimeBaseUnitEnum timeBaseUnit) {
TimeBaseUnitEnum oldValue = this.timeBaseUnit;
this.timeBaseUnit = timeBaseUnit;
firePropertyChange(PROPERTY_PARA_TIME_BASE_UNIT, oldValue, timeBaseUnit);
if (!Objects.equals(oldValue, timeBaseUnit)) {
firePendingChanges();
}
}
private void firePendingChanges() {
setAccessorySaveState(AccessorySaveState.PENDING_CHANGES);
}
/**
* @return the hasEmergencyStop
*/
public Boolean isHasEmergencyStop() {
return hasEmergencyStop;
}
/**
* @param hasEmergencyStop
* the hasEmergencyStop to set
*/
public void setHasEmergencyStop(Boolean hasEmergencyStop) {
Boolean oldValue = this.hasEmergencyStop;
this.hasEmergencyStop = hasEmergencyStop;
firePropertyChange(PROPERTY_PARA_HAS_EMERGENCY_STOP, oldValue, hasEmergencyStop);
}
/**
* @return the usesStrings
*/
public Boolean isUsesStrings() {
return usesStrings;
}
/**
* @param usesStrings
* the usesStrings to set
*/
public void setUsesStrings(Boolean usesStrings) {
Boolean oldValue = this.usesStrings;
this.usesStrings = usesStrings;
firePropertyChange(PROPERTY_PARA_USES_STRINGS, oldValue, usesStrings);
}
/**
* @return the operationModeAccessoryNumber
*/
public Integer getOperationModeAccessoryNumber() {
return operationModeAccessoryNumber;
}
/**
* @param operationModeAccessoryNumber
* the operationModeAccessoryNumber to set
*/
public void setOperationModeAccessoryNumber(Integer operationModeAccessoryNumber) {
Integer oldValue = this.operationModeAccessoryNumber;
this.operationModeAccessoryNumber = operationModeAccessoryNumber;
firePropertyChange(PROPERTY_PARA_OPERATION_MODE_ACCESSORY_NUMBER, oldValue, operationModeAccessoryNumber);
}
/**
* @return the totalAspects
*/
public int getTotalAspects() {
return totalAspects;
}
/**
* Set the total number of aspects for this accessory. The total number is only relevant for accessories that do not
* support macro mapped aspects. In case of macro-mapped aspects the maximum number of aspects is relevant.
*
* @param totalAspects
* the totalAspects to set
*/
public void setTotalAspects(int totalAspects) {
LOGGER.info("Set total number of aspects: {}", totalAspects);
if (this.totalAspects != totalAspects) {
this.totalAspects = totalAspects;
if (!isMacroMapped()) {
// signal the total number of aspects has changed
fireTotalAspectsChanged(id);
}
}
}
public AccessoryExecutionState getAccessoryExecutionState() {
return accessoryExecutionState;
}
public void setAccessoryExecutionState(final AccessoryExecutionState accessoryExecutionState, Integer aspect) {
LOGGER.info("Set the new accessoryExecutionState: {}", accessoryExecutionState);
AccessoryExecutionState oldAccessoryExecutionState = this.accessoryExecutionState;
this.accessoryExecutionState = accessoryExecutionState;
firePropertyChange(PROPERTY_ACCESSORY_EXECUTION_STATE, oldAccessoryExecutionState, accessoryExecutionState);
fireAccessoryStateChanged(aspect);
}
public void setAccessoryState(
final AccessoryState accessoryState, final AccessoryStateOptions accessoryStateOptions) {
LOGGER.info("Set the new accessoryState: {}, accessoryStateOptions: {}", accessoryState, accessoryStateOptions);
// update the accessory state
AccessoryState oldAccessoryState = this.accessoryState;
this.accessoryState = accessoryState;
firePropertyChange(PROPERTY_ACCESSORY_STATE, oldAccessoryState, accessoryState);
this.accessoryStateOptions = accessoryStateOptions;
if (AccessoryConfigState.pending.equals(accessoryConfigState)) {
LOGGER.info("The initial AccessoryState is delivered: {}", accessoryState);
setTotalAspects(ByteUtils.getInt(accessoryState.getTotal()));
accessoryConfigState = AccessoryConfigState.initialized;
}
else if (!isMacroMapped()) {
LOGGER
.info(
"The accessory is already initialized but not macro mapped. Check if we need to update the total aspect count.");
setTotalAspects(ByteUtils.getInt(accessoryState.getTotal()));
}
else {
LOGGER.info("The accessory is already initialized, do not update the total aspect count.");
}
final org.bidib.jbidibc.messages.logger.Logger logger = new org.bidib.jbidibc.messages.logger.Logger() {
@Override
public void warn(String format, Object... arguments) {
LOGGER.warn(format, arguments);
}
@Override
public void info(String format, Object... arguments) {
LOGGER.info(format, arguments);
}
@Override
public void debug(String format, Object... arguments) {
LOGGER.debug(format, arguments);
}
@Override
public void error(String format, Object... arguments) {
LOGGER.error(format, arguments);
}
};
AccessoryExecutionState accessoryExecutionState =
AccessoryStateUtils
.getExecutionState(accessoryState.getActiveAspect(), accessoryState.getExecute(), logger);
LOGGER
.debug("Set the new accessoryState: {}, accessoryExecutionState: {}", accessoryState,
accessoryExecutionState);
// prevent send state changed twice
// LOGGER.info("Set the new accessoryExecutionState: {}", accessoryExecutionState);
// this.accessoryExecutionState = accessoryExecutionState;
setAccessoryExecutionState(accessoryExecutionState, accessoryState.getActiveAspect());
}
public AccessoryState getAccessoryState() {
return accessoryState;
}
public AccessoryStateOptions getAccessoryStateOptions() {
return accessoryStateOptions;
}
public boolean hasExecutionStateError() {
return AccessoryExecutionState.ERROR == accessoryExecutionState;
}
public boolean hasError() {
return AccessoryErrorState.error.equals(accessoryErrorState);
}
public void setError(boolean error) {
boolean oldValue = hasError();
if (error) {
accessoryErrorState = AccessoryErrorState.error;
}
else {
accessoryErrorState = AccessoryErrorState.valid;
}
firePropertyChange(PROPERTYNAME_ERROR, oldValue, hasError());
}
private void fireMacrosChanged() {
// setPendingChanges(true);
setAccessorySaveState(AccessorySaveState.PENDING_CHANGES);
for (AccessoryListener l : listeners) {
l.macrosChanged();
}
}
private void fireAccessoryStateChanged(final Integer aspect) {
for (AccessoryListener l : listeners) {
l.accessoryStateChanged(getId(), aspect);
}
}
private void fireTotalAspectsChanged(final Integer accessoryId) {
LOGGER.info("Fire total number of aspects changed of accessory id: {}", accessoryId);
firePropertyChange(PROPERTY_TOTAL_ASPECTS_OF_ACCESSORY, null, accessoryId);
}
/**
* @return the accessorySaveState
*/
public AccessorySaveState getAccessorySaveState() {
return accessorySaveState;
}
/**
* @param accessorySaveState
* the accessorySaveState to set
*/
public void setAccessorySaveState(AccessorySaveState accessorySaveState) {
AccessorySaveState oldValue = this.accessorySaveState;
this.accessorySaveState = accessorySaveState;
firePropertyChange(PROPERTY_PENDING_CHANGES, oldValue, this.accessorySaveState);
}
/**
* @return the editable
*/
public boolean isEditable() {
return editable;
}
/**
* @param editable
* the editable to set
*/
public void setEditable(boolean editable) {
this.editable = editable;
}
@Override
public String getTooltipKey() {
String tootip = null;
switch (accessorySaveState) {
case PENDING_CHANGES:
tootip = "pending-changes";
break;
case PERMANENTLY_STORED_ON_NODE:
tootip = "permanently-stored-on-node";
break;
default:
LOGGER.error("Unknown accessory save state detected: {}", accessorySaveState);
break;
}
return tootip;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Accessory) {
return ((Accessory) obj).getId() == getId();
}
return false;
}
@Override
public int hashCode() {
return getId();
}
public String getDebugString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb
.append("[id=").append(id).append(",label=").append(label).append(",macros=").append(aspects)
.append(",macroSize=").append(maxMacroMappedAspects).append(",startup=").append(startupState).append("]");
return sb.toString();
}
@Override
public String toString() {
String result = null;
if (StringUtils.isNotBlank(label)) {
result = label;
}
return result;
}
public static class Builder {
private final Integer id;
private String label;
public Builder(Integer id) {
this.id = id;
}
public Builder setLabel(String label) {
this.label = label;
return this;
}
public Accessory build() {
return new Accessory(this);
}
}
public static Accessory cloneAccessoryData(final Accessory accessory) {
// create a clone of the accessory
final Accessory accessoryClone = new Accessory();
accessoryClone.setId(accessory.getId());
accessoryClone.setLabel(accessory.getLabel());
accessoryClone.setMaximumMacroMappedAspects(accessory.getMaximumMacroMappedAspects());
if (CollectionUtils.isNotEmpty(accessory.getAspects())) {
MacroRef[] aspects = accessory.getAspects().toArray(new MacroRef[0]);
LOGGER.debug("Current aspects: {}", new Object[] { aspects });
accessoryClone.setAspects(Arrays.asList(aspects));
}
accessoryClone.setStartupState(accessory.getStartupState());
accessoryClone.setSwitchTime(accessory.getSwitchTime());
accessoryClone.setTimeBaseUnit(accessory.getTimeBaseUnit());
return accessoryClone;
}
/**
* Initialize the accessory with default values.
*/
public void initialize() {
clearAspects();
setStartupState(BidibLibrary.ASPECT_PARAM_UNCHANGED);
setError(false);
}
/**
* Get the accessory param.
*
* @param paramNumber
* the param number
*/
public int[] getParam(int paramNumber) {
int[] paramValue = null;
try {
switch (paramNumber) {
case BidibLibrary.BIDIB_ACCESSORY_PARA_USES_STRINGS:
if (isUsesStrings() != null) {
paramValue = new int[] { isUsesStrings() != null && isUsesStrings().booleanValue() ? 1 : 0 };
}
else {
paramValue = new int[0];
}
break;
case BidibLibrary.BIDIB_ACCESSORY_PARA_HAS_ESTOP:
if (isHasEmergencyStop() != null) {
paramValue =
new int[] { isHasEmergencyStop() != null && isHasEmergencyStop().booleanValue() ? 1 : 0 };
}
else {
paramValue = new int[0];
}
break;
case BidibLibrary.BIDIB_ACCESSORY_PARA_OPMODE:
if (getOperationModeAccessoryNumber() != null) {
paramValue = new int[] { getOperationModeAccessoryNumber().intValue() };
}
else {
paramValue = new int[0];
}
break;
case BidibLibrary.BIDIB_ACCESSORY_PARA_STARTUP:
if (getStartupState() != null) {
paramValue = new int[] { getStartupState() };
}
else {
paramValue = new int[0];
}
break;
case BidibLibrary.BIDIB_ACCESSORY_SWITCH_TIME:
if (getTimeBaseUnit() != null && getSwitchTime() != null) {
int timeBaseUnit = ByteUtils.getInt(getTimeBaseUnit().getType());
paramValue = new int[] { getSwitchTime() | (timeBaseUnit << 7) };
LOGGER.info("Current accessory switch time: {}", paramValue[0]);
}
else {
paramValue = new int[0];
}
break;
case BidibLibrary.BIDIB_ACCESSORY_PARA_MACROMAP:
if (aspects != null && aspects.size() > 0) {
List assignedAspects =
aspects.stream().filter(a -> a != null && a.getId() != null).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(assignedAspects)) {
paramValue = new int[assignedAspects.size()];
int index = 0;
for (MacroRef macroRef : assignedAspects) {
paramValue[index] = macroRef.getId();
index++;
}
}
}
else {
paramValue = new int[0];
}
break;
default:
LOGGER.warn("Unknown paramNumber: {}", paramNumber);
paramValue = new int[0];
break;
}
}
catch (Exception ex) {
LOGGER.warn("Get the accessory param failed, paramNumber: {}", paramNumber, ex);
}
return paramValue;
}
}