package org.supercsv.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCSVException;

/**
 * A utility class for various list/map operations. May be of use to the public as well as to BestCSV
 * 
 * @author Kasper B. Graversen
 */
public abstract class Util {

/**
 * Convert a map to a list
 * 
 * @param source
 *            the map to create a list from
 * @param nameMapping
 *            the keys of the map whose values will constitute the list
 * @return a list
 */
public static List<? extends Object> map2List(final Map<String, ? extends Object> source, final String[] nameMapping) {
	final List<? super Object> result = new ArrayList<Object>(nameMapping.length);
	for( final String element : nameMapping ) {
		result.add(source.get(element));
	}
	return result;
}

/**
 * A function to convert a list to a map using a namemapper for defining the keys of the map.
 * 
 * @param destination
 *            the resulting map instance. The map is cleared before populated
 * @param nameMapper
 *            cannot contain duplicate names
 * @param values
 *            A list of values TODO: see if using an iterator for the values is more efficient
 */
public static <T> void mapStringList(final Map<String, T> destination, final String[] nameMapper, final List<T> values) {
	if( nameMapper.length != values.size() ) {
		throw new SuperCSVException(
			"The namemapper array and the value list must match in size. Number of columns mismatch number of entries for your map.");
	}
	destination.clear();
	
	// map each element of the array
	for( int i = 0; i < nameMapper.length; i++ ) {
		final String key = nameMapper[i];
		
		// null's in the name mapping means skip column
		if( key == null ) {
			continue;
		}
		
		// only perform safe inserts
		if( destination.containsKey(key) ) {
			throw new SuperCSVException("nameMapper array contains duplicate key \"" + key
				+ "\" cannot map the list...");
		}
		
		destination.put(key, values.get(i));
	}
}

/**
 * A function which given a list of strings, process each cell using its corresponding processor-chain from the
 * processor array and return the result as an arary Can be extended so the safety check is cached in case the same two
 * arrays are used on several requests
 * 
 * @param destination
 *            This list is emptied and then populated with the result from reading a line
 * @param source
 *            Is an array of Strings/null's representing the soure elements
 * @param processors
 *            an array of CellProcessors/null's enabling custom processing of each cellvalue specified in the cellValue
 *            array. The number of non-null entries in the cellValues array must match the number of processors/null
 *            given.
 * @param lineNo
 *            the line number of the CSV source the processing is taking place on
 * @param errorLog
 *            a builder of error messages. In case of an exception, this builder is populated with a message. All cells
 *            are attempted processed even in case one cell throws an exception.
 */
public static void processStringList(final List<? super Object> destination, final List<? extends Object> source,
	final CellProcessor[] processors, final int lineNo) throws SuperCSVException {
	if( source.size() != processors.length ) {
		throw new SuperCSVException(
			"The value array (size "
				+ source.size()
				+ ")  must match the processors array (size "
				+ processors.length
				+ ")."
				+ " You are probably reading a CSV line with a different number of columns than the number of cellprocessors specified...");
	}
	
	destination.clear();
	final CSVContext context = new CSVContext();
	context.lineSource = source;
	for( int i = 0; i < source.size(); i++ ) {
		// if no processor, just add the string
		if( processors[i] == null ) {
			destination.add(source.get(i));
		}
		else {
			context.lineNumber = lineNo;
			context.columnNumber = i;
			destination.add(processors[i].execute(source.get(i), context)); // add
		}
	}
}

/**
 * Convert a map to an array of objects
 * 
 * @param values
 *            the values
 * @param nameMapping
 *            the mapping defining the order of the value extract of the map
 * @return the map unfolded as an array based on the nameMapping
 */
public static Object[] stringMap(final Map<String, ? extends Object> values, final String[] nameMapping) {
	final Object[] res = new Object[nameMapping.length];
	int i = 0;
	for( final String name : nameMapping ) {
		res[i++] = values.get(name);
	}
	return res;
}
}

@@ -3440,24 +3440,133 @@
 xception %7B%0D%0A
+%09final CSVContext context = new CSVContext();%0D%0A%09context.lineSource = source;%0D%0A%09context.lineNumber = lineNo;%0D%0A
 %09if( source.
@@ -3846,16 +3846,28 @@
  columns
+%22 +%0D%0A%09%09%09%09%09%09%22
  than th
@@ -3902,24 +3902,33 @@
 pecified...%22
+, context
 );%0D%0A%09%7D%0D%0A%09%0D%0A%09
@@ -3953,86 +3953,8 @@
 );%0D%0A
-%09final CSVContext context = new CSVContext();%0D%0A%09context.lineSource = source;%0D%0A
 %09for
@@ -4125,41 +4125,8 @@
  %7B%0D%0A
-%09%09%09context.lineNumber = lineNo;%0D%0A
 %09%09%09c

improving the error message while defining the context when the value array does not match the processor array