package de.lcag.common;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;

import routines.LcagFileTools;

public class CsvTable extends HashTable implements Storage {
	String filePath = null;
	private char encloseBy = '"';

	public CsvTable() {
	}

	public CsvTable(String pTableName, String aFilePath) {
		super(pTableName);

		setFilePath(aFilePath);
	}

	public CsvTable(String aFilePath, AbstractTable pSrcTable) {
		super(pSrcTable);
		setFilePath(aFilePath);
	}

	public CsvTable(String aFilePath, String... pColumnNameList) {
		super(pColumnNameList);
		setFilePath(aFilePath);
	}

	private String setFilePath(String aFilePath) {
		if (!aFilePath.toLowerCase().endsWith(".csv")) {
			aFilePath += ".csv";
		}

		return this.filePath = aFilePath;
	}

	public CsvTable(String aFilePath, Object pDefaultValue, SimpleDateFormat pDefaultDateFormat) {
		super(pDefaultValue, pDefaultDateFormat);
		setFilePath(aFilePath);
	}

	@Override
	public void saveAs(String pFilePath) throws IOException {
		File aFile = new File(pFilePath);
		String filePath = aFile.getCanonicalPath();
		String text = this.toString();

		createDirectoriesInPath(aFile);

		FileUtils.writeStringToFile(aFile, text, Charset.forName("UTF-8"));
	}

	@Override
	public void save() throws IOException {
		saveAs(this.filePath);
	}

	public void append() throws IOException {
		File aFile = new File(this.filePath);
		URI uri = aFile.toURI();

		if (aFile.exists()) {
			String text = this.asCsvData();

			FileUtils.writeStringToFile(aFile, text, Charset.forName("UTF-8"), true);
		} else {
			this.save();
		}
	}

	public void readColumNames() throws IOException {
		String text = LcagFileTools.readTextFile(filePath);
		String eol = this.getEol();
		String headline = text.substring(0, text.indexOf(eol));

		String[] cols = headline.split(getSeparator().trim());
		int colNo = 0;

		for (String col : cols) {
			col = col.trim();

			this.addColumn(col);
		}
	}

	@Override
	public void read() throws IOException {
		String text = LcagFileTools.readTextFile(filePath);
		parseString(text);
	}

	public void read(String text) {
		parseString(text);
	}

	private void parseString(String text) {
		int rowNo = -1;
		boolean firstIteration = true;
		String eol = this.getEol();
		String sep = getSeparator().trim();
		List<Integer> columnNumbersToUse = new ArrayList<>();

		for (String line : text.split(eol)) {
			String[] cols = line.split(sep);
			int colNo = 0;

			if (!firstIteration) {
				rowNo = this.newRow();
			}

			for (String cellValue : cols) {
				cellValue = cellValue.trim();

				cellValue = stripEncosingCharacter(cellValue);

				if (firstIteration) {
					if (useColumn(cellValue)) {
						this.addColumn(cellValue);
						columnNumbersToUse.add(colNo);
					}
				} else if (columnNumbersToUse.contains(colNo)) {
					this.setCellValue(rowNo, colNo, cellValue);
				}

				colNo += 1;
			}

			firstIteration = false;
		}
	}

	/**
	 * If a CSV cell is enclosed by a character, strip it off and return the result
	 * 
	 * @param pValue
	 * @return
	 */
	private String stripEncosingCharacter(String pValue) {
		int n = pValue.length() - 1;

		if (n > 0 && pValue.charAt(0) == this.encloseBy && pValue.charAt(n) == this.encloseBy) {
			pValue = pValue.substring(1, n);
		}
		return pValue;
	}

	static void createDirectoriesInPath(File aFile) {
		File dir = aFile.getParentFile();

		if (dir != null) {
			dir.mkdirs();
		}
	}
}
