/**
 *
 */
package jp.agentec.sinaburocast.action.admin.setting;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Field;
import java.net.URLEncoder;

import javax.annotation.Resource;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.transaction.UserTransaction;

import jp.agentec.sinaburocast.action.AbstractAction;
import jp.agentec.sinaburocast.common.SinaburoConstant;
import jp.agentec.sinaburocast.common.annotation.OperationHistoryAno;
import jp.agentec.sinaburocast.common.util.PropertyUtil;
import jp.agentec.sinaburocast.common.util.SinaburoViewUtil;
import jp.agentec.sinaburocast.csv.PostalInfoCsv;
import jp.agentec.sinaburocast.entity.Postalcode;
import jp.agentec.sinaburocast.entity.UploadError;
import jp.agentec.sinaburocast.form.admin.setting.PostCodeFileRegistForm;
import jp.agentec.sinaburocast.service.PostalcodeService;
import jp.agentec.sinaburocast.service.UploadErrorService;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.impl.BeanDescImpl;
import org.seasar.framework.beans.util.Beans;
import org.seasar.framework.util.FieldUtil;
import org.seasar.framework.util.StringUtil;
import org.seasar.s2csv.csv.S2CSVParseCtrl;
import org.seasar.s2csv.csv.S2CSVWriteCtrl;
import org.seasar.s2csv.csv.exception.runtime.CSVValidationResultRuntimeException;
import org.seasar.s2csv.csv.factory.S2CSVCtrlFactory;
import org.seasar.s2csv.csv.message.CSVMsg;
import org.seasar.s2csv.csv.validator.CSVValidateResult;
import org.seasar.struts.annotation.ActionForm;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.util.ResponseUtil;

/**
 * 郵便番号CSVデータアップロード
 * @author arakawa
 *
 */
public class PostCodeFileRegistAction extends AbstractAction {
	private final Logger logger = Logger.getLogger(getClass());

	@ActionForm
	@Resource
	public PostCodeFileRegistForm postCodeFileRegistForm;

	public PostalcodeService postalcodeService;

	public UploadErrorService uploadErrorService;

	public S2CSVCtrlFactory csvCtrlFactory;

	public UserTransaction userTransaction;

	//アップロードエラーファイル名
	private final String uploadErrFileName="postcode_upload_error.tsv";

	//ファイルタイプID
	private final String type="4";

	/**
	 * 初期表示
	 */
	@Execute(validator = false)
	public String index() {
		//エラーファイルダウンロード
		postCodeFileRegistForm.uploadError = uploadErrorService.findByType(type);
		//郵便番号一括
		return "/admin/setting/postCodeFileRegist.html";
	}


	/**
	 * 郵便番号CSVデータアップロード
	 * @throws Exception
	 */
	@Execute(validator = false)
	@OperationHistoryAno(operationTypeId=SinaburoConstant.OperationType.UPDATE,target="郵便番号マスタ",detail="登録",screenId=SinaburoConstant.screenId.COS0001)
	@TransactionAttribute(TransactionAttributeType.NEVER)
	public String PostalcodeUpload()throws Exception {

		if (postCodeFileRegistForm.file.getFileSize() == 0 ||
				StringUtil.isBlank(postCodeFileRegistForm.file.getFileName())) {
			//ファイル指定なしの場合

			ActionMessages messages =
					(ActionMessages)request.getAttribute(Globals.ERROR_KEY);
			if (messages == null) {
				messages = new ActionMessages();
			}
			messages.add("file", new
					ActionMessage(SinaburoViewUtil.getMessage("errors.E027")));
			request.setAttribute(Globals.ERROR_KEY, messages);

			return "/admin/setting/postCodeFileRegist/";
		}

		String fileTmpPath = saveTmpFile();

		if(!postCodeFileRegistForm.file.getFileName().toUpperCase().endsWith(".CSV")){
			addError("errors.E046");
			return "/admin/setting/postCodeFileRegist/";
		}

		InputStream in = null;
		try {
			in = postCodeFileRegistForm.file.getInputStream();
			//csvData = IOUtils.toString(in, "UTF-8");
			//バイナリ形式チェック
            byte[] b = new byte[1];
            while (in.read(b, 0, 1) > 0) {
                if (b[0] == 0) {
        			addError("errors.E042");
        			return "/admin/setting/postCodeFileRegist/";
                }
            }
		}catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			IOUtils.closeQuietly(in);

		}

		userTransaction.begin();

		boolean ret=false;
		try {
			ret = csvUpload(fileTmpPath);
		} catch (org.seasar.s2csv.csv.exception.CSVFormatException e) {
			addError("errors.E039");
			userTransaction.rollback();
			return "/admin/setting/postCodeFileRegist.html";
		} catch (NumberFormatException e) {
			addError("errors.E039");
			userTransaction.rollback();
			return "/admin/setting/postCodeFileRegist.html";
		} catch (Exception e) {
			addError("errors.E039");
			userTransaction.rollback();
			return "/admin/setting/postCodeFileRegist.html";
		}

		String retUrl = null;
		if (ret){
			userTransaction.commit();
			retUrl = "/admin/setting/postCodeFileRegistEnd.html";
		}else{
			userTransaction.rollback();
			retUrl = "/admin/setting/postCodeFileRegist.html";
		}

		UploadError uploadError = new UploadError();
		uploadError.filePath =
				PropertyUtil.getProperty(SinaburoConstant.filePath.UPLOAD_ERROR_FILE_PATH);
		uploadError.filePath+=uploadErrFileName;
		uploadError.type=type;//市民団体一括アップロード
		uploadError.status =  (ret) ? "OK" : "NG";

		uploadErrorService.deleteInsertByType(uploadError, getAdmin());
		postCodeFileRegistForm.uploadError = uploadErrorService.findByType(type);

		//郵便番号CSVデータアップロード
		return retUrl;

	}

	private String saveTmpFile() throws Exception{

		//一時保存
		String path =
				PropertyUtil.getProperty(SinaburoConstant.filePath.UPLOAD_TMP_FILE_PATH);

		String fileTmpPath = path + postCodeFileRegistForm.file.getFileName();
		OutputStream out = new BufferedOutputStream(new FileOutputStream(
				fileTmpPath));

		out.write(postCodeFileRegistForm.file.getFileData(), 0,
				postCodeFileRegistForm.file.getFileSize());
		out.close();

		return fileTmpPath;
	}

	private boolean csvUpload(String fileTmpPath) throws Exception{

		boolean ret = true;
		FileInputStream is = new FileInputStream(fileTmpPath);
		Reader reader = new InputStreamReader(is, "SJIS");

		S2CSVParseCtrl<PostalInfoCsv> csv_parser =
				csvCtrlFactory.getParseController(PostalInfoCsv.class, reader);

//		csv_parser.setValidateFlag(false);

		//郵便番号データ全件削除
		postalcodeService.postalInfoDelAll();

		S2CSVWriteCtrl<PostalInfoCsv> csv_writer = null;
		try{

			String uploadErrorFilePath =
					PropertyUtil.getProperty(SinaburoConstant.filePath.UPLOAD_ERROR_FILE_PATH);
			uploadErrorFilePath+=uploadErrFileName;

			//20170508 SJIS文字化け対応
			Writer writer = new OutputStreamWriter(new FileOutputStream(uploadErrorFilePath),"Windows-31J");
			//Writer writer = new OutputStreamWriter(new FileOutputStream(uploadErrorFilePath),"Shift_JIS");

			csv_writer = csvCtrlFactory.getWriteController(PostalInfoCsv.class,writer);

			//次の行の読み込み
			while(csv_parser.readNext()){

//				CSVValidateResult validateResult = csv_parser.validate();

				 try{

					PostalInfoCsv postalInfoCsv = csv_parser.parse();

					postalInfoCsv.okNg = "OK";
					//CSVデータからオブジェクトに変換して取得
					Postalcode postalcode = Beans.createAndCopy(Postalcode.class,postalInfoCsv).execute();
					postalcodeService.insertPostalcode(postalcode, getAdmin().loginId);

					csv_writer.write(postalInfoCsv);

				 }catch(CSVValidationResultRuntimeException e){

					 CSVValidateResult validateResult = e.getValidateResult();

					//バリデーションエラー行
					//NGになったCSVデータを復元する。
					 PostalInfoCsv postalInfoCsv = new PostalInfoCsv();

					String[] data = validateResult.getData();
					BeanDesc beanDesc = new BeanDescImpl(PostalInfoCsv.class);
					int fieldSize = beanDesc.getFieldSize();
					for (int i= 0 ; i < fieldSize; i++){
						Field field = beanDesc.getField(i);

						if(field.getGenericType() == Integer.class){
							FieldUtil.set(field,postalInfoCsv,Integer.parseInt(data[i]));
						}else{
							FieldUtil.set(field,postalInfoCsv,data[i]);
						}
					}

					//バリデーションエラーメッセージ
					for(CSVMsg msg: validateResult.getMsgs()){

						if(postalInfoCsv.reason == null){
							postalInfoCsv.reason = msg.toString();
						}else{
							postalInfoCsv.reason += msg.toString();
						}
					}
					postalInfoCsv.okNg = "NG";
					ret = false;

					csv_writer.write(postalInfoCsv);
				 }
			}
		}catch (Exception e) {

			ret = false;
			csv_writer.close();
			is.close();

		} finally {
			csv_writer.close();
			is.close();
		}

		return ret;
	}

	/**
	 * 最後に登録したファイルの結果ファイルをダウンロード
	 * @throws Exception
	 */
	@Execute(validator = false)
	public String resultFileDownLoad()throws Exception {

		UploadError uploadError = uploadErrorService.findByType(type);
		File file = new File(uploadError.filePath);
		ResponseUtil.download(URLEncoder.encode(file.getName(), "UTF-8"),
				new BufferedInputStream(
						new FileInputStream(file)), (int)file.length());
		return null;

	}

}