/*
* Copyright (c) 2013 Villu Ruusmann
*
* This file is part of Openscoring
*
* Openscoring is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Openscoring is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Openscoring. If not, see <http://www.gnu.org/licenses/>.
*/
package org.openscoring.service;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openscoring.common.EvaluationRequest;
import org.openscoring.common.EvaluationResponse;
import org.supercsv.encoder.DefaultCsvEncoder;
import org.supercsv.io.CsvListReader;
import org.supercsv.io.CsvMapReader;
import org.supercsv.io.CsvMapWriter;
import org.supercsv.prefs.CsvPreference;
public class CsvUtil {
private CsvUtil(){
}
static
public CsvPreference getFormat(String delimiterChar, String quoteChar){
char delimiter = ',';
char quote = '\"';
if(delimiterChar != null){
delimiterChar = decodeDelimiter(delimiterChar);
if(delimiterChar.length() != 1){
throw new IllegalArgumentException("Invalid CSV delimiter character: \"" + delimiterChar + "\"");
}
delimiter = delimiterChar.charAt(0);
} // End if
if(quoteChar != null){
quoteChar = decodeQuote(quoteChar);
if(quoteChar.length() != 1){
throw new IllegalArgumentException("Invalid CSV quote character: \"" + quoteChar + "\"");
}
quote = quoteChar.charAt(0);
}
CsvPreference format = createFormat(delimiter, quote);
return format;
}
static
public CsvPreference getFormat(BufferedReader reader) throws IOException {
reader.mark(10 * 1024);
for(int i = 0; i < CsvUtil.DELIMITERS.length; i++){
char delimiter = CsvUtil.DELIMITERS[i];
try {
CsvPreference format = createFormat(delimiter, '\"');
if(checkFormat(reader, format)){
return format;
}
} finally {
reader.reset();
}
}
throw new IOException("Unrecognized CSV format");
}
static
private CsvPreference createFormat(char delimiter, char quote){
CsvPreference.Builder builder = new CsvPreference.Builder(quote, delimiter, "\n");
builder.useEncoder(new DefaultCsvEncoder());
return builder.build();
}
static
private boolean checkFormat(BufferedReader reader, CsvPreference format) throws IOException {
CsvListReader parser = new CsvListReader(reader, format){
@Override
public void close(){
}
};
int columns = 0;
// Check the header line and the first ten lines
for(int line = 0; line < (1 + 10); line++){
List<String> row = parser.read();
if(row == null){
break;
}
int rowColumns = row.size();
if((rowColumns > 1) && (columns == 0 || columns == rowColumns)){
columns = rowColumns;
} else
{
return false;
}
}
parser.close();
return (columns > 1);
}
static
public Table<EvaluationRequest> readTable(BufferedReader reader, CsvPreference format) throws IOException {
Table<EvaluationRequest> table = new Table<>();
CsvMapReader parser = new CsvMapReader(reader, format);
String[] header = parser.getHeader(true);
if(header.length > 0 && ("id").equalsIgnoreCase(header[0])){
table.setId(header[0]);
}
List<EvaluationRequest> requests = new ArrayList<>();
while(true){
Map<String, String> arguments = parser.read(header);
if(arguments == null){
break;
}
String id = arguments.remove(table.getId());
EvaluationRequest request = new EvaluationRequest(id);
request.setArguments(arguments);
requests.add(request);
}
parser.close();
table.setRows(requests);
return table;
}
static
public void writeTable(BufferedWriter writer, CsvPreference format, Table<EvaluationResponse> table) throws IOException {
CsvMapWriter formatter = new CsvMapWriter(writer, format);
String[] header = null;
List<EvaluationResponse> responses = table.getRows();
for(EvaluationResponse response : responses){
Map<String, ?> result = response.getResult();
String id = response.getId();
if(id != null){
result = join(Collections.<String, String>singletonMap(table.getId(), id), result);
} // End if
if(header == null){
Set<String> keys = result.keySet();
header = (keys).toArray(new String[keys.size()]);
formatter.writeHeader(header);
}
formatter.write(result, header);
}
formatter.flush();
formatter.close();
}
static
private String decodeDelimiter(String delimiterChar){
if(("\\t").equals(delimiterChar)){
return "\t";
}
return delimiterChar;
}
static
private String decodeQuote(String quoteChar){
if(("\\'").equals(quoteChar)){
return "\'";
} else
if(("\\\"").equals(quoteChar)){
return "\"";
}
return quoteChar;
}
static
private Map<String, ?> join(Map<String, ?> left, Map<String, ?> right){
Map<String, Object> result = new LinkedHashMap<>(left);
result.putAll(right);
return result;
}
static
public class Table<R> {
private String id = null;
private List<R> rows = null;
public String getId(){
return this.id;
}
public void setId(String id){
if(this.id != null){
throw new IllegalStateException();
}
this.id = id;
}
public List<R> getRows(){
return this.rows;
}
public void setRows(List<R> rows){
this.rows = rows;
}
}
private static final char[] DELIMITERS = {',', ';', '\t'};
}