/**
* 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.astro.internal.bus;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.astro.internal.common.AstroContext;
import org.openhab.binding.astro.internal.config.AstroBindingConfig;
import org.openhab.binding.astro.internal.model.PlanetName;
import org.openhab.binding.astro.internal.util.PropertyUtils;
import org.openhab.core.items.Item;
import org.openhab.model.item.binding.BindingConfigParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to parse the key - value base config for an Astro item.
* <p>
* Example:
* </p>
*
* <pre>
* Number Azimuth "Azimuth [%.2f]" {astro="planet=sun, type=position, property=azimuth"}
* Number Elevation "Elevation [%.2f]" {astro="planet=sun, type=position, property=elevation"}
*
* DateTime Sunrise_Time "Sunrise [%1$tH:%1$tM]" {astro="planet=sun, type=rise, property=start"}
* DateTime Noon_Time "Noon [%1$tH:%1$tM]" {astro="planet=sun, type=noon, property=start"}
* DateTime Sunset_Time "Sunset [%1$tH:%1$tM]" {astro="planet=sun, type=set, property=end"}
*
* Switch Sunrise_Event {astro="planet=sun, type=rise, property=start"}
* Switch Sunrise_Event_Delayed {astro="planet=sun, type=rise, property=start, offset=10"}
* Switch Noon_Event {astro="planet=sun, type=noon, property=start"}
* Switch Sunset_Event {astro="planet=sun, type=set, property=end"}
*
* Number Sunset_Duration {astro="planet=sun, type=set, property=duration"}
* String Sunset_Duration_Str {astro="planet=sun, type=set, property=duration"}
* </pre>
*
* @author Gerhard Riegler
* @since 1.5.0
*/
public class BindingConfigParser {
private static final Logger logger = LoggerFactory.getLogger(BindingConfigParser.class);
protected AstroContext context = AstroContext.getInstance();
/**
* Parses the bindingConfig of an item and returns a AstroBindingConfig.
*/
public AstroBindingConfig parse(Item item, String bindingConfig) throws BindingConfigParseException {
bindingConfig = StringUtils.trimToEmpty(bindingConfig);
bindingConfig = StringUtils.removeStart(bindingConfig, "{");
bindingConfig = StringUtils.removeEnd(bindingConfig, "}");
String[] entries = bindingConfig.split("[,]");
AstroBindingConfigHelper helper = new AstroBindingConfigHelper();
for (String entry : entries) {
String[] entryParts = StringUtils.trimToEmpty(entry).split("[=]");
if (entryParts.length != 2) {
throw new BindingConfigParseException("A bindingConfig must have a key and a value");
}
String key = StringUtils.trim(entryParts[0]);
String value = StringUtils.trim(entryParts[1]);
value = StringUtils.removeStart(value, "\"");
value = StringUtils.removeEnd(value, "\"");
try {
if ("offset".equalsIgnoreCase(key)) {
helper.getClass().getDeclaredField(key).set(helper, Integer.valueOf(value.toString()));
} else {
helper.getClass().getDeclaredField(key).set(helper, value);
}
} catch (Exception e) {
throw new BindingConfigParseException("Could not set value " + value + " for attribute " + key);
}
}
if (helper.isOldStyle()) {
logger.warn(
"Old Astro binding style for item {}, please see Wiki page for new style: https://github.com/openhab/openhab/wiki/Astro-binding",
item.getName());
return getOldAstroBindingConfig(helper);
}
if (!helper.isValid()) {
throw new BindingConfigParseException("Invalid binding: " + bindingConfig);
}
PlanetName planetName = getPlanetName(helper);
if (planetName == null) {
throw new BindingConfigParseException("Invalid binding, unknown planet: " + bindingConfig);
}
AstroBindingConfig astroConfig = new AstroBindingConfig(planetName, helper.type, helper.property,
helper.offset);
if (!PropertyUtils.hasProperty(context.getPlanet(astroConfig.getPlanetName()),
astroConfig.getPlanetProperty())) {
throw new BindingConfigParseException("Invalid binding, unknown type or property: " + bindingConfig);
}
return astroConfig;
}
/**
* Parses the planet name.
*/
private PlanetName getPlanetName(AstroBindingConfigHelper helper) {
try {
return PlanetName.valueOf(StringUtils.upperCase(helper.planet));
} catch (Exception ex) {
return null;
}
}
/**
* Returns the AstroBindingConfig for old binding style.
*/
private AstroBindingConfig getOldAstroBindingConfig(AstroBindingConfigHelper helper) {
String type = helper.type.toUpperCase();
if ("AZIMUTH".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "position", "azimuth");
} else if ("ELEVATION".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "position", "elevation");
} else if ("SUNRISE".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "rise", "start");
} else if ("NOON".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "noon", "start");
} else if ("SUNSET".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "set", "end");
} else if ("SUNRISE_TIME".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "rise", "start");
} else if ("NOON_TIME".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "noon", "start");
} else if ("SUNSET_TIME".equals(type)) {
return new AstroBindingConfig(PlanetName.SUN, "set", "end");
}
return null;
}
/**
* Helper class for parsing the bindingConfig.
*/
private class AstroBindingConfigHelper {
public String planet;
public String type;
public String property;
public int offset = 0;
protected boolean isValid() {
return StringUtils.isNotBlank(planet) && StringUtils.isNotBlank(type) && StringUtils.isNotBlank(property);
}
protected boolean isOldStyle() {
return StringUtils.isNotBlank(type) && StringUtils.isBlank(planet) && StringUtils.isBlank(property);
}
}
}