/** * 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.core.scheduler; import java.text.ParseException; import java.util.Collection; import java.util.TreeSet; /** * <code>AbstractExpressionPart</code> is an abstract implementation of {@link ExpressionPart} that capture the common * functionality to all ExpressionPart implementations. * * @author Karel Goderis - Initial contribution * */ abstract class AbstractExpressionPart implements ExpressionPart { private String part; private BoundedIntegerSet valueSet; public AbstractExpressionPart(String s) throws ParseException { this.set(s); this.parse(); } @Override public void set(String s) { this.setPart(s); } /** * @return the set of values that are valid for the expression part */ public BoundedIntegerSet getValueSet() { return valueSet; } /** * @param set the set of values that the epxression part should take into consideration */ public void setValueSet(BoundedIntegerSet set) { this.valueSet = set; } abstract BoundedIntegerSet initializeValueSet(); /** * A <code>BoundedIntegerSet</code> is a set of Integers that is bound by a minimum and maximum value, that does * allow or not allow negative values, and that is either starts from index 0 or 1 * * @author Karel Goderis * */ protected class BoundedIntegerSet extends TreeSet<Integer> { private static final long serialVersionUID = 19296179649170335L; protected final int max; protected final int min; protected final boolean negative; protected boolean is1indexed; BoundedIntegerSet(final int min, final int max, final boolean negativeValuesAllowed, final boolean is1indexed) { this.min = min; this.max = max; this.negative = negativeValuesAllowed; this.is1indexed = is1indexed; } /** * Validates if an integer can be added to the set * * @param integer the integer to validate */ private void validate(final Integer integer) { if (negative) { final int abs = Math.abs(integer); if (abs < min || abs > max) { throw new IllegalArgumentException("Invalid integer value (value not in range [" + (-max) + ", " + -min + "] U [" + min + ", " + max + "])"); } } else { if (integer < min || integer > max) { throw new IllegalArgumentException( "Invalid integer value (value not in range [" + min + ", " + max + "])"); } } } @Override public boolean add(final Integer e) { validate(e); return super.add(e); } /** * Adds a series of integers to the set, starting from start, and ending at end, with a given increment * * @param start value to start at * @param end value to end at (inclusive) * @param increment increment to advance * @return true if the addition of integers was successful */ public boolean add(final Integer start, final Integer end, final Integer increment) { if (end != null && end > max) { throw new IllegalArgumentException( "Invalid integer value (end not in range [" + min + ", " + max + "])"); } if (start != null && start < min) { throw new IllegalArgumentException( "Invalid integer value (start not in range [" + min + ", " + max + "])"); } int stopAt; if (end == null) { stopAt = this.max; } else { stopAt = end; } int startAt; if (start == null) { startAt = this.min; } else { startAt = start; } boolean overflow = false; if (stopAt < startAt) { stopAt = stopAt + this.max; overflow = true; } for (int i = startAt; i <= stopAt; i += increment) { if (!overflow) { add(i); } else { int i2 = i % max; if (i2 == 0 && is1indexed) { i2 = max; } add(i2); } } return true; } @Override public boolean addAll(final Collection<? extends Integer> c) { for (Integer integer : c) { validate(integer); } return super.addAll(c); } } @Override public abstract int order(); @Override public int compareTo(ExpressionPart o) { if (this.order() < o.order()) { return -1; } else if (this.order() < o.order()) { return 1; } else { return 0; } } public String getPart() { return part; } public void setPart(String part) { this.part = part; } }