/*
* Licensed Materials - Property of Rogue Wave Software, Inc.
* © Copyright Rogue Wave Software, Inc. 2014, 2017
* © Copyright IBM Corp. 2009, 2014
* © Copyright ILOG 1996, 2009
* All Rights Reserved.
*
* Note to U.S. Government Users Restricted Rights:
* The Software and Documentation were developed at private expense and
* are "Commercial Items" as that term is defined at 48 CFR 2.101,
* consisting of "Commercial Computer Software" and
* "Commercial Computer Software Documentation", as such terms are
* used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
* as applicable.
*/
package shared;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.zip.DataFormatException;
import ilog.views.chart.data.IlvDataReader;
import ilog.views.chart.data.IlvDataSet;
import ilog.views.chart.data.IlvDefaultDataSet;
import ilog.views.chart.util.IlvDoubleArray;
/**
* A reader that reads quote values in CSV format.
*/
public class CSVDataReader implements IlvDataReader {
private boolean reverse;
static class Properties {
String dataFile;
String dateFomat;
boolean transposed;
}
/**
* Initializes a new reader.
*/
public CSVDataReader() {
this(false);
}
/**
* Initializes a new reader, specifying whether the read values should be
* reversed.
*/
public CSVDataReader(boolean reverse) {
this.reverse = reverse;
}
static int QUOTE_CHAR = '"';
private StreamTokenizer createTokenizer(Reader reader) {
StreamTokenizer st = new StreamTokenizer(reader);
st.quoteChar(QUOTE_CHAR);
st.ordinaryChar(',');
st.wordChars('-', '-');
st.eolIsSignificant(true);
st.whitespaceChars(0, 32);
return st;
}
/**
* Returns a <code>Reader</code> object on the specified
* <code>InputStream</code>.
*/
protected Reader makeReader(InputStream in) throws MalformedURLException, IOException {
Reader res = new InputStreamReader(in);
if (!(in instanceof BufferedInputStream))
res = new BufferedReader(res);
return res;
}
/**
* Loads data from the given <code>InputStream</code>.
*
* @return An array containing the data sets.
* @throws ParseException
* Parsing a date failed.
* @throws NumberFormatException
* Parsing a date failed.
* @throws DataFormatException
* The file is not a valid Yahoo CSV format; this exception is
* thrown when a line is being parsed and something other than a
* number has been read.
* @throws IOException
* Opening (in the case of a URL) or reading the input stream
* failed.
*/
Override
public IlvDataSet[] read(InputStream in)
throws ParseException, NumberFormatException, DataFormatException, IOException {
Reader reader = makeReader(in);
StreamTokenizer st = createTokenizer(reader);
boolean xDateSeries = false;
List<String> seriesNames = readColumnHeaders(st);
IlvDoubleArray[] values = new IlvDoubleArray[seriesNames.size()];
int seriesCount = values.length;
for (int i = 0; i < seriesCount; ++i) {
values[i] = new IlvDoubleArray();
}
int i = 0;
// == Recover the date.
xDateSeries = true;
DateFormat dateFormat = new SimpleDateFormat("dd-MMMM-yy", Locale.ENGLISH);
Date date, minDate = new Date(0), maxDate = new Date(Long.MAX_VALUE);
List<Date> dates = new ArrayList<Date>();
// Skip column names.
int tok = st.nextToken();
StringBuffer dateBuffer = new StringBuffer();
while (tok != StreamTokenizer.TT_EOF) {
if (tok == ',') {
++i;
} else if (tok == StreamTokenizer.TT_EOL) {
i = 0;
} else {
if ((i == 0) && xDateSeries) {
if (tok == StreamTokenizer.TT_NUMBER) {
dateBuffer.append(Integer.toString((int) st.nval));
dateBuffer.append("-");
} else if (tok == StreamTokenizer.TT_WORD) {
dateBuffer.append(st.sval);
}
if (dateBuffer.length() > 3) {
date = dateFormat.parse(dateBuffer.toString());
dates.add(date);
values[0].add(date.getTime());
if (date.before(minDate))
minDate = date;
else if (date.after(maxDate))
maxDate = date;
dateBuffer.delete(0, 9);
}
} else if (tok == StreamTokenizer.TT_NUMBER) {
values[i].add(st.nval);
} else
throw new DataFormatException("Expected number at line " + st.lineno());
}
tok = st.nextToken();
}
String[] names = new String[seriesCount - 1];
double[][] data = new double[seriesCount][];
for (int j = 0; j < seriesCount; ++j) {
if (this.reverse)
values[j].reverse();
values[j].trim();
data[j] = values[j].data();
if (j > 0)
names[j - 1] = seriesNames.get(j);
}
return IlvDefaultDataSet.create(data, 0, names, null);
}
/**
* Loads data from the given URL.
*/
Override
public IlvDataSet[] read(String url) throws ParseException, NumberFormatException, DataFormatException, IOException {
InputStream in = new BufferedInputStream(new URL(url).openStream());
IlvDataSet[] dataSets = read(in);
in.close();
return dataSets;
}
private List<String> readColumnHeaders(StreamTokenizer st) throws IOException, DataFormatException {
List<String> names = new ArrayList<String>();
while (st.nextToken() != StreamTokenizer.TT_EOL) {
if (st.ttype == StreamTokenizer.TT_WORD) {
names.add(st.sval);
if (st.nextToken() == StreamTokenizer.TT_EOL)
break;
} else
throw new DataFormatException("Expected word at line : " + st.lineno());
}
return names;
}
}