/**
* Copyright (c) 2010-2016, openHAB.org and others.
*
* 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.fatekplc.items;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.fatekplc.internal.FatekPLCActivator;
import org.openhab.core.items.Item;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.transform.TransformationException;
import org.openhab.core.transform.TransformationHelper;
import org.openhab.core.transform.TransformationService;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.model.item.binding.BindingConfigParseException;
import org.simplify4u.jfatek.FatekException;
import org.simplify4u.jfatek.FatekPLC;
import org.simplify4u.jfatek.FatekWriteMixDataCmd;
import org.simplify4u.jfatek.io.FatekIOException;
import org.simplify4u.jfatek.registers.Reg;
import org.simplify4u.jfatek.registers.RegValue;
import org.simplify4u.jfatek.registers.UnknownRegNameException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Number item implementation.
*
* @author Slawomir Jaranowski
* @since 1.9.0
*/
public class FatekNumberItem extends FatekPLCItem {
private static final Pattern TRANSFORMATION_CONFIG_PATTERN = Pattern.compile("([A-Z]+)\\((.+)\\)");
private static final Logger logger = LoggerFactory.getLogger(FatekNumberItem.class);
private boolean signed = true;
private boolean floatValue = false;
private String transType = null;
private String transFunc = null;
private BigDecimal factor = null;
public FatekNumberItem(Item item, List<String> confItems) throws BindingConfigParseException {
super(item, confItems);
String sFactor = getParamsFromConf(confItems, "factor", null);
if (sFactor != null) {
factor = new BigDecimal(sFactor);
}
// try to find transformation configuration
parseForTransformation(confItems);
if (confItems.size() != 1) {
throw new BindingConfigParseException("Incorrect binding for number item");
}
String regName = confItems.get(0);
if (regName.startsWith("+")) {
signed = false;
regName = regName.substring(1);
}
if (regName.endsWith("F")) {
floatValue = true;
regName = regName.substring(0, regName.length() - 1);
}
try {
reg1 = Reg.parse(regName);
} catch (UnknownRegNameException e) {
throw new BindingConfigParseException(e.getMessage());
}
}
/**
* Parse transformation config for item.
*
* @param confItems
* config list
*/
private void parseForTransformation(List<String> confItems) {
for (Iterator<String> iterator = confItems.iterator(); iterator.hasNext();) {
String conf = iterator.next();
Matcher matcher = TRANSFORMATION_CONFIG_PATTERN.matcher(conf);
if (matcher.find()) {
transType = matcher.group(1);
transFunc = matcher.group(2);
iterator.remove();
return;
}
}
}
@Override
public State getState(Map<Reg, RegValue> response) {
BigDecimal val;
if (floatValue) {
val = new BigDecimal(response.get(reg1).floatValue());
} else {
long longVal;
if (signed) {
longVal = response.get(reg1).longValue();
} else {
longVal = response.get(reg1).longValueUnsigned();
}
val = new BigDecimal(longVal);
}
if (factor != null) {
val = factor.multiply(val);
}
if (transType != null) {
return getStateWithTransformation(val);
} else {
return new DecimalType(val);
}
}
private State getStateWithTransformation(BigDecimal val) {
TransformationService transformationService = TransformationHelper.getTransformationService(
FatekPLCActivator.getContext(), transType);
String strVal = String.valueOf(val);
String transOut;
if (transformationService != null) {
try {
transOut = transformationService.transform(transFunc, strVal);
logger.debug("transOut={}", transOut);
} catch (TransformationException e) {
transOut = null;
logger.warn("Transformation error: {}", e.getMessage());
}
} else {
transOut = null;
logger.warn("No transformation service for: {}", transType);
}
if (transOut != null && !"null".equals(transOut)) {
strVal = transOut;
}
return new DecimalType(strVal);
}
@Override
public void command(FatekPLC fatekPLC, Command command) throws CommandException {
if (command instanceof DecimalType) {
BigDecimal val = ((DecimalType) command).toBigDecimal();
if (factor != null) {
val = val.divide(factor);
}
try {
FatekWriteMixDataCmd cmd = new FatekWriteMixDataCmd(fatekPLC);
if (floatValue) {
cmd.addReg(reg1, val.floatValue());
} else {
cmd.addReg(reg1, val.longValue());
}
cmd.send();
} catch (FatekIOException | FatekException e) {
throw new CommandException(this, command, e);
}
} else {
throw new UnsupportedCommandException(this, command);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (!signed) {
sb.append(", unsign(+)");
}
if (floatValue) {
sb.append(", float");
}
if (factor != null) {
sb.append(", factor=").append(factor);
}
if (transType != null) {
sb.append(", trans=").append(transType).append("(").append(transFunc).append(")");
}
return toString(sb);
}
}