package org.sagebionetworks.repo.model.dbo.dao.table;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.sagebionetworks.repo.model.table.ColumnModel;
import org.sagebionetworks.repo.model.table.Row;
import org.sagebionetworks.repo.model.table.TableConstants;
import org.sagebionetworks.util.csv.CsvNullReader;

/**
 * Provides an Iterator<Row> abstraction over a raw CSV reader.
 * 
 * @author jmhill
 * 
 */
public class CSVToRowIterator implements Iterator<Row> {

	List<ColumnModel> resultSchema;
	List<String> headers;
	CsvNullReader reader;
	String[] lastRow;
	Map<String, Integer> idToIndexMap;
	int rowsProcessed;
	Integer rowIdIndex;
	Integer rowVersionIndex;
	int[] indexMapping;
	boolean isFirstLineHeader;

	/**
	 * Create a new object for each use.
	 * 
	 * @param resultSchema
	 *            Each row returned will match this schema.
	 * @param reader
	 *            The CSV stream that contains the source data. Data will be
	 *            read from this stream and translated into rows. It is the job
	 *            of the caller to close this stream when finished.
	 * @param progressReporter
	 * @throws IOException
	 */
	public CSVToRowIterator(List<ColumnModel> resultSchema, CsvNullReader reader, boolean isFirstLineHeader)
			throws IOException {
		super();
		this.isFirstLineHeader = isFirstLineHeader;
		this.resultSchema = resultSchema;
		this.reader = reader;
		this.headers = TableModelUtils.getHeaders(resultSchema);
		this.rowsProcessed = 0;
		// We need to read the first row to determine if it a header
		lastRow = reader.readNext();
		// We need a map of column ID to index.
		idToIndexMap = TableModelUtils.createColumnIdToIndexMapFromFirstRow(
				lastRow, resultSchema);
		if(idToIndexMap == null && this.isFirstLineHeader){
			throw new IllegalArgumentException("The first line was expected to be a header but the values did not match the names of of the columns of the table. Header row: "+lastRow);
		}
		if (idToIndexMap != null) {
			// Since the first row was a header, we need to next row to start.
			lastRow = reader.readNext();
		} else {
			// This means the row is not a header. So just map from the schema
			idToIndexMap = TableModelUtils
					.createColumnIdToIndexMap(this.headers);
		}
		// Does contain RowId?
		rowIdIndex = idToIndexMap.get(TableConstants.ROW_ID);
		rowVersionIndex = idToIndexMap.get(TableConstants.ROW_VERSION);
		// build the index mapping
		this.indexMapping = new int[resultSchema.size()];
		int index = 0;
		for(ColumnModel cm: this.resultSchema){
			// Lookup the mapping for this column
			Integer valueIndex = idToIndexMap.get(cm.getId());
			if(valueIndex == null){
				throw new IllegalArgumentException("Expected a column with the name: "+cm.getName()+" but did not find it");
			}
			indexMapping[index] = valueIndex;
			index++;
		}
	}

	@Override
	public boolean hasNext() {
		return lastRow != null;
	}

	@Override
	public Row next() {
		// Convert the row.
		Row row = new Row();
		// Do we have ROW_ID?
		if(rowIdIndex != null){
			String value = lastRow[rowIdIndex];
			if(value != null){
				row.setRowId(new Long(value));
			}

		}
		// Do we have a row version?
		if(rowVersionIndex != null){
			String value = lastRow[rowVersionIndex];
			if(value != null){
				row.setVersionNumber(new Long(value));
			}
		}
		List<String> values = new ArrayList<String>(this.resultSchema.size());
		// Copy over the values according to the mapping
		for(int i=0; i<this.resultSchema.size(); i++){
			values.add(lastRow[this.indexMapping[i]]);
		}
		row.setValues(values);

		// Net the next row
		try {
			lastRow = this.reader.readNext();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return row;
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException("Not supported");
	}

}

@@ -177,16 +177,60 @@
 l.Map;%0A%0A
+import org.apache.commons.lang.StringUtils;%0A
 import o
@@ -1742,32 +1742,88 @@
 %09%09idToIndexMap =
+ null;%0A%09%09if (this.isFirstLineHeader) %7B%0A%09%09%09idToIndexMap =
  TableModelUtils
@@ -1860,21 +1860,16 @@
 irstRow(
-%0A%09%09%09%09
 lastRow,
@@ -1886,18 +1886,20 @@
 ema);%0A%09%09
+%09
 if
+ 
 (idToInd
@@ -1915,37 +1915,13 @@
 null
- && this.isFirstLineHeader
 )
+ 
 %7B%0A
+%09
 %09%09%09t
@@ -1954,16 +1954,23 @@
 ception(
+%0A%09%09%09%09%09%09
 %22The fir
@@ -2093,52 +2093,56 @@
 w: %22
-+lastRow);%0A%09%09%7D%0A%09%09if (idToIndexMap != null) %7B
+%0A%09%09%09%09%09%09%09%09+ StringUtils.join(lastRow, ','));%0A%09%09%09%7D
 %0A%09%09%09
@@ -2321,16 +2321,16 @@
  schema%0A
+
 %09%09%09idToI
@@ -2354,22 +2354,16 @@
 delUtils
-%0A%09%09%09%09%09
 .createC

fix error message