/**
 * Copyright (c) 2004, yher2 project
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, 
 *   this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * * Neither the name of the nor the names of its contributors may be used to endorse or 
 *   promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */
package net.yher2.junit.db.excel;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.yher2.commons.io.Path;
import net.yher2.junit.db.data.ColumnData;
import net.yher2.junit.db.data.Header;
import net.yher2.junit.db.data.Row;
import net.yher2.junit.db.data.Table;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

/**
 * @auther  hisaboh
 */
public class ExcelReader {
	Log log = LogFactory.getLog(this.getClass());
	HSSFWorkbook book;
	Map metaDataMap;
	String path;
	
	public ExcelReader(Path resourcePath) throws IOException {
		this.path = resourcePath.getPath();
		book = new HSSFWorkbook(new POIFSFileSystem(resourcePath.getInputStream()));
		metaDataMap = new HashMap();
	}
	
	public Table[] read() throws IllegalStateException {
		List tableList = new ArrayList();
		int sheetCount = book.getNumberOfSheets();
		for (int i=0; i<sheetCount; i++) {
			try {
				tableList.add(readSheet(book.getSheetName(i), book.getSheetAt(i)));
			} catch (IllegalStateException e) {
				IllegalStateException ex = new IllegalStateException(path + ":Sheet["+book.getSheetName(i)+"]:" + e.getMessage());
				ex.setStackTrace(e.getStackTrace());
				throw ex;
			}
		}
		return (Table[])tableList.toArray(new Table[tableList.size()]);
	}
	
	private Table readSheet(String sheetName, HSSFSheet sheet) throws IllegalStateException {
		Table table = new Table(sheetName);
		int lastRowNum = sheet.getLastRowNum();
		
		HSSFRow header = sheet.getRow(0);
		if (header == null) throw new IllegalStateException("The sheet does not have header.");
		table.setHeader(readHeaderRow(header));
		for (int j=1; j<=lastRowNum; j++) {
			table.addRow(readRow(sheet.getRow(j)));
		}
		return table;
	}
	
	private Header[] readHeaderRow(HSSFRow header) {
		List list = new ArrayList();
		if (header == null) throw new IllegalStateException("There is no Header.");
		int lastCellNum = header.getLastCellNum();
		if (lastCellNum == 0) throw new IllegalStateException("There is no Header.");
		// なぜかgetLastCellNumは実際の最後のCellNum+1を返す。(Excelの挙動か？)
		for (int i=0; i<lastCellNum; i++) {
			HSSFCell cell = header.getCell((short)i);
			if (cell == null) throw new IllegalStateException("There is illegal header at "+i+"(0 based).");
			
			switch (cell.getCellType()) {
			case HSSFCell.CELL_TYPE_BOOLEAN:
			case HSSFCell.CELL_TYPE_NUMERIC:
			case HSSFCell.CELL_TYPE_STRING:
			case HSSFCell.CELL_TYPE_FORMULA:
				list.add(new Header(cell.getStringCellValue().trim(), isPrimaryKey(cell)));
				break;

			case HSSFCell.CELL_TYPE_BLANK:
			case HSSFCell.CELL_TYPE_ERROR:
			default:
				throw new IllegalStateException("There is illegal header.");
			}
		}
		return (Header[])list.toArray(new Header[list.size()]);
	}
	
	private boolean isPrimaryKey(HSSFCell cell) {
		return (book.getFontAt(cell.getCellStyle().getFontIndex()).getBoldweight() == HSSFFont.BOLDWEIGHT_BOLD);
	}
	
	private Row readRow(HSSFRow hssfRow) {
		Row row = new Row();
		int lastCellNum = hssfRow.getLastCellNum();
		// なぜかgetLastCellNumは実際の最後のCellNum+1を返す。(Excelの挙動か？)
		for (int i=0; i<lastCellNum; i++) {
			HSSFCell cell = hssfRow.getCell((short)i);
			row.add(ColumnData.getInstance(cell));
		}
		return row;
	}
}
