package org.activityinfo.ui.client.component.importDialog.data; import com.google.common.collect.Lists; import org.activityinfo.core.shared.importing.match.ColumnTypeGuesser; import org.activityinfo.core.shared.importing.source.SourceColumn; import org.activityinfo.core.shared.importing.source.SourceRow; import org.activityinfo.core.shared.importing.source.SourceTable; import org.activityinfo.core.shared.type.converter.ConverterFactory; import java.util.Date; import java.util.List; import java.util.logging.Logger; /** * An import source pasted in to a text field by the user. */ public class PastedTable implements SourceTable { private static final Logger LOGGER = Logger.getLogger(PastedTable.class.getName()); public static final int HEADER_ROW_COUNT = 1; public static final int DEFAULT_ROW_PARSER_COUNT = 10; private final RowParser rowParser; private List<SourceColumn> columns; private final List<PastedRow> rows = Lists.newArrayList(); private final DelimiterGuesser delimiterGuesser; public PastedTable(String text) { delimiterGuesser = new DelimiterGuesser(text); final char delimiter = delimiterGuesser.guess(); this.rowParser = new RowParser(text, delimiter); } public int getFirstInvalidRow() { return delimiterGuesser.getFirstNotMatchedRow(); } @Override public List<SourceColumn> getColumns() { ensureColumnsParsed(); return columns; } private void ensureColumnsParsed() { if (columns == null) { // ensure header row is parsed if (rows.isEmpty()) { parseNextRows(HEADER_ROW_COUNT); } if (!rows.isEmpty()) { columns = new ColumnParser(rows.get(0)).parseColumns(); rows.remove(0); // remove header row } else { columns = Lists.newArrayList(); } } } private void ensureRowsParsed() { if (rowParser.eof() || rows.size() > DEFAULT_ROW_PARSER_COUNT) { ensureColumnsParsed(); return; } parseNextRows(DEFAULT_ROW_PARSER_COUNT); ensureColumnsParsed(); } /** * Parses all rows if not parsed yet. Otherwise if parsed do nothing. * * @return returns newly parsed rows (if nothing was parsed before returns all rows) */ public List<PastedRow> parseAllRows() { return parseNextRows(Integer.MAX_VALUE); } @Override public boolean parsedAllRows() { return rowParser.eof(); } public List<PastedRow> parseNextRows(int numberOfRowsToParse) { long startTime = new Date().getTime(); List<PastedRow> parsedRows = rowParser.parseRows(numberOfRowsToParse); rows.addAll(parsedRows); LOGGER.fine("Parsed " + parsedRows.size() + " row(s), takes: " + (new Date().getTime() - startTime)); return parsedRows; } public void guessColumnsType(ConverterFactory converterFactory) { ensureRowsParsed(); for (int i = 0; i < columns.size(); i++) { columns.get(i).setGuessedType(new ColumnTypeGuesser(columnRowValues(i), converterFactory).guessType()); } } private List<String> columnRowValues(int columnIndex) { List<String> rowValues = Lists.newArrayList(); for (PastedRow row : rows) { rowValues.add(row.getColumnValue(columnIndex)); } return rowValues; } @Override public List<? extends SourceRow> getRows() { ensureRowsParsed(); return rows; } public String get(int row, int column) { ensureRowsParsed(); int rowSize = rows.size(); if (row > rowSize && rowParser.hasNextRow()) { parseNextRows(row - rowSize + 1); } return rows.get(row).getColumnValue(column); } @Override public String getColumnHeader(Integer columnIndex) { ensureColumnsParsed(); return columns.get(columnIndex).getHeader(); } }