package project.web.job;

import java.sql.Timestamp;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import batch.controller.JobRequestor;
import batch.status.Job;
import batch.status.JobMasterInfo;
import batch.status.JobState;
import batch.status.JobStatus;
import common.db.JdbcSource;
import core.config.Env;
import core.config.Factory;
import online.context.check.InputCheck;
import online.struts.action.BrowseAction;
import online.struts.action.UniForm;
import project.check.attribute.LongNumeralCheck;
import project.check.existence.MustCheck;
import project.web.InstanceFactory;

/**
 * 印刷確認アクション
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class PollingAction implements BrowseAction {

	/** バッチエラー */
	private static final String ID_BATCH_ERROR = "BATCH_ERROR";
	/** バッチタイムアウト */
	private static final String ID_BATCH_TIMEOUT = "BATCH_TIMEOUT";
	/** キャンセル画面 */
	private static final String ID_CANCEL = "CANCEL";
	/** クライアントポーリング時間（60秒） */
	private static final int WAIT_MAX = 60;

	/** 待ち時間 */
	private static final String ENV_POLLING_WAIT_MAX = "Polling.WaitMax";

	/** キャンセルタイプ */
	private static final String TAG_CANCEL_TYPE = "CancelType";

	/** ジョブ連番 */
	private static final String TAG_JOB_SEQ = "JobSeq";
	/** ジョブID */
	private static final String TAG_JOB_ID = "JobId";
	/** ジョブ名 */
	private static final String TAG_JOB_NAME = "JobMei";
	/** ジョブステータス */
	private static final String TAG_JOB_STS = "JobSts";

	/**
	 * ステータス確認
	 *
	 * @param uf 汎用モデル
	 * @return 処理結果
	 */
	public String get(final UniForm uf) {

		final var ic = InstanceFactory.create(InputCheck.class, uf);
		ic.add(TAG_JOB_SEQ, new MustCheck());
		ic.add(TAG_JOB_SEQ, new LongNumeralCheck());
		ic.populate();

		try (var conn = JdbcSource.getConnection()) {
			// ステータス取得
			final var js = Factory.create(JobStatus.class);
			final var job = js.getJob(conn, uf.getNumber(TAG_JOB_SEQ).longValue());
			if (job != null) {
				// ユーザIDチェック
				final var su = uf.getSessionUser();
				if (Objects.equals(job.getUid(), su.getUid())) {
					// ジョブ情報設定
					uf.setValue(TAG_JOB_ID, job.getJobId());
					uf.setValue(TAG_JOB_NAME, job.getJobName());
					uf.setValue(TAG_JOB_STS, job.getJobSts());

					// 中止タイプ設定
					final var ji = Factory.create(JobMasterInfo.class);
					final var info = ji.getJobMasterInfo(conn, job.getJobId());
					if (info != null) {
						uf.setValue(TAG_CANCEL_TYPE, info.getCancelType());
					}

					return toResultValue(job, uf.getPresent());
				}
			}
		}

		return ID_SYS_ERROR;
	}

	/**
	 * ステータス変換
	 * @param job Job
	 * @param dt 日時
	 * @return 処理結果
	 */
	private String toResultValue(final Job job, final Timestamp dt) {
		// 正常終了
		var ret = ID_VIEW;
		final var sts = job.getJobSts();
		if (JobState.isEnd(sts)) {
			// 対象データ無し
			ret = ID_OK;
		} else if (JobState.isCancel(sts)) {
			// キャンセル
			ret = ID_CANCEL;
		} else if (JobState.isError(sts)) {
			// 異常終了
			ret = ID_BATCH_ERROR;
		} else {
			// ポーリング時間チェック
			final int max = Env.getEnv(ENV_POLLING_WAIT_MAX, WAIT_MAX);
			if (job.getDateTime().getTime() + TimeUnit.SECONDS.toMillis(max) < dt.getTime()) {
				ret = ID_BATCH_TIMEOUT;
			}
		}
		return ret;
	}

	/**
	 * キャンセル処理
	 *
	 * @param model 汎用モデル
	 * @return 処理結果
	 */
	public String cancel(final UniForm model) {
		final var ic = InstanceFactory.create(InputCheck.class, model);
		ic.add(TAG_JOB_SEQ, new MustCheck());
		ic.add(TAG_JOB_SEQ, new LongNumeralCheck());
		ic.populate();

		// キャンセル処理
		JobRequestor.cancelJob(model.getNumber(TAG_JOB_SEQ).longValue());
		return ID_CANCEL;
	}
}
