/*
 * MosP - Mind Open Source Project    http://www.mosp.jp/
 * Copyright (C) MIND Co., Ltd.       http://www.e-mind.co.jp/
 * 
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jp.mosp.platform.bean.file.impl;

import java.io.InputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import jp.mosp.framework.base.MospException;
import jp.mosp.framework.base.MospParams;
import jp.mosp.platform.bean.file.HumanImportBeanInterface;
import jp.mosp.platform.bean.human.EntranceReferenceBeanInterface;
import jp.mosp.platform.bean.human.EntranceRegistBeanInterface;
import jp.mosp.platform.bean.human.RetirementReferenceBeanInterface;
import jp.mosp.platform.bean.human.RetirementRegistBeanInterface;
import jp.mosp.platform.bean.human.impl.HumanRegistBean;
import jp.mosp.platform.constant.PlatformFileConst;
import jp.mosp.platform.dao.file.ImportFieldDaoInterface;
import jp.mosp.platform.dto.file.ImportDtoInterface;
import jp.mosp.platform.dto.file.ImportFieldDtoInterface;
import jp.mosp.platform.dto.human.EntranceDtoInterface;
import jp.mosp.platform.dto.human.HumanDtoInterface;
import jp.mosp.platform.dto.human.RetirementDtoInterface;

/**
 * 人事マスタインポートクラス。
 */
public class HumanImportBean extends HumanRegistBean implements HumanImportBeanInterface {
	
	/**
	 * 人事入社情報参照クラス。<br>
	 */
	protected EntranceReferenceBeanInterface	entranceRefer;
	
	/**
	 * 人事退職情報参照クラス。<br>
	 */
	protected RetirementReferenceBeanInterface	retirementRefer;
	
	/**
	 * 人事入社情報登録クラス。<br>
	 */
	protected EntranceRegistBeanInterface		entranceRegist;
	
	/**
	 * 人事退職情報登録クラス。<br>
	 */
	protected RetirementRegistBeanInterface		retirementRegist;
	
	/**
	 * 人事情報リスト。<br>
	 */
	protected List<HumanDtoInterface>			humanList;
	
	/**
	 * 人事入社情報リスト。<br>
	 */
	protected List<EntranceDtoInterface>		entranceList;
	
	/**
	 * 人事退職情報リスト。<br>
	 */
	protected List<RetirementDtoInterface>		retirementList;
	
	/**
	 * 人事マスタ情報。<br>
	 * データ取得時及び登録時に、対象人事マスタ情報を保持しておく。<br>
	 */
	protected HumanDtoInterface					human;
	

	/**
	 * {@link HumanRegistBean#HumanRegistBean()}を実行する。<br>
	 */
	public HumanImportBean() {
		super();
	}
	
	/**
	 * {@link HumanRegistBean#HumanRegistBean(MospParams, Connection)}を実行する。<br>
	 * @param mospParams MosP処理情報
	 * @param connection DBコネクション
	 */
	public HumanImportBean(MospParams mospParams, Connection connection) {
		super(mospParams, connection);
	}
	
	@Override
	public void initBean() throws MospException {
		super.initBean();
		// Bean準備
		entranceRefer = (EntranceReferenceBeanInterface)createBean(EntranceReferenceBeanInterface.class);
		retirementRefer = (RetirementReferenceBeanInterface)createBean(RetirementReferenceBeanInterface.class);
		entranceRegist = (EntranceRegistBeanInterface)createBean(EntranceRegistBeanInterface.class);
		retirementRegist = (RetirementRegistBeanInterface)createBean(RetirementRegistBeanInterface.class);
	}
	
	@Override
	public int importFile(ImportDtoInterface importDto, InputStream requestedFile) throws MospException {
		// アップロードファイルを登録情報リストに変換
		List<String[]> dataList = getDataList(importDto, requestedFile);
		// 登録情報リストから人事マスタ情報に変換
		getTargetLists(importDto, dataList);
		// エラー確認
		if (mospParams.hasErrorMessage()) {
			return 0;
		}
		// 人事マスタ情報毎に登録
		for (int i = 0; i < humanList.size(); i++) {
			// 人事マスタ情報登録
			registHumanDto(humanList.get(i));
			// 人事入社情報登録
			registEntranceDto(entranceList.get(i));
			// 人事入社情報登録
			registRetirementDto(retirementList.get(i));
		}
		// 登録件数取得
		return humanList.size();
	}
	
	/**
	 * 登録対象リスト群を取得する。<br>
	 * インポートマスタ情報に従い、登録情報リストから人事マスタ情報リストに変換する。<br>
	 * インポート不能登録情報が存在した場合は、MosP処理情報にエラーメッセージを残す。<br>
	 * @param importDto インポートマスタ情報
	 * @param dataList  登録情報リスト
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected void getTargetLists(ImportDtoInterface importDto, List<String[]> dataList) throws MospException {
		// 人事マスタリスト準備
		humanList = new ArrayList<HumanDtoInterface>();
		// 人事入社情報リスト準備
		entranceList = new ArrayList<EntranceDtoInterface>();
		// 人事退職情報リスト準備
		retirementList = new ArrayList<RetirementDtoInterface>();
		// インポートフィールド情報取得準備
		ImportFieldDaoInterface importFieldDao = (ImportFieldDaoInterface)createDao(ImportFieldDaoInterface.class);
		// インポートフィールド情報取得
		List<ImportFieldDtoInterface> fieldList = importFieldDao.findForList(importDto.getImportCode());
		// 登録情報リスト内の各登録情報長を確認
		checkCsvLength(fieldList, dataList);
		// エラー確認
		if (mospParams.hasErrorMessage()) {
			return;
		}
		// 登録情報リスト毎に処理
		for (int i = 0; i < dataList.size(); i++) {
			// 登録情報取得
			String[] data = dataList.get(i);
			// 人事マスタ情報取得及び確認
			HumanDtoInterface humanDto = getHumanDto(fieldList, data, i);
			if (humanDto != null) {
				// 人事マスタリストに追加
				humanList.add(humanDto);
			} else {
				// 人事情報が取得できなかった場合
				continue;
			}
			// 人事入社情報を取得しリストに追加
			entranceList.add(getEntranceDto(fieldList, data, i));
			// 人事退職情報取得及び確認
			retirementList.add(getRetirementDto(fieldList, data, i));
		}
	}
	
	/**
	 * 人事マスタ情報を取得する。<br>
	 * インポートフィールド情報リストに従い、登録情報リストから人事マスタ情報に変換する。<br>
	 * インポート不能登録情報が存在した場合は、MosP処理情報にエラーメッセージを残す。<br>
	 * インポート不能登録情報の場合は、nullを返す。<br>
	 * @param fieldList インポートフィールド情報リスト
	 * @param data      登録情報
	 * @param row       行インデックス
	 * @return 人事マスタ情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected HumanDtoInterface getHumanDto(List<ImportFieldDtoInterface> fieldList, String[] data, int row)
			throws MospException {
		// 社員コード及び有効日取得
		String employeeCode = getFieldValue(PlatformFileConst.FIELD_EMPLOYEE_CODE, fieldList, data);
		Date activateDate = getDateFieldValue(PlatformFileConst.FIELD_ACTIVATE_DATE, fieldList, data);
		// 社員コード確認
		if (employeeCode == null || employeeCode.isEmpty()) {
			// エラーメッセージ追加
			addRequiredErrorMessage(getNameEmployeeCode(), Integer.valueOf(row));
			return null;
		}
		// 有効日確認
		if (activateDate == null) {
			// エラーメッセージ追加
			addRequiredErrorMessage(getNameActivateDate(), Integer.valueOf(row));
			return null;
		}
		// 有効日における最新の人事マスタ情報を取得
		human = dao.findForEmployeeCode(employeeCode, activateDate);
		// 有効日における最新の人事マスタ情報が無く社員コードが使われている場合
		if (human == null && isEmployeeCodeUsed(employeeCode)) {
//			// エラーメッセージ設定
//			addEmployeeHistoryNotExistMessage(row, employeeCode, activateDate);
//			return null;
			human = getInitDto();
			// 個人IDをセット
			human.setPersonalId(getOldestHumanDto(employeeCode).getPersonalId());
		}
		// 人事マスタDTO準備(新規登録の場合)
		if (human == null) {
			// 個人IDはnull
			human = getInitDto();
		}
		// 登録情報の値をDTOに設定
		setHumanDtoFields(fieldList, data, human);
		// 入力チェック
		validate(human, Integer.valueOf(row));
		return human;
	}
	
	/**
	 * 人事入社情報を取得する。<br>
	 * インポートフィールド情報リストに従い、登録情報リストから人事入社情報に変換する。<br>
	 * インポート不能登録情報が存在した場合は、MosP処理情報にエラーメッセージを残す。<br>
	 * インポート不能登録情報の場合は、nullを返す。<br>
	 * @param fieldList インポートフィールド情報リスト
	 * @param data      登録情報
	 * @param row       行インデックス
	 * @return 人事入社情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected EntranceDtoInterface getEntranceDto(List<ImportFieldDtoInterface> fieldList, String[] data, int row)
			throws MospException {
		// 登録情報の内容を取得(登録情報に含まれない場合はnull)
		Date entranceDate = getDateFieldValue(PlatformFileConst.FIELD_ENTRANCE_DATE, fieldList, data);
		// 登録情報確認
		if (entranceDate == null) {
			// 登録情報に入社日が含まれない場合
			return null;
		}
		// 人事入社情報準備
		EntranceDtoInterface entrance = null;
		// 個人ID確認
		if (human.getPersonalId() != null) {
			entrance = entranceRefer.getEntranceInfo(human.getPersonalId());
		}
		// 人事入社情報確認
		if (entrance == null) {
			entrance = entranceRegist.getInitDto();
		}
		// 人事入社情報に登録情報の内容を設定
		entrance.setEntranceDate(entranceDate);
		// 入力チェック
		entranceRegist.validate(entrance, Integer.valueOf(row));
		return entrance;
	}
	
	/**
	 * 人事退職情報を取得する。<br>
	 * インポートフィールド情報リストに従い、登録情報リストから人事退職情報に変換する。<br>
	 * インポート不能登録情報が存在した場合は、MosP処理情報にエラーメッセージを残す。<br>
	 * インポート不能登録情報の場合は、nullを返す。<br>
	 * @param fieldList インポートフィールド情報リスト
	 * @param data      登録情報
	 * @param row       行インデックス
	 * @return 人事退職情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected RetirementDtoInterface getRetirementDto(List<ImportFieldDtoInterface> fieldList, String[] data, int row)
			throws MospException {
		// 登録情報の内容を取得(登録情報に含まれない場合はnull)
		Date retirementDate = getDateFieldValue(PlatformFileConst.FIELD_RETIREMENT_DATE, fieldList, data);
		String retirementReason = getFieldValue(PlatformFileConst.FIELD_RETIREMENT_REASON, fieldList, data);
		String retirementDetail = getFieldValue(PlatformFileConst.FIELD_RETIREMENT_DETAIL, fieldList, data);
		// 登録情報確認
		if (retirementDate == null && (retirementReason == null || retirementReason.isEmpty())
				&& (retirementDetail == null || retirementDetail.isEmpty())) {
			// 登録情報に退職関連情報が含まれない場合
			return null;
		}
		// 人事退職情報準備
		RetirementDtoInterface retirement = null;
		// 個人ID確認
		if (human.getPersonalId() != null) {
			retirement = retirementRefer.getRetireInfo(human.getPersonalId());
		}
		// 人事退職情報確認
		if (retirement == null) {
			retirement = retirementRegist.getInitDto();
		}
		// 人事退職情報に登録情報の内容を設定
		if (retirementDate != null) {
			retirement.setRetirementDate(retirementDate);
		}
		if (retirementReason != null) {
			retirement.setRetirementReason(retirementReason);
		} else if (retirement.getRetirementReason() == null) {
			retirement.setRetirementReason("");
		}
		if (retirementDetail != null) {
			retirement.setRetirementDetail(retirementDetail);
		} else if (retirement.getRetirementDetail() == null) {
			retirement.setRetirementDetail("");
		}
		// 入力チェック
		retirementRegist.validate(retirement, Integer.valueOf(row));
		return retirement;
	}
	
	/**
	 * 社員コードが使用されているかどうかを確認する。<br>
	 * @param employeeCode 社員コード
	 * @return 確認結果(true：使用されている、false：使用されていない)
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected boolean isEmployeeCodeUsed(String employeeCode) throws MospException {
		// 社員コードで人事マスタ情報リストを取得
		List<HumanDtoInterface> list = dao.findForEmployeeCode(employeeCode);
		// 人事マスタ情報リスト確認
		if (list.isEmpty()) {
			return false;
		}
		return true;
	}
	
	/**
	 * 最も古い人事マスタ情報を取得する。
	 * @param employeeCode 社員コード
	 * @return 最も古い人事マスタ情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected HumanDtoInterface getOldestHumanDto(String employeeCode) throws MospException {
		HumanDtoInterface dto = null;
		// 社員コードで人事マスタ情報リストを取得
		List<HumanDtoInterface> list = dao.findForEmployeeCode(employeeCode);
		for (HumanDtoInterface humanDto : list) {
			if (dto == null || humanDto.getActivateDate().before(dto.getActivateDate())) {
				dto = humanDto;
			}
		}
		return dto;
	}
	
	/**
	 * インポートフィールド情報リストに従い、登録情報の内容を人事マスタ情報のフィールドに設定する。<br>
	 * @param fieldList インポートフィールド情報リスト
	 * @param data      登録情報
	 * @param human     設定対象人事マスタ情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected void setHumanDtoFields(List<ImportFieldDtoInterface> fieldList, String[] data, HumanDtoInterface human)
			throws MospException {
		// 登録情報の内容を取得(登録情報に含まれない場合はnull)
		String employeeCode = getFieldValue(PlatformFileConst.FIELD_EMPLOYEE_CODE, fieldList, data);
		Date activateDate = getDateFieldValue(PlatformFileConst.FIELD_ACTIVATE_DATE, fieldList, data);
		String lastName = getFieldValue(PlatformFileConst.FIELD_LAST_NAME, fieldList, data);
		String firstName = getFieldValue(PlatformFileConst.FIELD_FIRST_NAME, fieldList, data);
		String lastKana = getFieldValue(PlatformFileConst.FIELD_LAST_KANA, fieldList, data);
		String firstKana = getFieldValue(PlatformFileConst.FIELD_FIRST_KANA, fieldList, data);
		String workPlaceCode = getFieldValue(PlatformFileConst.FIELD_WORK_PLACE_CODE, fieldList, data);
		String employmentContractCode = getFieldValue(PlatformFileConst.FIELD_EMPLOYMENT_CONTRACT_CODE, fieldList, data);
		String sectionCode = getFieldValue(PlatformFileConst.FIELD_SECTION_CODE, fieldList, data);
		String positionCode = getFieldValue(PlatformFileConst.FIELD_POSITION_CODE, fieldList, data);
		// 人事マスタ情報に登録情報の内容を設定(nullの場合は設定しない)
		if (employeeCode != null) {
			human.setEmployeeCode(employeeCode);
		}
		if (activateDate != null) {
			human.setActivateDate(activateDate);
		}
		if (lastName != null) {
			human.setLastName(lastName);
		} else if (human.getLastName() == null) {
			human.setLastName("");
		}
		if (firstName != null) {
			human.setFirstName(firstName);
		} else if (human.getFirstName() == null) {
			human.setFirstName("");
		}
		if (lastKana != null) {
			human.setLastKana(lastKana);
		} else if (human.getLastKana() == null) {
			human.setLastKana("");
		}
		if (firstKana != null) {
			human.setFirstKana(firstKana);
		} else if (human.getFirstKana() == null) {
			human.setFirstKana("");
		}
		if (workPlaceCode != null) {
			human.setWorkPlaceCode(workPlaceCode);
		} else if (human.getWorkPlaceCode() == null) {
			human.setWorkPlaceCode("");
		}
		if (employmentContractCode != null) {
			human.setEmploymentContractCode(employmentContractCode);
		} else if (human.getEmploymentContractCode() == null) {
			human.setEmploymentContractCode("");
		}
		if (sectionCode != null) {
			human.setSectionCode(sectionCode);
		} else if (human.getSectionCode() == null) {
			human.setSectionCode("");
		}
		if (positionCode != null) {
			human.setPositionCode(positionCode);
		} else if (human.getPositionCode() == null) {
			human.setPositionCode("");
		}
		if (human.getMail() == null) {
			human.setMail("");
		}
	}
	
	/**
	 * 人事マスタ情報を登録する。<br>
	 * @param humanDto 人事マスタ情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected void registHumanDto(HumanDtoInterface humanDto) throws MospException {
		// 人事マスタ情報設定
		human = humanDto;
		// 個人ID確認
		if (human.getPersonalId() == null || human.getPersonalId().isEmpty()) {
			// 新規登録
			insert(human);
			return;
		}
		// 個人ID及び有効日で人事マスタ情報を取得
		if (dao.findForKey(human.getPersonalId(), human.getActivateDate()) == null) {
			// 履歴追加
			add(human);
			return;
		}
		// 履歴更新
		update(human);
	}
	
	/**
	 * 人事入社情報を登録する。<br>
	 * @param entrance 人事入社情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected void registEntranceDto(EntranceDtoInterface entrance) throws MospException {
		// 人事入社情報確認
		if (entrance == null) {
			return;
		}
		// 個人ID確認
		if (entrance.getPersonalId() == null || entrance.getPersonalId().isEmpty()) {
			// 個人ID設定
			entrance.setPersonalId(human.getPersonalId());
		}
		// 人事入社情報登録
		entranceRegist.regist(entrance);
	}
	
	/**
	 * 人事退職情報を登録する。<br>
	 * @param retirement 人事退職情報
	 * @throws MospException インスタンスの取得、或いはSQL実行に失敗した場合
	 */
	protected void registRetirementDto(RetirementDtoInterface retirement) throws MospException {
		// 人事退職情報確認
		if (retirement == null) {
			return;
		}
		// 個人ID確認
		if (retirement.getPersonalId() == null || retirement.getPersonalId().isEmpty()) {
			// 個人ID設定
			retirement.setPersonalId(human.getPersonalId());
		}
		// 人事入社情報登録
		retirementRegist.regist(retirement);
	}
	
}
