/*
* #%L
* gitools-ui-app
* %%
* Copyright (C) 2013 Universitat Pompeu Fabra - Biomedical Genomics group
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.gitools.ui.app.fileimport.wizard.text.reader;
import org.gitools.api.analysis.IProgressMonitor;
import org.gitools.api.resource.IResourceLocator;
import org.gitools.utils.readers.FileField;
import org.gitools.utils.readers.FileHeader;
import org.gitools.utils.readers.MatrixReaderProfile;
import org.gitools.utils.readers.profile.ReaderProfile;
import org.gitools.utils.readers.profile.Separator;
import org.gitools.utils.readers.profile.TableReaderProfile;
import org.gitools.utils.readers.text.CSVParser;
import org.gitools.utils.readers.text.CSVReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import static org.gitools.utils.readers.profile.Separator.COMMA;
import static org.gitools.utils.readers.profile.Separator.TAB;
public class FlatTextImporter implements Closeable {
private final IResourceLocator locator;
private CSVReader reader = null;
private List<FileHeader> headers;
private int previewLength = 20;
private List<List<FileField>> preview;
private ReaderProfile readerProfile;
private ReaderAssistant readerAssistant;
private boolean previewMode;
private String[] currentLine;
private IProgressMonitor monitor;
public FlatTextImporter(IResourceLocator locator, IProgressMonitor monitor, boolean previewMode, ReaderProfile profile) {
super();
this.monitor = monitor;
this.locator = locator;
this.readerProfile = profile == null ? new TableReaderProfile() : profile;
this.previewMode = previewMode;
guessSeparator(locator);
loadHead(monitor);
if (profile == null) {
this.readerProfile = guessDataLayout();
}
setAssistant(readerProfile);
}
public FlatTextImporter(IResourceLocator locator, IProgressMonitor monitor, boolean previewMode) {
this(locator, monitor, previewMode, null);
}
private ReaderProfile guessDataLayout() {
// if top left field is empty, layout is probably a matrix
if (getFileHeaders().get(0).getLabel().equals("")) {
return MatrixReaderProfile.fromProfile(readerProfile);
} else {
return readerProfile;
}
}
private void guessSeparator(IResourceLocator locator) {
// Choose COMMA separator if it's a CSV
if ("csv".equalsIgnoreCase(locator.getExtension())) {
readerProfile.setSeparator(COMMA);
} else if ("tsv".equalsIgnoreCase(locator.getExtension()) || "tab".equalsIgnoreCase(locator.getExtension())) {
readerProfile.setSeparator(TAB);
} else {
// try to guess:
int recordOfFields = 0;
for (Separator sep : Separator.values()) {
Separator oldSep = readerProfile.getSeparator();
readerProfile.setSeparator(sep);
loadHead(monitor);
if (headers.size() < recordOfFields) {
readerProfile.setSeparator(oldSep);
} else {
recordOfFields = headers.size();
}
}
}
}
private void setAssistant(ReaderProfile profile) {
this.readerAssistant = profile.getLayout().equals(ReaderProfile.MATRIX) ?
new MatrixReaderAssistant(this) : new TableReaderAssistant(this);
}
public void loadHead(IProgressMonitor monitor) {
monitor.begin("Loading preview: " + locator.getName(), 0);
reader = null;
try {
reader = newCSVReader(monitor);
// Load file headers
String[] line = reader.readNext();
headers = new ArrayList<>(line.length);
for (int i = 0; i < line.length; i++) {
headers.add(new FileHeader(line[i], i));
}
//Load preview
if (previewLength > 0 && previewMode) {
preview = new ArrayList<>();
for (int i = 0; i < previewLength; i++) {
line = reader.readNext();
if (line != null) {
ArrayList<FileField> fields = new ArrayList<FileField>(line.length);
int previewFields = line.length;
for (int j = 0; j < previewFields; j++) {
fields.add(new FileField(line[j], j, i));
}
preview.add(fields);
} else {
previewLength = i;
}
}
reader.close();
}
if (readerAssistant != null) {
readerAssistant.update();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private CSVReader newCSVReader(IProgressMonitor monitor) throws IOException {
CSVReader reader = new CSVReader(
new InputStreamReader(locator.openInputStream(monitor)),
readerProfile.getSeparator().getChar(),
CSVParser.DEFAULT_QUOTE_CHARACTER,
CSVParser.DEFAULT_ESCAPE_CHARACTER,
readerProfile.getCommentChar(),
readerProfile.getSkipLines(),
CSVParser.DEFAULT_STRICT_QUOTES,
CSVParser.DEFAULT_IGNORE_LEADING_WHITESPACE);
return reader;
}
public boolean readNext() throws IOException {
if (reader == null) {
loadHead(monitor);
}
currentLine = reader.readNext();
if (currentLine == null) {
return false;
}
return true;
}
public List<FileHeader> getFileHeaders() {
return headers;
}
public List<List<FileField>> getPreview() {
return preview;
}
public IResourceLocator getLocator() {
return locator;
}
public int getLastRowNum() {
//TODO
return 0;
}
public ReaderProfile getReaderProfile() {
return readerProfile;
}
public void setReaderProfile(ReaderProfile readerProfile) {
this.readerProfile = readerProfile;
setAssistant(readerProfile);
}
public ReaderAssistant getReaderAssistant() {
return readerAssistant;
}
@Override
public void close() throws IOException {
if (reader != null) {
reader.close();
}
}
public void setPreviewMode(boolean previewMode) {
this.previewMode = previewMode;
loadHead(monitor);
}
public String[] getCurrentLine() {
return currentLine;
}
}