package smash.appointment.parse;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public abstract class SubjectParser {
	private static final SimpleDateFormat	DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
	Logger																logger				 = Logger.getLogger(SubjectParser.class);
	DataFormatter													df						 = new DataFormatter();

	public List<Subject> processExcel(String filename) throws EncryptedDocumentException, InvalidFormatException, IOException, ParseException {
		List<Subject> result = new ArrayList<>();
		InputStream inp = new FileInputStream(filename);
		Workbook workbook = WorkbookFactory.create(inp);
		Iterator<Sheet> sheetIter = workbook.sheetIterator();
		while (sheetIter.hasNext()) {
			Sheet sheet = sheetIter.next();
			String name = sheet.getSheetName().trim();
			if (name.trim().toLowerCase().equals(getSheetName().toLowerCase())) {
				result.addAll(processSheet(sheet));
			} else {
				logger.debug(filename + "Skipping sheet: " + name);
			}
		}
		return result;
	}

	private List<Subject> processSheet(Sheet sheet) {
		List<Subject> result = new ArrayList<>();
		int rowCount = sheet.getPhysicalNumberOfRows();
		for (int rowId = getInitRow(); rowId < rowCount; rowId++) {
			Row subjectRow = sheet.getRow(rowId);
			Subject subject = parseSubject(subjectRow);
			if (subject != null) {
				result.add(subject);
			}
		}
		return result;
	}

	private Subject parseSubject(Row row) {
		String screeningNumber = parseScreeningNumber(row);
		if (screeningNumber == null || screeningNumber.isEmpty()) {
			logger.debug("Skipping row: (" + getString(row.getCell(0)) + ", " + getString(row.getCell(1)) + ")");
			return null;
		}
		String name = parseName(row);
		String surname = parseSurname(row);
		String ndNumber = parseNdNumber(row);
		Subject result = new Subject(name, surname, ndNumber, screeningNumber);

		result.setRemarks(parseRemarks(row));
		result.setAddress(parseAddress(row));
		result.setZipCode(parseZipCode(row));
		result.setCity(parseCity(row));
		result.setCountry(parseCountry(row));
		result.setPhone1(parsePhone1(row));
		result.setPhone2(parsePhone2(row));
		result.setPhone3(parsePhone3(row));
		result.setMail(parseMail(row));
		result.setDiagnosisYear(parseDiagnosisYear(row));
		result.setDiagnosis(parseDiagnosis(row));
		result.setReferal(parseReferal(row));
		result.setAddDate(parseAddDate(row));
		result.setmPowerId(parsemPowerId(row));
		result.setBirthDate(parseBirthDate(row));
		result.setType(parseType(row));
		result.setLanguages(parseLanguages(row));
		result.setToBeSeenAt(parseToBeSeenAt(row));
		result.setDead(parseDead(row));
		result.setResigned(parseResigned(row));

		return result;
	}

	protected abstract boolean parseDead(Row row);

	protected abstract boolean parseResigned(Row row);

	protected abstract String parseToBeSeenAt(Row row);

	protected abstract List<String> parseLanguages(Row row);

	protected abstract SubjectType parseType(Row row);

	protected abstract String parseBirthDate(Row row);

	protected abstract String parsemPowerId(Row row);

	protected abstract String parseAddDate(Row row);

	protected abstract String parseReferal(Row row);

	protected abstract String parseDiagnosisYear(Row row);

	protected abstract String parseDiagnosis(Row row);

	protected abstract String parseMail(Row row);

	protected abstract String parsePhone3(Row row);

	protected abstract String parsePhone2(Row row);

	protected abstract String parsePhone1(Row row);

	protected abstract String parseCity(Row row);

	protected abstract String parseCountry(Row row);

	protected abstract String parseZipCode(Row row);

	protected abstract String parseAddress(Row row);

	protected abstract String parseRemarks(Row row);

	protected abstract String parseScreeningNumber(Row row);

	protected abstract String parseName(Row row);

	protected abstract String parseSurname(Row row);

	protected abstract String parseNdNumber(Row row);

	protected abstract String getSheetName();

	protected abstract int getInitRow();

	protected String getString(Cell cell) {
		if (cell == null) {
			return "";
		}
		if (cell.getCellTypeEnum().equals(CellType.STRING)) {
			return cell.getStringCellValue().trim();
		}
		return df.formatCellValue(cell).trim();
	}

	protected String getComments(Cell cell) {
		Comment comment = cell.getCellComment();
		if (comment != null) {
			RichTextString richTextString = comment.getString();
			if (richTextString != null) {
				return richTextString.getString();

			}
		}
		return "";
	}

	protected String getDate(Cell cell, Calendar defaultDate) {
		String defaultDateString = "";
		if (defaultDate != null) {
			defaultDateString = DATE_FORMATTER.format(defaultDate.getTime());
		}
		if (cell == null) {
			return defaultDateString;
		}
		String result = null;
		if (cell.getCellTypeEnum().equals(CellType.STRING)) {
			result = getString(cell);
		} else if (HSSFDateUtil.isCellDateFormatted(cell)) {
			Date date = cell.getDateCellValue();
			if (date != null) {
				result = DATE_FORMATTER.format(date);
			} else {
				result = defaultDateString;
			}
		} else {
			result = getString(cell);
		}
		if (result == null || result.trim().isEmpty()) {
			result = defaultDateString;
		}
		result = fixDate(result);
		return result;
	}

	protected String fixDate(String result) {
		result = result.replaceAll("\\?", "");
		result = result.replaceAll("jan", "01");
		result = result.replaceAll("fev", "02");
		result = result.replaceAll("mar", "03");
		result = result.replaceAll("avr", "04");
		result = result.replaceAll("may", "05");
		result = result.replaceAll("aou", "08");
		result = result.replaceAll("cot", "08");
		result = result.replaceAll("sep", "09");
		result = result.replaceAll("oct", "10");
		if (result.indexOf("/") >= 0) {
			String tmp[] = result.split("/");
			result = tmp[2] + "-" + tmp[1] + "-" + tmp[0];
		}
		return result;
	}

	protected String parseDateOfBirth(Cell cell) {
		String date = getString(cell).replaceAll(" ", "");
		if (date.length() < 8) {
			return "";
		}
		String year = date.substring(0, 4);
		String month = date.substring(4, 6);
		String day = date.substring(6, 8);
		String result = year + "-" + month + "-" + day;
		return result;
	}

}