package com.revolsys.record.io.format.csv;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.revolsys.datatype.DataTypes;
import com.revolsys.io.FileUtil;
import com.revolsys.io.map.IteratorMapReader;
import com.revolsys.io.map.MapReader;
import com.revolsys.io.map.MapWriter;
import com.revolsys.io.map.MapWriterFactory;
import com.revolsys.record.Record;
import com.revolsys.record.RecordFactory;
import com.revolsys.record.io.AbstractRecordIoFactory;
import com.revolsys.record.io.RecordReader;
import com.revolsys.record.io.RecordWriter;
import com.revolsys.record.io.RecordWriterFactory;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.spring.resource.Resource;
import com.revolsys.util.Exceptions;
import com.revolsys.util.Property;
public class Csv extends AbstractRecordIoFactory implements RecordWriterFactory, MapWriterFactory {
public static final char FIELD_SEPARATOR = ',';
public static final String MIME_TYPE = "text/csv";
public static List<String> parseLine(final String text) {
final StringBuilder sb = new StringBuilder();
sb.delete(0, sb.length());
final List<String> fields = new ArrayList<>();
if (Property.hasValue(text)) {
boolean inQuotes = false;
boolean hadQuotes = false;
final int length = text.length();
for (int i = 0; i < length; i++) {
final char c = text.charAt(i);
switch (c) {
case '"':
if (i < length - 1) {
hadQuotes = true;
final char nextChar = text.charAt(i + 1);
if (inQuotes && nextChar == '"') {
sb.append('"');
i++;
} else {
inQuotes = !inQuotes;
if (sb.length() > 0 && nextChar != ',' && nextChar != '\n' && nextChar != 0) {
sb.append(c);
}
}
} else {
if (inQuotes) {
fields.add(sb.toString());
}
return fields;
}
break;
case ',':
if (inQuotes) {
sb.append(c);
} else {
if (hadQuotes || sb.length() > 0) {
fields.add(sb.toString());
sb.delete(0, sb.length());
} else {
fields.add(null);
}
hadQuotes = false;
}
break;
case '\r':
if (i < length - 1) {
if (text.charAt(i + 1) == '\n') {
} else {
if (inQuotes) {
sb.append('\n');
} else {
if (hadQuotes || sb.length() > 0) {
fields.add(sb.toString());
sb.delete(0, sb.length());
} else {
fields.add(null);
}
return fields;
}
}
}
break;
case '\n':
if (i > length - 1) {
if (text.charAt(i + 1) == '\r') {
i++;
}
if (inQuotes) {
sb.append(c);
} else {
if (hadQuotes || sb.length() > 0) {
fields.add(sb.toString());
sb.delete(0, sb.length());
} else {
fields.add(null);
}
return fields;
}
}
break;
default:
sb.append(c);
break;
}
}
}
if (sb.length() > 0) {
fields.add(sb.toString());
}
return fields;
}
public static CsvWriter plainWriter(final File file) {
if (file == null) {
throw new NullPointerException("File must not be null");
} else {
final java.io.Writer writer = FileUtil.newUtf8Writer(file);
return plainWriter(writer);
}
}
public static CsvWriter plainWriter(final java.io.Writer writer) {
return new CsvWriter(writer);
}
/**
* Convert a to a CSV string with a header row and a data row.
*
* @param map The to convert to CSV
* @return The CSV string.
*/
public static String toCsv(final Map<String, ? extends Object> map) {
final StringWriter csvString = new StringWriter();
try (
final CsvMapWriter csvMapWriter = new CsvMapWriter(csvString)) {
csvMapWriter.write(map);
return csvString.toString();
}
}
public static Map<String, String> toMap(final String businessApplicationParameters) {
final HashMap<String, String> map = new LinkedHashMap<>();
final CsvIterator iterator = new CsvIterator(new StringReader(businessApplicationParameters));
if (iterator.hasNext()) {
final List<String> keys = iterator.next();
if (iterator.hasNext()) {
final List<String> values = iterator.next();
for (int i = 0; i < keys.size() && i < values.size(); i++) {
map.put(keys.get(i), values.get(i));
}
}
}
return map;
}
public static Map<String, Object> toObjectMap(final String businessApplicationParameters) {
final HashMap<String, Object> map = new LinkedHashMap<>();
final CsvIterator iterator = new CsvIterator(new StringReader(businessApplicationParameters));
if (iterator.hasNext()) {
final List<String> keys = iterator.next();
if (iterator.hasNext()) {
final List<String> values = iterator.next();
for (int i = 0; i < keys.size() && i < values.size(); i++) {
map.put(keys.get(i), values.get(i));
}
}
}
return map;
}
/*
* Replaces whitespace with spaces
*/
public static void writeColumns(final StringWriter out,
final Collection<? extends Object> columns, final char fieldSeparator,
final char recordSeparator) {
boolean first = true;
for (final Object value : columns) {
if (first) {
first = false;
} else {
out.write(fieldSeparator);
}
if (value != null) {
String text = DataTypes.toString(value);
text = text.replaceAll("\\s", " ");
out.write(text);
}
}
out.write(recordSeparator);
}
public Csv() {
super("Comma-Separated Values");
addMediaTypeAndFileExtension(MIME_TYPE, "csv");
}
@Override
public MapReader newMapReader(final Resource resource) {
try {
final CsvMapIterator iterator = new CsvMapIterator(resource, FIELD_SEPARATOR);
return new IteratorMapReader(iterator);
} catch (final IOException e) {
throw Exceptions.wrap(e);
}
}
@Override
public MapWriter newMapWriter(final java.io.Writer out) {
return new CsvMapWriter(out);
}
@Override
public RecordReader newRecordReader(final Resource resource,
final RecordFactory<? extends Record> recordFactory) {
return new CsvRecordReader(resource, recordFactory);
}
@Override
public RecordWriter newRecordWriter(final RecordDefinition recordDefinition,
final Resource resource) {
return new CsvRecordWriter(recordDefinition, resource, Csv.FIELD_SEPARATOR, true, true);
}
@Override
public RecordWriter newRecordWriter(final String baseName,
final RecordDefinition recordDefinition, final OutputStream outputStream,
final Charset charset) {
final OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset);
return new CsvRecordWriter(recordDefinition, writer, Csv.FIELD_SEPARATOR, true, true);
}
}