package junkutil.excel;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
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;

/**
 * Excelを操作する
 * @author Hiroyuki Shiota
 */
public class ExcelUtil {
	HSSFWorkbook workbook;
	HSSFSheet sheet;
	HSSFCellStyle style;
	HSSFFont selectedFont;
	String fontName;
	int fontSize;
	
	/**
	 * コンストラクタ
	 */
	public ExcelUtil() {
		fontName = "ＭＳ ゴシック";
		fontSize = 11;
	}
	
	/**
	 * デフォルトのフォントが指定できるコンストラクタ
	 * @param fontName
	 * @param size
	 */
	public ExcelUtil(String fontName, int fontSize) {
		this.fontName = fontName;
		this.fontSize = fontSize;
	}
	
	/**
	 * メモリを開放する
	 */
	public void free() {
		workbook = null;
		sheet = null;
		style = null;
		selectedFont = null;
		fontName = null;
	}
	
	/**
	 * ブックを作成する
	 */
	public void create() {
		workbook = new HSSFWorkbook();
		initFont();
		setFont(fontName, fontSize);
	}
	
	/**
	 * Excelファイルを読み込む
	 * @param file
	 * @throws IOException
	 */
	public void read(File file) throws IOException {
		BufferedInputStream bufInput = null;
		try {
			// テンプレートのExcelファイル読み込み
			bufInput = new BufferedInputStream(new FileInputStream(file));			
			POIFSFileSystem fileSys = new POIFSFileSystem(bufInput);
			// ワークブックの作成
			workbook = new HSSFWorkbook(fileSys);
			initFont();
			setFont(fontName, fontSize);
			if (getNumberOfSheets() > 0) selectSheet(0);
		} catch (IOException e) {
			throw e;
		} finally {
			try {
				if (bufInput != null) bufInput.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Excelファイルを書き出す
	 * @param file
	 * @throws IOException
	 */
	public void write(File file) throws IOException {
		BufferedOutputStream bufOutput = null;
		try {
			bufOutput = new BufferedOutputStream(new FileOutputStream(file));
			// ワークブックの書き出し
			workbook.write(bufOutput);
			bufOutput.flush();
			bufOutput.close();
		} catch (IOException e) {
			throw e;
		} finally {
			try {
				if (bufOutput != null) bufOutput.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * ワークブックを取得する
	 * @return
	 */
	public HSSFWorkbook getWorkbook() {
		return workbook;
	}
	
	/**
	 * シートを取得する
	 * @return
	 */
	public HSSFSheet getSheet() {
		return sheet;
	}
	
	/**
	 * シートを選択する
	 * @param i
	 */
	public void selectSheet(int i) {
		sheet = workbook.getSheetAt(i);
	}
	
	/**
	 * シートを選択する
	 * @param i
	 */
	public void selectSheet(String name) {
		sheet = workbook.getSheet(name);
	}
	
	/**
	 * シートを作成する
	 * @param name
	 * @return
	 */
	public int createSheet(String name) {
		workbook.createSheet(name);
		return getNumberOfSheets()-1;
	}
	
	/**
	 * シートを選択する
	 * @param name
	 * @return
	 */
	public int createSheetAndSelect(String name) {
		workbook.createSheet(name);
		int sheetNo = getNumberOfSheets()-1;
		selectSheet(sheetNo);
		return sheetNo;
	}
	
	/**
	 * シートを削除する
	 * @param i
	 */
	public void removeSheet(int i) {
		workbook.removeSheetAt(i);
	}
	
	/**
	 * シート数を返す
	 * @return
	 */
	public int getNumberOfSheets() {
		return workbook.getNumberOfSheets();
	}
	
	/**
	 * セルの値セット（文字）
	 * @param iRow
	 * @param iCol
	 * @param intVal
	 */
	public void setCellString(int iRow, int iCol, String strVal) {
		if (sheet == null) {
			throw new NullPointerException("Sheet is null");
		}
		HSSFCell cell = getCell(sheet, iRow, iCol);
		//cell.setEncoding(HSSFCell.ENCODING_UTF_16);
		cell.setCellValue(strVal);
		setCellFont(cell);
	}

	/**
	 * セルの値セット（数値）
	 * @param iRow
	 * @param iCol
	 * @param intVal
	 */
	public void setCellNumeric(int iRow, int iCol, double intVal) {
		if (sheet == null) {
			throw new NullPointerException("Sheet is null");
		}
		HSSFCell cell = getCell(sheet, iRow, iCol);
		//cell.setEncoding(HSSFCell.ENCODING_UTF_16);
		cell.setCellValue(intVal);
		setCellFont(cell);
	}

	/**
	 * セルの値取得（文字）
	 * @param iRow
	 * @param iCol
	 * @return
	 */
	public String getCellString(int iRow, int iCol) {
		if (sheet == null) {
			throw new NullPointerException("Sheet is null");
		}
		HSSFCell cell = getCell(sheet, iRow, iCol);
		return cell.getStringCellValue();
	}

	/**
	 * セルの値取得（数値）
	 * @param iRow
	 * @param iCol
	 * @return
	 */
	public double getCellNumeric(int iRow, int iCol) {
		if (sheet == null) {
			throw new NullPointerException("Sheet is null");
		}
		HSSFCell cell = getCell(sheet, iRow, iCol);
		return cell.getNumericCellValue();
	}

	/**
	 * セルオブジェクトを取得
	 * @param sheet
	 * @param iRow
	 * @param iCol
	 * @return
	 */
	private HSSFCell getCell(HSSFSheet sheet, int iRow, int iCol) {
		HSSFRow row = sheet.getRow(iRow);
		if (row == null) {
			row = sheet.createRow((short)iRow);
		}
		HSSFCell cell = row.getCell((short)iCol);
		if (cell == null) {
			cell = row.createCell((short)iCol);
		}
		return cell;
	}
	
	/**
	 * セルオブジェクトを取得
	 * @param sheet
	 * @param iRow
	 * @param iCol
	 * @return
	 */
	private HSSFCell getCellOrNull(HSSFSheet sheet, int iRow, int iCol) {
		HSSFRow row = sheet.getRow(iRow);
		if (row == null) return null;
		HSSFCell cell = row.getCell((short)iCol);
		return cell;
	}
	
	/**
	 * セルのフォントを設定する
	 * @param cell
	 */
	private void setCellFont(HSSFCell cell) {
		HSSFCellStyle style = cell.getCellStyle();
		if (style != null) {
			style.setFont(selectedFont);
		} else {
			style = this.style;
			cell.setCellStyle(style);
		}
	}

	/**
	 * フォント名の初期化をします。
	 */
	private void initFont() {
		for (int i = 0; i < workbook.getNumberOfFonts(); i++) {
			HSSFFont font = workbook.getFontAt((short)i);
			font.setFontName(fontName);
			font.setFontHeightInPoints((short)fontSize);
		}
	}
	
	/**
	 * フォントを設定します。
	 * @param fontName
	 * @param size
	 */
	public void setFont(String fontName, int size) {
		selectedFont = workbook.createFont();
		selectedFont.setFontName(fontName);
		selectedFont.setFontHeightInPoints((short)size);
		style = workbook.createCellStyle();
		style.setFont(selectedFont);
	}

}
