package org.openmuc.framework.driver.csv.channel;
import java.util.List;
import org.openmuc.framework.driver.csv.CsvException;
import org.openmuc.framework.driver.csv.exceptions.NoValueReceivedYetException;
import org.openmuc.framework.driver.csv.exceptions.TimeTravelException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class CsvTimeChannel implements CsvChannel {
private final static Logger LOGGER = LoggerFactory.getLogger(CsvTimeChannel.class);
/** remember index of last valid sampled value */
protected int lastReadIndex = 0;
protected int maxIndex;
protected List<String> data;
protected boolean rewind;
protected boolean isInitialised = false;
long[] timestamps;
long firstTimestamp;
long lastTimestamp;
public CsvTimeChannel(List<String> data, boolean rewind, long[] timestamps) {
this.data = data;
this.maxIndex = data.size() - 1;
this.rewind = rewind;
this.timestamps = timestamps;
this.firstTimestamp = timestamps[0];
this.lastTimestamp = timestamps[timestamps.length - 1];
}
protected int searchNextIndex(long samplingTime) throws CsvException {
int index;
if (isWithinTimeperiod(samplingTime)) {
index = handleWithinTimeperiod(samplingTime);
}
else { // is outside time period
index = handleOutsideTimeperiod(samplingTime);
}
if (!isInitialised) {
isInitialised = true;
}
return index;
}
private int handleWithinTimeperiod(long samplingTime) throws CsvException {
if (isBehindLastReadIndex(samplingTime)) {
return getIndexByRegularSearch(samplingTime);
}
else if (isBeforeLastReadIndex(samplingTime)) {
return handleBeforeLastReadIndex(samplingTime);
}
else { // is same timestamp
return lastReadIndex;
}
}
private int handleBeforeLastReadIndex(long samplingTime) throws CsvException {
if (rewind) {
rewindIndex();
return getIndexByRegularSearch(samplingTime);
}
else { // rewind disabled
throw new TimeTravelException(
"Current sampling time is before the last sampling time. Since rewind is disabled, driver can't get value for current sampling time.");
}
}
private int handleOutsideTimeperiod(long samplingTime) throws CsvException {
if (isBeforeFirstTimestamp(samplingTime)) {
return handleOutsideTimeperiodEarly(samplingTime);
}
else { // is after last timestamp
LOGGER.warn(
"Current sampling time is behind last available timestamp of csv file. Returning value corresponding to last timestamp in file.");
return maxIndex;
}
}
/**
* Search in chronological order beginning from last read index. This is the regular case since the samplingTime
* will normally increase with each read called*
*/
private int getIndexByRegularSearch(long samplingTime) {
long nextTimestamp;
int nextIndex;
do {
nextIndex = lastReadIndex + 1;
if (nextIndex > maxIndex) {
return maxIndex;
}
nextTimestamp = timestamps[nextIndex];
lastReadIndex = nextIndex;
} while (samplingTime > nextTimestamp);
if (samplingTime == nextTimestamp) {
return nextIndex;
}
else {
return nextIndex - 1;
}
}
private boolean isBeforeLastReadIndex(long samplingTime) {
if (samplingTime < timestamps[lastReadIndex]) {
return true;
}
else {
return false;
}
}
private void rewindIndex() {
lastReadIndex = 0;
}
private boolean isBehindLastReadIndex(long samplingTime) {
if (samplingTime > timestamps[lastReadIndex]) {
return true;
}
else {
return false;
}
}
private int handleOutsideTimeperiodEarly(long samplingTime) throws CsvException {
if (isInitialised) {
throw new TimeTravelException(
"Illogical time jump for sampling time. Driver can't find corresponding value in csv file.");
}
else {
throw new NoValueReceivedYetException("Sampling time before first timestamp of csv file.");
}
}
private boolean isWithinTimeperiod(long samplingTime) {
if (samplingTime >= firstTimestamp && samplingTime <= lastTimestamp) {
return true;
}
else {
return false;
}
}
private boolean isBeforeFirstTimestamp(long samplingTime) {
if (samplingTime < firstTimestamp) {
return true;
}
else {
return false;
}
}
}