package de.lcag.common;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import de.lcag.common.ExcelWorkbook.ExcelTable;
import routines.LcagFileTools;

/**
 * This class represents a sheet in an Excel Workbook file. By default, it has
 * just one sheet. You add HashTables as additional sheets using the addSheet
 * method. When saving this ExcelTable all its sheets are saved too.
 * 
 * @author U401455
 *
 */
public class ExcelHashTable extends HashTable implements Storage {
	private static final String EXCEL_DEFAULT_SHEET_NAME = "Sheet1";
	private static final String EXCEL_DATETIME_FORMAT_STR = "yyyy-MM-dd HH:mm:ss";
	private static final SimpleDateFormat EXCEL_DATETIME_FORMAT = new SimpleDateFormat(EXCEL_DATETIME_FORMAT_STR);
	String filePath = null;
	ExcelWorkbook workbook = new ExcelWorkbook();

	Map<String, HashTable> excelSheets = new LinkedHashMap<>();

	public ExcelHashTable(String aFilePath, Object pDefaultValue, SimpleDateFormat pDefaultDateFormat) {
		super(pDefaultValue, pDefaultDateFormat);

		resolveFilePath(aFilePath, new HashMap<String, Object>());
	}

	public ExcelHashTable(String aFilePath, String... pColumnNameList) {
		super(pColumnNameList);

		this.setDefaultDateFormat(EXCEL_DATETIME_FORMAT);
		resolveFilePath(aFilePath, new HashMap<String, Object>());
	}

	public ExcelHashTable(String aFilePath, Map<String, Object> pParams) {
		super(pParams);

		SimpleDateFormat defaultDateFormat = (SimpleDateFormat) pParams.getOrDefault("DateFormat",
				EXCEL_DATETIME_FORMAT);

		this.setDefaultDateFormat(defaultDateFormat);
		resolveFilePath(aFilePath, pParams);
	}

	public ExcelHashTable(String aFilePath) {
		this(aFilePath, null, EXCEL_DATETIME_FORMAT);
	}

	public ExcelHashTable() {
		this(null);
	}

	public HashTable getSheet(String pSheetName) {
		return excelSheets.get(pSheetName);
	}

	public void addSheet(String pSheetName) {
		this.excelSheets.put(pSheetName, this);
	}

	public void addSheet(String pSheetName, HashTable pSheetTable) {
		this.excelSheets.put(pSheetName, pSheetTable);
	}

	@Override
	public void saveAs(String pFilePath) throws IOException {
		File aFile = new File(pFilePath);

		if (excelSheets.isEmpty()) {
			excelSheets.put(EXCEL_DEFAULT_SHEET_NAME, this);
		}

		for (String sheetName : excelSheets.keySet()) {
			HashTable aSheetTable = excelSheets.get(sheetName);
			ExcelTable excelSheet = workbook.addSheet(sheetName);

			Set<String> columnNames = aSheetTable.getColumnNames();
			Object[] columnList = columnNames.toArray();
			int numberOfColumns = columnNames.size();

			int newRow = excelSheet.newRow();

			// write header row
			for (int i = 0; i < numberOfColumns; i++) {
				String colName = (String) columnList[i];

				excelSheet.setCellValue(newRow, colName, colName);
			}

			// write data
			for (int rowNo = 0; rowNo < aSheetTable.lenght(); rowNo++) {
				newRow = excelSheet.newRow();

				for (int i = 0; i < numberOfColumns; i++) {
					String colName = (String) columnList[i];

					Object valueObject = aSheetTable.getCellValue(rowNo, colName);

					if (valueObject == null) {
						valueObject = aSheetTable.getDefaultValue();

						if (valueObject == null) {
							continue;
						}
					}

					excelSheet.setCellValue(rowNo, colName, valueObject);
				}
			}
		}

		CsvTable.createDirectoriesInPath(aFile);
		workbook.save();
	}

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

	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());

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

			this.addColumn(col);
		}
	}

	@Override
	public void read() throws IOException {

		workbook = new ExcelWorkbook(filePath);
		// Workbook workbook =
		// StreamingReader.builder().rowCacheSize(100).bufferSize(4096).open(inputStream);

		Integer rowNoLimitInt = getOption(OPTION_LIMIT_NUMBER_ROWS);
		int rowNoLimit = rowNoLimitInt == null ? -1 : rowNoLimitInt;

		workbook.read();

		int noRows = Math.min(workbook.lenght(), rowNoLimit);
		Collection<String> columns = workbook.getColumnLabels();

		for (int rowNo = 1; rowNo < noRows; rowNo++) {
			for (String colName : columns) {
				if (useColumn(colName)) {
					Object value = workbook.getCellValue(rowNo, colName);
					this.setCellValue(rowNo, colName, value);
				}
			}

			workbook.setKey(rowNo);
		}
	}

}
