package de.ptb.epics.eve.util.math.range;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Marcus Michalsky
 * @since 1.28
 */
public class BigDecimalRange extends Range<BigDecimal> {

	public BigDecimalRange(String expression) {
		if (expression.split("/").length == 1) {
			// expression is either j:i:k or j:k
			if (expression.split(":").length == 2) {
				// expressions is j:k
				String[] jk = expression.split(":");
				this.from = new BigDecimal(jk[0]);
				this.step = new BigDecimal("1.0");
				this.to = new BigDecimal(jk[1]);
			} else {
				// expression is j:i:k
				String[] jik = expression.split(":");
				this.from = new BigDecimal(jik[0]);
				this.step = new BigDecimal(jik[1]);
				this.to = new BigDecimal(jik[2]);
			}
		} else {
			// expression is j:k/N
			String[] jkN = expression.split("/");
			BigDecimal n = new BigDecimal(jkN[1]);
			String[] jk = jkN[0].split(":");
			this.from = new BigDecimal(jk[0]);
			this.to = new BigDecimal(jk[1]);
			if (from.compareTo(to) < 0) {
				this.step = to.subtract(from).divide(n);
			} else {
				this.step = from.subtract(to).divide(n, RoundingMode.HALF_UP);
			}
		}
		if (this.isInfinite()) {
			this.negateStepwidth();
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<BigDecimal> getValues() {
		List<BigDecimal> values = new ArrayList<>();
		if (step.compareTo(BigDecimal.ZERO) == 0) {
			if (from.compareTo(to) == 0) {
				values.add(from);
			} else {
				values.add(from);
				values.add(to);
			}
			return values;
		}
		values.add(from);
		BigDecimal d = from.plus();
		if (from.compareTo(to) < 0) {
			while (d.add(step).compareTo(to) < 1) {
				values.add(d.add(step));
				d = d.add(step);
			}
		} else if (from.compareTo(to) >= 0) {
			while (d.subtract(step).compareTo(to) > -1) {
				values.add(d.subtract(step));
				d = d.subtract(step);
			}
		}
		if (values.get(values.size()-1).compareTo(to) != 0) {
			values.add(to);
		}
		return values;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected boolean isInfinite() {
		return ((this.from.compareTo(this.to) < 0 && 
				this.from.add(this.step).compareTo(this.from) < 0)
			|| (this.from.compareTo(this.to) > 0 &&
				this.from.subtract(this.step).compareTo(this.from) > 0));
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void negateStepwidth() {
		this.step = this.step.negate();
	}
}
@@ -65,16 +65,46 @@
 ecimal;%0A
+import java.math.MathContext;%0A
 import j
@@ -126,16 +126,16 @@
 ngMode;%0A
-
 import j
@@ -178,16 +178,49 @@
 .List;%0A%0A
+import org.apache.log4j.Logger;%0A%0A
 /**%0A * @
@@ -319,16 +319,110 @@
 imal%3E %7B%0A
+%09private static final Logger LOGGER = Logger.getLogger(%0A%09%09%09BigDecimalRange.class.getName());%0A%09
 %0A%09public
@@ -1202,16 +1202,26 @@
 jk%5B1%5D);%0A
+%09%09%09try %7B%0A%09
 %09%09%09if (f
@@ -1245,24 +1245,25 @@
  %3C 0) %7B%0A%09%09%09%09
+%09
 this.step = 
@@ -1290,24 +1290,25 @@
 vide(n);%0A%09%09%09
+%09
 %7D else %7B%0A%09%09%09
@@ -1300,24 +1300,25 @@
 %09%09%09%7D else %7B%0A
+%09
 %09%09%09%09this.ste
@@ -1372,16 +1372,297 @@
 LF_UP);%0A
+%09%09%09%09%7D%0A%09%09%09%7D catch(ArithmeticException e) %7B%0A%09%09%09%09LOGGER.warn(e.getMessage() + %22, rounding%22);%0A%09%09%09%09if (from.compareTo(to) %3C 0) %7B%0A%09%09%09%09%09this.step = to.subtract(from).divide(n, MathContext.DECIMAL64);%0A%09%09%09%09%7D else %7B%0A%09%09%09%09%09this.step = from.subtract(to).divide(n, MathContext.DECIMAL64);%0A%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%7D

round decimal if no exact representation possible