/*
 * MosP - Mind Open Source Project         http://www.mosp.jp/
 * Copyright (C) 1987-2009 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 General Public License
 * as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package jp.mosp.payroll.common;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

//import jp.mosp.base.AttendanceTotalAction;
import jp.mosp.payroll.common.vo.FirmBankingOutputVo;
import jp.mosp.payroll.dao.CmBranchDao;
import jp.mosp.payroll.dto.CmBranchDto;
import jp.mosp.payroll.dao.CmBankDao;
import jp.mosp.payroll.dto.CmBankDto;
import jp.mosp.payroll.dao.BankTransferDao;
import jp.mosp.payroll.dao.CmCoBankDao;
import jp.mosp.payroll.dao.CmCompanyDao;
import jp.mosp.payroll.dao.PdPayAllowanceDao;
import jp.mosp.payroll.dao.PdPayBreakdownDao;
import jp.mosp.payroll.dao.PdPayDeductionDao;
import jp.mosp.payroll.dao.PdPaySumDao;
import jp.mosp.payroll.dao.PdPayTimeDao;
import jp.mosp.payroll.dao.PhPaymentDao;
import jp.mosp.payroll.dao.PmDetailPaDao;
import jp.mosp.payroll.dao.PmDetailPbDao;
import jp.mosp.payroll.dao.PmDetailPdDao;
import jp.mosp.payroll.dao.PmDetailPsDao;
import jp.mosp.payroll.dao.PmDetailPtDao;
import jp.mosp.payroll.dto.BankTransferFBDataDto;
import jp.mosp.payroll.dto.CmCoBankDto;
import jp.mosp.payroll.dto.CmCompanyDto;
import jp.mosp.payroll.dto.PhPaymentDto;
import jp.mosp.payroll.base.Payment;
import jp.mosp.payroll.base.PayrollConst;
import jp.mosp.common.MosPAction;
import jp.mosp.common.common.MospConst;
import jp.mosp.common.common.MospException;
import jp.mosp.common.common.MospUtility;
import jp.mosp.legal.LegalReportUtility;

public class PaymentFBDataOutputAction  extends MosPAction {
	// コマンド
	private static final String CMD_PAYMENT_FB_DATA_OUTPUT = "P9002";
	
	/**
	 * コンストラクタ
	 */
	public PaymentFBDataOutputAction() {
		super();
		setNeedProcSeq(false);
	}
	
	int total  = 0;
	int amount = 0; 
	// 追加レコード長
	int lenRecord = 0;
	/**
	 * アクション
	 */
	public void action() throws Exception {
		// DBコネクション取得
		getConnection();
		// PAYROLL権限確認
		confirmPayrollAuth();
		// VOの取得
		FirmBankingOutputVo vo = (FirmBankingOutputVo)session.getAttribute(MospConst.ATT_FORMER_VO);
		vo.clearMessage();
		vo.clearErrField();
		vo.initVo(cfg, msg, cmd, aspUser, user);
		if (cmd.equals(CMD_PAYMENT_FB_DATA_OUTPUT)) {
			// パラメータ取得
			vo.setParams(request);
			// 会社情報登録
			updateCompanyInfo(vo);
			// 追加レコード長取得
			getAddRecordLength(Integer.parseInt(vo.getTxtRecordLength()));
			
			// 対象年月取得
			Date date = vo.getDate(vo.getPltSpecifyYear(), vo.getPltSpecifyMonth(), String.valueOf(PayrollConst.TIME_DEFAULT_DAY));
			// FBデータ情報取得
			BankTransferDao bankTransferDao = new BankTransferDao();
			bankTransferDao.initDao(cfg, cmd, aspUser, user, conn);	
			List<BankTransferFBDataDto> list = bankTransferDao.findForCondition(vo.getPltCoBankCode(), date, null, true);
			// 帳票作成準備
			StringBuffer sb = new StringBuffer();
			String fileName = vo.getPltSpecifyYear () + PayrollConst.FILE_NAME_SEPARATOR
							+ vo.getPltSpecifyMonth() + PayrollConst.FILE_NAME_SEPARATOR
							+ PayrollConst.FILE_FB_PAYMENT_DATA;
			request.setAttribute(MospConst.ATT_FILE_NAME, fileName);
			request.setAttribute(MospConst.ATT_FILE_OBJECT, sb);
			// 給与データ確認
			if (list.size() == 0) {
				String errMessage = MospUtility.getMessage(msg, PayrollConst.MSG_NO_PAYMENT, "");
				sb.append(errMessage);
				return;
			}
			//振込金額の取得
			getFrimAmo(list);
			// FBデータ作成
			getFBDataRecord(sb, list, vo);
		}
	}
	
	/**
	 * FBデータ作成
	 * @param sb
	 * @param list
	 * @throws Exception
	 */
	protected void getFBDataRecord(StringBuffer sb, List<BankTransferFBDataDto> list, FirmBankingOutputVo vo)
		throws Exception
	{
		// 会社銀行情報取得準備
		CmCoBankDao cmCoBankDao = new CmCoBankDao();
		cmCoBankDao.initDao(cfg, cmd, aspUser, user, conn);
		// 会社銀行コードを持つ社員のリストを取得
		// 会社銀行情報取得
		CmCoBankDto	cmCoBankDto = cmCoBankDao.findForKey(vo.getPltCoBankCode());
		// 対象社員でまわす
		for (int j = 0; j < list.size(); j++) {
			BankTransferFBDataDto bankTransferFBDataDto = list.get(j);
			if (j == 0) {
				// ヘッダーレコード設定
				setHeaderRecordData(sb, bankTransferFBDataDto, cmCoBankDto, vo);
			}
			// データレコード設定
			setDataRecordData(sb, bankTransferFBDataDto, vo);
			// ステータス更新
			updatePaymentStatus(bankTransferFBDataDto);
		}
		// すべて確認し終わったらトレーラーレコード設定
		LegalReportUtility.getTrailerRecord(sb, String.valueOf(total), String.valueOf(amount)
					, checkLineFeed(vo.getPltRecordType()), lenRecord);
		// エンドレコード作成
		// エンドレコード出力確認
		if (checkLineFeed(vo.getPltEndRecord())) {
			LegalReportUtility.getEndRecord(sb, checkLineFeed(vo.getPltRecordType()), lenRecord);
		}
		// 初期化
		total = 0;
		amount = 0;
	}
	
	/**
	 * ヘッダーデータ設定
	 * @param sb
	 * @param aryBankCode
	 * @param aryBranchCode
	 * @param cmCompanyDto
	 * @param udPaymentDto
	 * @param cmCoBankDto
	 * @throws Exception 
	 */
	protected void setHeaderRecordData(
			StringBuffer sb, BankTransferFBDataDto bankTransferFBDataDto,CmCoBankDto cmCoBankDto,
			FirmBankingOutputVo vo
	) throws Exception {
		
		String[] aryBankName   = getBankName(cmCoBankDto.getBankCode());
		String[] aryBranchName = getBranchNameArray(cmCoBankDto.getBankCode(),cmCoBankDto.getBranchCode());
		
		// 銀行名設定
		String coBankName   = aryBankName  [2];
		String coBranchName = aryBranchName[3];
		LegalReportUtility.getHeaderRecode(sb, PayrollConst.FB_PAYMENT_TYPE_CODE, vo.getPltCodeType(),
					vo.getTxtCompanyCode(), getLowerUpKana(vo.getTxtCompanyName())
					, String.valueOf(MospUtility.getMonth(bankTransferFBDataDto.getPayday())), String.valueOf(MospUtility.getDay(bankTransferFBDataDto.getPayday()))
					, cmCoBankDto.getBankCode   (), getLowerUpKana(coBankName)
					, cmCoBankDto.getBranchCode (), getLowerUpKana(coBranchName)
					, cmCoBankDto.getAccountType(), cmCoBankDto.getAccountNo()
					, checkLineFeed(vo.getPltRecordType()), lenRecord
			);
	}
	
	/**
	 * データレコードデータ設定
	 * @param sb
	 * @param bankTransferFBDataDto
	 * @throws Exception
	 */
	private void setDataRecordData(
		StringBuffer sb, BankTransferFBDataDto bankTransferFBDataDto, FirmBankingOutputVo vo
	) throws Exception {
		if(0 !=  bankTransferFBDataDto.getBankPayAmount()){
			String[] aryBankName   = getBankName(bankTransferFBDataDto.getPaidBankCode());
			String[] aryBranchName = getBranchNameArray(bankTransferFBDataDto.getPaidBankCode(),bankTransferFBDataDto.getPaidBranchCode());
			// 銀行名設定
			String bankName   = aryBankName  [2];
			String branchName = aryBranchName[3];
			String bankPayAmount = String.valueOf(bankTransferFBDataDto.getBankPayAmount());
		
			LegalReportUtility.getFBDataRecord(
					sb, bankTransferFBDataDto.getPaidBankCode(), getLowerUpKana(bankName)
					, bankTransferFBDataDto.getPaidBranchCode(), getLowerUpKana(branchName)
					, bankTransferFBDataDto.getAccountType(), bankTransferFBDataDto.getAccountNo()
					, getLowerUpKana(bankTransferFBDataDto.getHolderKana()) , bankPayAmount
					, bankTransferFBDataDto.getKCode(), bankTransferFBDataDto.getStationCode()
					, checkLineFeed(vo.getPltRecordType()), lenRecord
			);
			// 件数設定
			total ++;
			// 合計金額設定
			amount +=  bankTransferFBDataDto.getBankPayAmount();
		}
	}
	
	/**
	 * 給与ステータス更新
	 * @param bankTransferFBDataDto
	 * @throws SQLException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws MospException
	 */
	private void updatePaymentStatus(BankTransferFBDataDto bankTransferFBDataDto)
		throws SQLException, IllegalAccessException, NoSuchFieldException, MospException
	{
		// 給与情報更新
		//UdPaymentDao udPaymentDao = new UdPaymentDao();
		//udPaymentDao.initDao(cfg, cmd, aspUser, user, conn);
		//UdPaymentDto udPaymentDto = udPaymentDao.findForKey(bankTransferFBDataDto.getKCode(), bankTransferFBDataDto.getCalcDate());
		//if (udPaymentDto != null) {
			// ステータスをFBデータ出力済みに設定
		//	udPaymentDto.setCalcStatus(PayrollConst.CALC_STATUS_FB);
			// UD_PAYMENT更新
		//	udPaymentDao.update(udPaymentDto, true);
			// コミット
		//	commit();
		//}
		
	}
	
	
	/**
	 * 会社情報更新
	 * @param vo
	 * @throws SQLException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws MospException
	 */
	private void updateCompanyInfo(FirmBankingOutputVo vo) throws SQLException, IllegalAccessException, NoSuchFieldException, MospException {
		// DAO準備
		CmCompanyDao cmCompanyDao = new CmCompanyDao();
		cmCompanyDao.initDao(cfg, cmd, aspUser, user, conn);
		// 存在確認
		CmCompanyDto cmCompanyDto = cmCompanyDao.findAll();
		
		if (cmCompanyDto != null) {
			cmCompanyDto.setCompanyFbAddress(vo.getTxtCoAddress());
			cmCompanyDto.setCompanyFbKana(vo.getTxtCompanyName ());
			// 更新
			cmCompanyDao.update(cmCompanyDto);
		} else {
			cmCompanyDto = new CmCompanyDto();
			cmCompanyDto.setCompanyFbAddress(vo.getTxtCoAddress());
			cmCompanyDto.setCompanyFbKana(vo.getTxtCompanyName ());
			// 登録
			cmCompanyDao.insert(cmCompanyDto);
			
		}
		// コミット
		commit();
	}
	
	
	/**
	 * 改行付与確認
	 * @param strLineFeed
	 * @return
	 */
	private boolean checkLineFeed(String strLineFeed) {
		// レコード区分に改行をつけない
		if (strLineFeed.equals(PayrollConst.FB_RECORD_TYPE_NONE)) {
			return false;
		}
		// レコード区分に改行をつける
		return true;
	}
	
	/**
	 * 追加レコード長取得
	 * @param addLenRecord
	 */
	private void getAddRecordLength(int addLenRecord) {
		// 追加レコード長-120(最小レコード長)
		 lenRecord = addLenRecord - PayrollConst.FB_LOWER_LEN_RECORD;
		 if (lenRecord < 0) {
			 lenRecord = 0;
		 }
	}
	
	/**
	 * 銀行名取得(利用可能所属のみ)(CM_BANK)
	 * @return 銀行名リスト
	 * @throws Exception
	 */
	protected String[] getBankName(String bankCode) throws Exception {
		// 準備
		String[] aryBankName = new String[3];
		// DAOの準備
		CmBankDao dao = new CmBankDao();
		dao.initDao(cfg, cmd, aspUser, user, conn);
		// 情報の取得
		CmBankDto  cmBankDto = dao.findForKey(bankCode);
		// 配列の作成
		if (cmBankDto != null) {
			aryBankName[0] = cmBankDto.getBankCode();
			aryBankName[1] = cmBankDto.getBankName();
			aryBankName[2] = cmBankDto.getBankKana();
		} else {
			aryBankName[0] = bankCode;
			aryBankName[1] = bankCode;
			aryBankName[2] = bankCode;
			
		}
		
		return aryBankName;
	}
	
	/**
	 * 支店コード取得(利用可能所属のみ)(CM_BANK)
	 * @return 銀行コードリスト
	 * @throws Exception
	 */
	protected String[] getBranchNameArray(String bankCode, String branchCode) throws Exception {
		// 準備
		String[] aryBranchName = new String[4];
		// DAOの準備
		CmBranchDao dao = new CmBranchDao();
		dao.initDao(cfg, cmd, aspUser, user, conn);
		// 情報の取得
		CmBranchDto cmBranchDto = dao.findForKey(bankCode, branchCode);
		// 配列の作成
		if (cmBranchDto != null) {
			aryBranchName[0] = cmBranchDto.getBankCode();
			aryBranchName[1] = cmBranchDto.getBranchCode();
			aryBranchName[2] = cmBranchDto.getBranchName();
			aryBranchName[3] = cmBranchDto.getBranchKana();
		} else {
			aryBranchName[0] = bankCode;
			aryBranchName[1] = branchCode;
			aryBranchName[2] = branchCode;
			aryBranchName[3] = branchCode;
			
		}
		return aryBranchName;
	}
	
	/**
	 * 半角カナ変換(小文字→大文字)
	 * @param strTarget
	 * @return　半角カナ文字列
	 */
	protected String getLowerUpKana(String strTarget) {
		// 半角カナ(小文字)
		String[] aryLowerKana = {
				"ｧ",  "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ"
		};
		// 半角カナ(大文字)
		String[] aryLowerUpKana = {
				"ｱ",  "ｲ", "ｳ", "ｴ", "ｵ", "ﾔ", "ﾕ", "ﾖ", "ﾂ"
		};
		// 準備
		String retString = "";
		String repString = "";
		// 文字列の桁数で回す
		for (int i = 0; i < strTarget.length(); i++) {
			// 順番に文字列を取得していく
			repString = strTarget.substring(i, i+1);
			// 文字列を順番に確認
			for (int j = 0; j < aryLowerKana.length; j++) {
				// 半角かな(小文字)が存在したら大文字へ変換
				if (aryLowerKana[j].equals(repString)) {
					repString = aryLowerUpKana[j];
					break;
				}
			}
			// 文字列を結合
			retString += repString;
		}
		return retString;
	}
	
	/**
	 * 振込み金額の取得
	 * @param list
	 */
	private void getFrimAmo(List<BankTransferFBDataDto> lineList) throws Exception {
		String oldkCode = "";
		String newkCode = "";
		
		for (int i = 0; i < lineList.size(); i++) {
			BankTransferFBDataDto list = lineList.get(i);
			
			newkCode = list.getKCode();
			if (!oldkCode.equals(newkCode)) {
				Payment sumAmo = getPayment(list.getKCode(), list.getCalcDate());
				int Amount = sumAmo.getSumAmount(PayrollConst.DTL_SUM_BANK1);
				list.setBankPayAmount(Amount);
			} else {
				Payment sumAmo = getPayment(list.getKCode(), list.getCalcDate());
				int Amount = sumAmo.getSumAmount(PayrollConst.DTL_SUM_BANK2);
				list.setBankPayAmount(Amount);
			}
			oldkCode = newkCode;
			
		}
		
	}
	
	/**
	 * 給与伝票インスタンスを取得、設定する。<br><br>
	 * kCode、calcDateをキーとして給与情報を取得し、{@link #payment}に格納する。
	 * @param kCode     社員コード
	 * @param calcMonth 計算年月
	 * @return 給与伝票
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws SQLException 
	 */
	protected Payment getPayment(
			String kCode, Date calcMonth
	) throws SQLException, IllegalAccessException, NoSuchFieldException {
		PhPaymentDto header = new PhPaymentDao(
				cfg, cmd, aspUser, user, conn).findForKey(kCode, calcMonth);
		if (header == null) {
			return null;
		}
		return new Payment(
				header,
				new PmDetailPtDao(cfg, cmd, aspUser, user, conn).findForSlip(header.getSlipCode()),
				new PmDetailPaDao(cfg, cmd, aspUser, user, conn).findForSlip(header.getSlipCode()),
				new PmDetailPdDao(cfg, cmd, aspUser, user, conn).findForSlip(header.getSlipCode()),
				new PmDetailPbDao(cfg, cmd, aspUser, user, conn).findForSlip(header.getSlipCode()),
				new PmDetailPsDao(cfg, cmd, aspUser, user, conn).findForSlip(header.getSlipCode()),
				new PdPayTimeDao     (cfg, cmd, aspUser, user, conn).find(kCode, calcMonth),
				new PdPayAllowanceDao(cfg, cmd, aspUser, user, conn).find(kCode, calcMonth),
				new PdPayDeductionDao(cfg, cmd, aspUser, user, conn).find(kCode, calcMonth),
				new PdPayBreakdownDao(cfg, cmd, aspUser, user, conn).find(kCode, calcMonth),
				new PdPaySumDao      (cfg, cmd, aspUser, user, conn).find(kCode, calcMonth)
		);
	}

}
