package lu.tudor.santec.gecamed.formeditor.gui.view.dialog;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;

import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.NamedComponent;
import lu.tudor.santec.gecamed.formeditor.gui.FormWidgets;
import lu.tudor.santec.gecamed.formeditor.gui.model.ComboBoxElement;
import lu.tudor.santec.i18n.Translatrix;
import lu.tudor.santec.org.fife.ui.autocomplete.dialog.BaseDialogImpl;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import au.com.bytecode.opencsv.CSVReader;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

public abstract class CSVImportDialog {
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(CSVImportDialog.class.getName());
	
	public static final String[] DEFAULT_DATE_PATTERN = {
		"yyyy-MM-dd hh:mm", "M/d/yy h:mm", "dd/MM/yy hh:mm", "dd.MM.yy hh:mm"
	};
	
	private GECAMedBaseDialogImpl dialog;
	
	private File csvFile;
	
	protected HashMap<Integer, ComboBoxElement<Class<?>>> columnMap;
	
	private int comboBoxChangedBySelection = 0;
	
	private CellConstraints cc = new CellConstraints();
	
	private int fromLine;
	
	private Vector<ComboBoxElement<Class<?>>> mappableElements;
	
	
	// Components
	private JButton okButton;
	
	private JTextArea descriptionField;
	
	private JTextField fileNameField;
	
	private JFileChooser fileChooser;
	
	private char columnSeparator;
	
	private char quoteChar;
	
	private NamedComponent mappedValueNamedComponent;
	
	private JComboBox mappedValueBox;
	
	private JPanel mappedValueSettingsPanel;
	
	protected final JTable previewTable;
	
	protected JLabel warningLabel;
	
	
	
	public CSVImportDialog (Component parent, String title, String description) {
		/* ======================================== */
		this.fileChooser = new JFileChooser();
		this.fileChooser.setFileFilter(FormWidgets.getFileFilter("csv"));
		
		previewTable = new JTable() {
			private static final long serialVersionUID = 1L;

			@Override
			public boolean isCellEditable(int x, int y) {
                return false;
            }
		};
		
		columnMap = new HashMap<Integer, ComboBoxElement<Class<?>>>();
		
		initDialog(parent, title, description);
		/* ======================================== */
	}


	private void initDialog (Component parent, String title, String description) {
		/* ======================================== */
		CellConstraints cc = new CellConstraints();
		
		// DESCRIPTION
		JPanel descriptionPanel;
		descriptionField = new JTextArea();
		
		if (description == null || description.isEmpty()) {
			descriptionPanel = new JPanel();
			descriptionPanel.setOpaque(false);
		} else {
			descriptionField.setOpaque(false);
			descriptionField.setLineWrap(true);
			descriptionField.setWrapStyleWord(true);
			descriptionField.setAutoscrolls(true);
			descriptionField.setBorder(BorderFactory.createEmptyBorder());
			descriptionField.setText(description);
			descriptionField.setCaretPosition(0);
			descriptionField.setEditable(false);
			
			JScrollPane descriptionScoller = new JScrollPane(descriptionField);
			descriptionScoller.getVerticalScrollBar().setUnitIncrement(16);
			descriptionScoller.setOpaque(false);
			descriptionScoller.getViewport().setOpaque(false);
			descriptionScoller.setBorder(BorderFactory.createEmptyBorder());
			
			descriptionPanel = new JPanel(new FormLayout("f:1px:g", "5px, f:min(125px;p):g, 5px"));
			descriptionPanel.setOpaque(false);
			descriptionPanel.add(descriptionScoller, cc.xy(1, 2));
		}

		
		// LOAD FILE
		this.fileNameField = new JTextField();
		this.fileNameField.setEditable(false);
		
		JButton loadFileButton = new JButton(
				Translatrix.getTranslationString("FileSelectorPanel.BrowseButton"),
				GECAMedModule.getMiniIcon(GECAMedIconNames.OPEN));
		loadFileButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				int buttonOption = fileChooser.showOpenDialog(dialog);
				
				if (buttonOption == JFileChooser.APPROVE_OPTION) {
					initData(fileChooser.getSelectedFile());
				}
				/* ---------------------------------------- */
			}
		});
		
		
		JPanel loadFilePanel = new JPanel (new FormLayout("f:150px, 10px, f:125px, 0px", "f:p"));
		loadFilePanel.setOpaque(false);
		loadFilePanel.add(fileNameField, cc.xy(1, 1));
		loadFilePanel.add(loadFileButton, cc.xy(3, 1));
		
		
		
		// OPTIONS
		
		// 		FROM LINE
		JLabel fromLineLabel = new JLabel(
				Translatrix.getTranslationString("formeditor.fromLine") + ":");
		fromLineLabel.setOpaque(false);
		
		final JSpinner fromLineSpinner = new JSpinner(new SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 1));
		fromLineSpinner.addChangeListener(new ChangeListener() {
			
			public void stateChanged(ChangeEvent e) {
				/* ---------------------------------------- */
				// the starting line (first is 0, but for user, the first is 1):
				int i = (Integer)fromLineSpinner.getValue() - 1;
				
				if (fromLine != i) {
					fromLine = i;
					initData(false);
				}
				/* ---------------------------------------- */
			}
		});
		
		
		// 		COLUMN SEPARATOR
		JLabel columnSeparatorLabel = new JLabel(
				Translatrix.getTranslationString("formeditor.columnSeparator") + ":");
		
		
		Vector<ComboBoxElement<String>> defaultSeparators = new Vector<ComboBoxElement<String>>();
		defaultSeparators.add(new ComboBoxElement<String>(
				Translatrix.getTranslationString("formeditor.semicolon"), ";"));
		defaultSeparators.add(new ComboBoxElement<String>(
				Translatrix.getTranslationString("formeditor.comma"), ","));
		defaultSeparators.add(new ComboBoxElement<String>(
				Translatrix.getTranslationString("formeditor.tab"), "\t"));
		defaultSeparators.add(new ComboBoxElement<String>(
				Translatrix.getTranslationString("formeditor.blank"), " "));
		defaultSeparators.add(new ComboBoxElement<String>("", (String)null));
		
		final JComboBox columnSeparatorBox = new JComboBox(defaultSeparators);
		columnSeparatorBox.setEditable(true);
		columnSeparatorBox.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				Object item = columnSeparatorBox.getSelectedItem();
				
				if (item == null || item.equals("")) {
					return;
				}
				
				if (item instanceof ComboBoxElement) {
					item = ((ComboBoxElement<?>) item).getValue();
				}
				
				char c = item.toString().charAt(0);
				
				
				if (columnSeparator != c) {
					columnSeparator = c;
					initData(true);
				}
				/* ---------------------------------------- */
			}
		});
		
		// initialize the columnSeparator char
		columnSeparator = ((String) ((ComboBoxElement<?>)columnSeparatorBox
				.getSelectedItem()).getValue()).charAt(0);
		
		
		// 		QUOTE CHAR
		JLabel quoteCharLabel = new JLabel(
				Translatrix.getTranslationString("formeditor.quoteChar") + ":");
		quoteCharLabel.setOpaque(false);
		
		final JComboBox quoteCharBox = new JComboBox(new String[] {"\"", "'"});
		quoteCharBox.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				char c = ((String)quoteCharBox.getSelectedItem()).charAt(0);
				
				if (quoteChar != c) {
					quoteChar = c;
					initData(false);
				}
				/* ---------------------------------------- */
			}
		});
		
		// initialize the quoteChar
		quoteChar = ((String)quoteCharBox.getSelectedItem()).charAt(0);
		
		

		JPanel optionPanel = new JPanel(new FormLayout(
				"f:p, 10px, l:50dlu, 1px:g", 
				"f:p, 5px, f:p, 5px, f:p, 10px"));
		optionPanel.setOpaque(false);
		optionPanel.add(fromLineLabel, cc.xy(1, 1));
		optionPanel.add(fromLineSpinner, cc.xy(3, 1));
		optionPanel.add(columnSeparatorLabel, cc.xy(1, 3));
		optionPanel.add(columnSeparatorBox, cc.xy(3, 3));
		optionPanel.add(quoteCharLabel, cc.xy(1, 5));
		optionPanel.add(quoteCharBox, cc.xy(3, 5));
		
		
		
		// COLUMN OPTIONS
		this.mappedValueBox = new JComboBox();
		this.mappedValueBox.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				if (comboBoxChangedBySelection > 0) {
					comboBoxChangedBySelection--;
				} else {
					mapValueToCurrentColumn();
				}
				/* ---------------------------------------- */
			}
		});
		this.mappedValueBox.setEnabled(false);
		
		this.mappedValueSettingsPanel = new JPanel(new FormLayout(
				"f:max(p; 55px), 15px, f:1px:g", "t:p"));
		this.mappedValueSettingsPanel.setOpaque(false);
		
		this.mappedValueNamedComponent = new NamedComponent(
				Translatrix.getTranslationString("formeditor.assignSelectedColumn"),
				this.mappedValueBox);
		this.mappedValueSettingsPanel.add(mappedValueNamedComponent, cc.xy(1, 1));
		
		
		
		// PREVIEW TABLE
		this.previewTable.setModel(new DefaultTableModel());
		this.previewTable.setOpaque(false);
		this.previewTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.previewTable.setColumnSelectionAllowed(true);
		this.previewTable.setRowSelectionAllowed(false);
		
		this.previewTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			
			public void valueChanged(ListSelectionEvent e) {
				if (e.getValueIsAdjusting()) {
					return;
				}
				if (previewTable.getSelectedColumn() < 0) {
					mappedValueBox.setEnabled(false);
				}
			}
		});

		
		/*
		 * Selecting the same row, but different column will not call the valueChanged Event 
		 * of the ListSelectionListener. Therefore a MouseListener and a KeyListener are used
		 * to catch, whether a different column is selected.
		 */
		this.previewTable.addMouseListener(new MouseListener() {
			
			public void mouseReleased(MouseEvent e) {
				selectionChanged();
			}
			
			public void mousePressed(MouseEvent e) {}
			public void mouseExited(MouseEvent e) {}
			public void mouseEntered(MouseEvent e) {}
			public void mouseClicked(MouseEvent e) {}
		});
		
		this.previewTable.addKeyListener(new KeyListener() {
			
			public void keyReleased(KeyEvent e) {
				int keyCode = e.getKeyCode();
				switch (keyCode) {
				case KeyEvent.VK_LEFT:
				case KeyEvent.VK_RIGHT:
				case KeyEvent.VK_HOME:
				case KeyEvent.VK_END:
				case KeyEvent.VK_TAB:
					selectionChanged();
				}
			}
			
			public void keyTyped(KeyEvent e) {}
			public void keyPressed(KeyEvent e) {}
		});
		
		JPanel tableScrollerPanel = new JPanel(new BorderLayout());
		tableScrollerPanel.setOpaque(false);
		tableScrollerPanel.add(this.previewTable, BorderLayout.CENTER);
		tableScrollerPanel.add(this.previewTable.getTableHeader(), BorderLayout.NORTH);
		
		JScrollPane tableScroller = new JScrollPane(tableScrollerPanel);
		tableScroller.getVerticalScrollBar().setUnitIncrement(16);
		tableScroller.setOpaque(false);
		tableScroller.getViewport().setOpaque(false);
		
		
		this.warningLabel = new JLabel() {
			private static final long serialVersionUID = 1L;

			@Override
			public void setText(String text) {
				if (text != null
						&& !text.trim().equals(""))
					super.setText("<html>"+text);
				else {
					super.setText("");
				}
			};
		};
		this.warningLabel.setForeground(Color.RED);
		
		
		
		// LOAD COMPONENTS INTO THE MAIN PANEL
		JPanel mainPanel = new JPanel(new FormLayout("5px, f:275px:g, 5px", 
				"5px, f:p, 10px, f:p, 10px, f:p, 10px, f:p, 10px, f:1px:g, 5px, f:p, 5px"));
		mainPanel.add(descriptionPanel, cc.xy(2, 2));
		mainPanel.add(loadFilePanel, cc.xy(2, 4));
		mainPanel.add(optionPanel, cc.xy(2, 6));
		mainPanel.add(this.mappedValueSettingsPanel, cc.xy(2, 8));
		mainPanel.add(tableScroller, cc.xy(2, 10));
		mainPanel.add(this.warningLabel, cc.xy(2, 12));
		
		// CREATE THE DIALOG
		dialog = GECAMedBaseDialogImpl.getNewInstance(parent, title, 
				BaseDialogImpl.OK_CANCEL_BUTTON_MODE, mainPanel);
		
		okButton = dialog.getOKButton();
//		okButton.setEnabled(false);
		okButton.getAction().setEnabled(false);
		/* ======================================== */
	}
	
	
	/**
	 * Called, when the selected column could be changed
	 */
	private void selectionChanged () {
		/* ---------------------------------------- */
		int column = previewTable.getSelectedColumn();
		
		if (column >= 0) {
			mappedValueBox.setEnabled(true);
			mappedValueBox.setSelectedItem(columnMap.get(column));
		} else {
			mappedValueBox.setEnabled(false);
			mappedValueBox.setSelectedIndex(-1);
		}
		/* ---------------------------------------- */
	}
	
	
	/**
	 * Loads the data from the CSV-file and shows it in the preview table
	 * 
	 * @param file	the CSV-file
	 */
	private void initData (File file) {
		/* ======================================== */
		if (file != null 
				&& file.exists()) {
			boolean discardMapping =  !file.equals(csvFile);
			
			fileNameField.setText(file.getAbsolutePath());
			csvFile = file;
			
			initData(discardMapping);
		}
		/* ======================================== */
	}
	
	
	/**
	 * Reloads the data of the stored CSV-file and shows it in the preview table.
	 * 
	 * @param discardMapping tells whether the mapping shall be erased. 
	 */
	private void initData (boolean discardMapping) {
		/* ======================================== */
		if (csvFile == null || !csvFile.exists()) {
			return;
		}
		
		try {
			// read the CSV-file
			FileReader csvFileReader = new FileReader(csvFile);
			CSVReader csvReader = new CSVReader(csvFileReader, 
					// the separator, given in the columnSeparatorBox:
					this.columnSeparator,
					// the quote char (fix yet):
					this.quoteChar,
					this.fromLine);
			
			List<String[]> lines = csvReader.readAll();
			csvReader.close();
			csvFileReader.close();
			
			// fill the tableData vector, which represents the model of the previewTable
			Vector<Vector<String>> tableData = new Vector<Vector<String>>();
			Vector<String> columnNames = new Vector<String>();
			
			if (!discardMapping) {
				// keep the old column names
				TableColumnModel tcm = previewTable.getColumnModel();
				
				for (int index = 0; index < tcm.getColumnCount(); index++) {
					columnNames.add(tcm.getColumn(index).getHeaderValue().toString());
				}
			} else {
				this.columnMap.clear();
			}
			
			Vector<String> rowData;
			// create a table model from the data of the CSV-file
			for (String[] line : lines) {
				
				// fit the column size of the table to the max size of columns
				while (line.length > columnNames.size()) {
					columnNames.add(String.valueOf(columnNames.size()+1));
				}
				
				rowData = new Vector<String>();
				for (String colValue : line) {
					rowData.add(colValue);
				}
				
				tableData.add(rowData);
			}
			
			
			((DefaultTableModel)this.previewTable.getModel()).setDataVector(tableData, columnNames);
			
			this.mapAfterDataLoad(this.mappableElements, this.columnMap);
		} catch (IOException e) {
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		/* ======================================== */
	}
	
	
	@SuppressWarnings("unchecked")
	private void mapValueToCurrentColumn () {
		/* ======================================== */
		int column = previewTable.getSelectedColumn();
		columnMap.put(column, (ComboBoxElement<Class<?>>)mappedValueBox.getSelectedItem());
		
		// TODO rename the column header
		int selectedColumn = previewTable.getSelectedColumn();
		if (selectedColumn < 0) {
			return;
		}
		
		StringBuffer name = new StringBuffer(String.valueOf(selectedColumn + 1));
		
		
		this.mappedValueSettingsPanel.removeAll();
		this.mappedValueSettingsPanel.add(this.mappedValueNamedComponent, cc.xy(1, 1));
		if ((ComboBoxElement<?>) ((ComboBoxElement<?>)mappedValueBox.getSelectedItem()) != null) {
			name.append(" - ").append((ComboBoxElement<?>) ((ComboBoxElement<?>)mappedValueBox.getSelectedItem()));
			
			this.mappedValueSettingsPanel.add(this.createSettingsPanelForClass(
					(Class<?>)((ComboBoxElement<?>) ((ComboBoxElement<?>)mappedValueBox.getSelectedItem())).getValue(), column),cc.xy(3, 1));
		}
		this.mappedValueSettingsPanel.repaint();
		
		previewTable.getColumnModel().getColumn(selectedColumn).setHeaderValue(name);
		
		dialog.validate();
		
		
		boolean mappingOK = checkMapping();
//		this.okButton.setEnabled(mappingOK);
		this.okButton.getAction().setEnabled(mappingOK);
		this.warningLabel.setVisible(!mappingOK && csvFile != null);
		/* ======================================== */
	}
	
	
	
	/**
	 * Returns a Vector containing the keys, a column is mapped to in the first row
	 * and the data of the CSV-file in the following rows
	 * 
	 * @param values
	 * @return
	 */
	public Vector<Vector<ComboBoxElement<Object>>> showDialog (Vector<ComboBoxElement<Class<?>>> values) {
		/* ======================================== */
		
		/* ---------------------------------------- */
		// BEFORE SHOWING DIALOG
		/* ---------------------------------------- */
		values.insertElementAt(null, 0);
		this.mappableElements = values;
		this.mappedValueBox.setModel(new DefaultComboBoxModel(this.mappableElements));
		okButton.setEnabled(checkMapping());
		/* ---------------------------------------- */
		
		dialog.setSize(400, 520);
//		FormEditorDialog.centerWindowOnOwner(dialog, dialog.getOwner());
		
		boolean showDialog = true;
		Vector<Vector<ComboBoxElement<Object>>> resultData = new Vector<Vector<ComboBoxElement<Object>>>();
		
		// if there is any problem, show an error message and return to the import dialog 
		while (showDialog) {
			showDialog = false;
			
			int buttonOption = dialog.showCenteredDialog();
			
			/* ---------------------------------------- */
			// AFTER SHOWING DIALOG
			/* ---------------------------------------- */
			if (buttonOption == GECAMedBaseDialog.CANCEL_OPTION) {
				// cancel button was pressed
				return null;
				
			} else {
				// OK button was pressed
				
				Vector<ComboBoxElement<Object>> resultRowData;
				
				resultData.clear();
				Vector<?> tableData = ((DefaultTableModel)previewTable.getModel()).getDataVector();
				
				
				// write the mapped names into the first row
				resultRowData = new Vector<ComboBoxElement<Object>>();
				for (Integer column : columnMap.keySet()) {
					/* ---------------------------------------- */
					while (column >= resultRowData.size()) {
						resultRowData.add(null);
					}
					
					ComboBoxElement<Class<?>> item = columnMap.get(column);
					if (item != null) {
						resultRowData.setElementAt(new ComboBoxElement<Object>(
								item.getTranslation(), (Object)item.getValues()), column);
					}
					/* ---------------------------------------- */
				}
				resultData.add(resultRowData);
				
				
				// puts the data into the vector as specified in the dialog
				for (Object o : tableData) {
					/* ---------------------------------------- */
					Vector<?> rowData = (Vector<?>)o;
					
					resultRowData = new Vector<ComboBoxElement<Object>>(rowData.size());
					
					for (int i = resultRowData.size(); i < rowData.size(); i++) {
						resultRowData.add(null);
					}
					
					for (Integer column : columnMap.keySet()) {
						if (column < rowData.size()) {
							// make an object out of the given string value
							try {
								Object value = stringToObject((String)rowData.get(column), column);
								
								resultRowData.set(column, new ComboBoxElement<Object> ((String)rowData.get(column), value));
							} catch (Exception e) {
								GECAMedBaseDialogImpl.showMessageDialog(dialog, 
										Translatrix.getTranslationString("formeditor.error"), 
										Translatrix.getTranslationString("formeditor.errorWhileImporting_msg")
														.replace("$col", String.valueOf(column + 1))
														.replace("$row", String.valueOf(tableData.indexOf(rowData) + 1))
												+ e.getMessage(), 
										GECAMedBaseDialogImpl.OK_BUTTON_MODE);
								
								showDialog = true;
								break;
							}
						}
					}
					
					if (showDialog) {
						break;
					}
					
					resultData.add(resultRowData);
					/* ---------------------------------------- */
				}
			}
		}
		
		return resultData;
		/* ---------------------------------------- */
		
		/* ======================================== */
	}
	
	
	public void setDescription (String descriptionText) {
		this.descriptionField.setText(descriptionText);
	}
	
	
	public void setTitle (String titleText) {
		this.dialog.setTitle(titleText);
	}
	
	
	public boolean isFileLoaded () {
		return csvFile != null;
	}
	
	
	
	/**
	 * This method is called after data is loaded or changed and the defined column mapping
	 * is lost or if the column mapping wasn't set before
	 * 
	 * @param availableElements	All elements that can be mapped to a column
	 * @param columnMap			The Map with which the elements can be mapped to the columns 
	 */
	protected void mapAfterDataLoad (
			Vector<ComboBoxElement<Class<?>>> availableElements, 
			HashMap<Integer, ComboBoxElement<Class<?>>> columnMap) { }
	
	
	/**
	 * Checks, whether the mapping is OK. 
	 * Check e.g. if only one column is mapped to an object 
	 * (if that must not occur).
	 * 
	 * @return <code>true</code> if the mapping is OK 
	 * and the OK button shell be disabled.
	 */
	protected abstract boolean checkMapping ();

	
	/**
	 * Creates a JPanel, that is shown next to the ComboBox, that maps a column to an object.
	 * Depending on the object type chosen, settings can be edited.
	 * 
	 * @param type
	 * The type of the object, selected in the ComboBox
	 * 
	 * @param selectedColumn
	 * The column of the preview table, that is currently selected
	 *  
	 * @return
	 * The panel, to show next to the ComboBox
	 */
	protected abstract JPanel createSettingsPanelForClass (Class<?> type, final int selectedColumn);
		
	
	/**
	 * After clicking OK, all cell of the CSV-file is converted into an object. 
	 * This method is responsible for that.
	 * 
	 * @param value
	 * The value of the selected cell.
	 * 
	 * @param column
	 * The column of the selected cell. 
	 * 
	 * @return
	 * The converted object, that is put into the result vector
	 * 
	 * @throws Exception 
	 */
	protected abstract Object stringToObject (String value, int column) throws Exception;
}
