package net.w_horse.excelpojo.excel;

import java.lang.annotation.Annotation;

import net.w_horse.excelpojo.ExcelPOJOBridge;
import net.w_horse.excelpojo.annotation.ExcelPOJOAnnotationParser;
import net.w_horse.excelpojo.xml.ExcelPOJOXmlParser;
import net.w_horse.excelpojo.xml.tag.Use;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.w3c.dom.Element;

public abstract class AbstractCellSeeker {
	private ExcelPOJOBridge excelPOJOBridge;
	private String use = Use.NONE.getValue();

	public abstract void set(Element element, ExcelPOJOXmlParser parser);
	public abstract void set(Annotation annotation, ExcelPOJOAnnotationParser parser) throws ClassNotFoundException, LinkageError;
	public abstract boolean verify() throws IllegalArgumentException;

	public abstract Object seekCellValue(HSSFSheet sheet, Class<?> requiredType) throws ClassNotFoundException, LinkageError, CellNotFoundException;
	protected abstract Offset seekCellPosition(HSSFSheet sheet) throws CellNotFoundException;
	protected abstract Offset seekCellPosition(HSSFSheet sheet, Offset basePosition, Offset offset) throws CellNotFoundException;
	public abstract void setValue(HSSFSheet sheet, Object value) throws CellNotFoundException;
	protected abstract void setValue(HSSFSheet sheet, Offset basePosition, Offset offset, Object value) throws CellNotFoundException;


	protected <T>T getCellValue(HSSFSheet sheet, Offset cellPosition, Class<T> requiredType) {
		return getCellValue(sheet, cellPosition, new Offset(), requiredType);
	}

	protected <T>T getCellValue(HSSFSheet sheet, Offset basePosition, Offset offset, Class<T> requiredType) {
		return getCellValue(getCell(sheet, basePosition, offset), requiredType);
	}

	public <T>T getCellValue(HSSFCell cell, Class<T> requiredType) {
		return ExcelUtils.getCellValue(cell, requiredType);
	}
	protected HSSFCell createCell(HSSFSheet sheet, Offset basePosition, Offset offset) {
		HSSFRow row = sheet.getRow(basePosition.rowIndex + offset.rowIndex);
		if (row == null) {
			row = sheet.createRow(basePosition.rowIndex + offset.rowIndex);
		}
		HSSFCell cell = row.getCell(basePosition.colIndex + offset.colIndex);
		if (cell == null) {
			cell = row.createCell(basePosition.colIndex + offset.colIndex);
		}
		return cell;
	}

	protected HSSFCell getCell(HSSFSheet sheet, Offset cellPosition) {
		return getCell(sheet, cellPosition, new Offset());
	}
	protected HSSFCell getCell(HSSFSheet sheet, Offset basePosition, Offset offset) {
		if (basePosition == null) return null;

		return createCell(sheet, basePosition, offset);
	}

	protected void setCellValue(HSSFCell cell, Object value) {
		ExcelUtils.setCellValue(cell, value);
	}

	public void setExcelPOJOBridge(ExcelPOJOBridge excelPOJOBridge) {
		this.excelPOJOBridge = excelPOJOBridge;
	}
	public ExcelPOJOBridge getExcelPOJOBridge() {
		return excelPOJOBridge;
	}

	public void setUse(String use) {
		this.use = use;
	}

	public String getUse() {
		return use;
	}

	protected class Offset {
		public int rowIndex = 0;
		public int colIndex = 0;

		public Offset() {
		}
		public Offset(Offset offset) {
			this.rowIndex = offset.rowIndex;
			this.colIndex = offset.colIndex;
		}
		public Offset(int rowIndex, int colIndex) {
			this.rowIndex = rowIndex;
			this.colIndex = colIndex;
		}

		public Offset add(Offset offset) {
			this.rowIndex += offset.rowIndex;
			this.colIndex += offset.colIndex;

			return this;
		}
		public Offset negate() {
			return new Offset(-this.rowIndex, -this.colIndex);
		}
	}
}
