package project.web.job;

import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.io.CopyStreamException;
import org.apache.logging.log4j.LogManager;

import batch.status.Job;
import batch.status.JobFile;
import core.config.Env;
import online.annotation.NoTransaction;
import online.struts.action.UniForm;

/**
 * FTPファイル取得ダウンロードアクション
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
@NoTransaction
public final class FtpJobFileAction implements DownloadJobFile {

	/**
	 * @see project.web.job.DownloadJobFile
	 * #canDownload(online.struts.action.UniForm, batch.status.Job)
	 */
	@Override
	public boolean canDownload(final UniForm model, final Job js) {
		return model.getSessionUser().getUid().equals(js.getUid());
	}

	/**
	 * ファイルダウンロード処理
	 *
	 * @param job ジョブ情報
	 * @param finfo ダウンロードファイル情報
	 * @param request HttpServletRequestオブジェクト
	 * @param response HttpServletResponseオブジェクト
	 */
	@Override
	public void fileDownload(final Job job, final JobFile finfo,
			final HttpServletRequest request, final HttpServletResponse response) {

		try {
			try (var os = response.getOutputStream()) {
				if (ftp(os, job, finfo)) {
					os.flush();
					return;
				}

				if (!response.isCommitted()) {
					response.reset();
					response.resetBuffer();
					response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
					response.flushBuffer();
				}
			}
		} catch (final IOException e) {
			LogManager.getLogger().info(e.getMessage());
		}
	}

	/**
	 * ファイル転送処理
	 *
	 * @param os 出力ストリーム
	 * @param job ジョブ情報
	 * @param finfo ダウンロードファイル情報
	 * @return 正常終了した場合 true を返す。
	 */
	private boolean ftp(final OutputStream os, final Job job, final JobFile finfo) {
		final var ftp = new FTPClient();
		ftp.enterLocalPassiveMode();
		ftp.setDefaultTimeout(300000);
		ftp.setDataTimeout(300000);
		try {
			ftp.connect(job.getHostId());
			if (!ftp.login(Env.getEnv("Batch.FtpUserId"), Env.getEnv("Batch.FtpPassword"))) {
				return false;
			}

			if (!ftp.setFileType(FTP.BINARY_FILE_TYPE)) {
				return false;
			}

			return ftp.retrieveFile(finfo.getPathName() + "/" + finfo.getFileName(), os);

		} catch (final CopyStreamException ex) {
			if (SocketException.class.isInstance(ex.getIOException().getCause())) {
				LogManager.getLogger().info(ex.getMessage());
			} else {
				LogManager.getLogger().error(ex.getMessage(), ex);
			}
		} catch (final IOException ex) {
			LogManager.getLogger().error(ex.getMessage(), ex);
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.logout();
				} catch (final IOException ex) {
					LogManager.getLogger().info(ex.getMessage());
				}
				try {
					ftp.disconnect();
				} catch (final IOException ex) {
					LogManager.getLogger().info(ex.getMessage());
				}
			}
		}

		return false;
	}
}
