package com.finitejs.modules.read;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 * Class represents a column in {@link DataTable}.
 * 
 * @param <T>  type of the column
 */
public class Column<T> implements Iterable<T>{
	
	/** Column header name */
	private String name;
	
	/** Column type for type T*/
	private ColumnType<T> type;
	
	/** List with column values */
	private List<T> column;
	
	/**
	 * Creates a new {@code Column} instance. 
	 * Used by the factory method {@code create}.
	 * 
	 * @param name  column header name
	 * @param type  column type
	 */
	private Column(String name, ColumnType<T> type){
		column = new ArrayList<>();
		this.name = name;
		this.type = type;
	}
	
	/**
	 * Adds a new value to the column of type T.
	 * 
	 * @param value  value to be added
	 */
	public void add(T value){
		column.add(value);
	}
	
	/**
	 * Parse a string value and adds to the column.
	 * 
	 * @param stringValue  string representation of the value to be added
	 */
	public void parseAndAdd(String stringValue){
		if (type != null){
			T value = type.parse(stringValue);
			column.add(value);
		}else{
			// non-typed column
			// every values will be null
			column.add(null);
		}
	}
	
	/**
	 * Get formatted string representation of given column value.
	 * 
	 * @param value  value to be formatted
	 * @return formatted string representation
	 */
	public String formatValue(T value){
		return type.format(value);
	}
	
	/**
	 * Get header name of the column.
	 * 
	 * @return header name
	 */
	public String getName(){
		return name;
	}
	
	/**
	 * Get type of the column.
	 * 
	 * @return type of column
	 */
	public ColumnType<T> getType(){
		return type;
	}
	
	/**
	 * Factory method for creating a new column.
	 * 
	 * @param name  column header name
	 * @param type  type of the column
	 * @return column instance
	 */
	public static <T> Column<T> create(String name, ColumnType<T> type){
		return new Column<T>(name, type);
	}

	@Override
	public Iterator<T> iterator() {
		return column.iterator();
	}
	
	/**
	 * Returns a list iterator over column elements of type T.
	 * 
	 * @return a list iterator
	 */
	public ListIterator<T> listIterator(){
		return column.listIterator();
	}
	
	/**
	 * Returns a list iterator over column elements of type T, 
	 * starting at the specified position in the column list.
	 * 
	 * @param index  index of first element to be 
	 * returned by the iterator {@code next()} method.
	 * @return a list iterator starting at the specified index
	 */
	public ListIterator<T> listIterator(int index){
		return column.listIterator(index);
	}
	
	/**
	 * Returns a list iterator over formatted string representation 
	 * of column elements.
	 * 
	 * @return a list iterator for formatted elements
	 */
	public Iterator<String> formattedValueIterator(){
		return new FormattedColumnIterator<T>(this);
	}
	
	/**
	 * Returns a list iterator over formatted string representation 
	 * of column elements, starting at the specified position in the column list.
	 * 
	 * @param index  index of first element to be 
	 * returned by the iterator {@code next()} method.
	 * @return a list iterator for formatted elements starting at the specified index
	 */
	public Iterator<String> formattedValueIterator(int index){
		return new FormattedColumnIterator<T>(this, index);
	}
	
}

@@ -1168,93 +1168,8 @@
 e);%0A
-%09%09%7Delse%7B%0A%09%09%09// non-typed column%0A%09%09%09// every values will be null%0A%09%09%09column.add(null);%0A
 %09%09%7D%0A
@@ -1368,24 +1368,63 @@
 e(T value)%7B%0A
+%09%09if (type == null)%7B%0A%09%09%09return %22%22;%0A%09%09%7D%0A
 %09%09return typ
@@ -1843,16 +1843,42 @@
 instance
+, or null if type is empty
 %0A%09 */%0A%09p
@@ -1945,16 +1945,82 @@
  type)%7B%0A
+%09%09// type cannot be null%0A%09%09if (type == null)%7B%0A%09%09%09return null;%0A%09%09%7D%0A
 %09%09return

Create method will not allow non-typed columns.