/*

Copyright (C) 2009 NTT DATA INTELLILINK CORPORATION

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, version 2.

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.

 */

package jp.co.intellilink.hinemos.export.history;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;

import jp.co.intellilink.hinemos.util.CheckString;
import jp.co.intellilink.hinemos.util.Config;
import jp.co.intellilink.hinemos.util.EjbConnectionManager;
import jp.co.intellilink.hinemos.util.Messages;
import jp.co.intellilink.hinemos.util.StringListComparator;
import jp.co.intellilink.hinemos.util.WriteCsvFile;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.clustercontrol.bean.CommonTableTreeItem;
import com.clustercontrol.bean.EndStatusConstant;
import com.clustercontrol.bean.JobConstant;
import com.clustercontrol.bean.StatusConstant;
import com.clustercontrol.jobmanagement.bean.HistoryTableDefine;
import com.clustercontrol.jobmanagement.bean.JobDetailTableDefine;
import com.clustercontrol.jobmanagement.bean.JobHistory;
import com.clustercontrol.jobmanagement.bean.JobHistoryFilter;
import com.clustercontrol.jobmanagement.bean.JobHistoryList;
import com.clustercontrol.jobmanagement.bean.JobNodeDetail;
import com.clustercontrol.jobmanagement.ejb.session.JobController;

/**
 * ジョブ実行履歴を取得するクラス<br>
 * 
 * @version 1.0.0
 * @since 1.0.0
 */
public class ExportJob {

	// ログ出力
	private static Log log = LogFactory.getLog(ExportJob.class);

	/**
	 * ジョブ実行履歴をExportする。<br>
	 */
	public void export(Date startDate) {
		log.info(Messages.getMsg("ExportTool.Job.Start"));

		//CSV出力配列を用意
		ArrayList<ArrayList<String>> treeCsvOutput = new ArrayList<ArrayList<String>>();
		//CSV出力配列を用意
		ArrayList<ArrayList<String>> nodeCsvOutput = new ArrayList<ArrayList<String>>();

		Calendar cal = Calendar.getInstance();
		cal.setTime(startDate);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		Date startTime = cal.getTime();

		cal.add(Calendar.DATE, 1);
		cal.add(Calendar.MILLISECOND, -1);
		Date endTime = cal.getTime();

		//ジョブセッション一覧
		JobHistoryList info = getSessionList(startTime, endTime);

		if(info.getList() instanceof ArrayList){
			Iterator itr = info.getList().iterator();
			while(itr.hasNext()){
				JobHistory line = (JobHistory)itr.next();
				
				Object[] args = {line.getSessionId()};
				log.info(Messages.getMsg("SessionID", args));

				CommonTableTreeItem item = getJobDetail(line.getSessionId());
				getJobDetailData(line, item, treeCsvOutput);

				getJobNodeData(line, item, nodeCsvOutput);
			}
		}

		//ジョブIDでソート
		Collections.sort(treeCsvOutput, new StringListComparator(4));
		//セッションIDでソート
		Collections.sort(treeCsvOutput, new StringListComparator(3));

		treeCsvOutput.add(0, createDetailCsvHeader());

		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
		WriteCsvFile.writeCsvFile(
				Config.getConfig("History.Dir") + "/JOB_" + format.format(startTime) + ".csv", 
				treeCsvOutput);

		//ジョブIDでソート
		Collections.sort(nodeCsvOutput, new StringListComparator(3));
		//セッションIDでソート
		Collections.sort(nodeCsvOutput, new StringListComparator(2));

		nodeCsvOutput.add(0, createNodeCsvHeader());

		WriteCsvFile.writeCsvFile(
				Config.getConfig("History.Dir") + "/JOB_NODE_" + format.format(startTime) + ".csv", 
				nodeCsvOutput);

		log.info(Messages.getMsg("ExportTool.Job.End"));
	}

	/**
	 * ジョブ詳細一覧用のCSVフォーマットのヘッダ文字列を作成する。<br>
	 * 
	 * @return CSVフォーマット文字列
	 */
	public ArrayList<String> createDetailCsvHeader() {
		ArrayList<String> csvLine = new ArrayList<String>();

		csvLine.add(com.clustercontrol.util.Messages.getString("run.status"));
		csvLine.add(com.clustercontrol.util.Messages.getString("end.status"));
		csvLine.add(com.clustercontrol.util.Messages.getString("end.value"));
		csvLine.add(com.clustercontrol.util.Messages.getString("session.id"));
		csvLine.add(com.clustercontrol.util.Messages.getString("job.id"));
		csvLine.add(com.clustercontrol.util.Messages.getString("job.name"));
		csvLine.add(com.clustercontrol.util.Messages.getString("type"));
		csvLine.add(com.clustercontrol.util.Messages.getString("facility.id"));
		csvLine.add(com.clustercontrol.util.Messages.getString("scope"));
		csvLine.add(com.clustercontrol.util.Messages.getString("scheduled.start.time"));
		csvLine.add(com.clustercontrol.util.Messages.getString("time"));
		csvLine.add(com.clustercontrol.util.Messages.getString("start.rerun.time"));
		csvLine.add(com.clustercontrol.util.Messages.getString("end.suspend.time"));
		csvLine.add(com.clustercontrol.util.Messages.getString("trigger.type"));
		csvLine.add(com.clustercontrol.util.Messages.getString("trigger.info"));

		return csvLine;
	}

	/**
	 * ジョブ詳細情報取得（再帰呼び出し）
	 * 
	 * @param sessionInfo セッション情報
	 * @param treeItem ジョブツリー
	 * @param csvOutput CSV出力文字列配列
	 */
	public void getJobDetailData(JobHistory sessionInfo, CommonTableTreeItem treeItem, ArrayList<ArrayList<String>> csvOutput) {

		//子ツリーを取得する
		if (treeItem.getData() instanceof ArrayList){
			ArrayList info = treeItem.getData();
			String jobId = (String)info.get(JobDetailTableDefine.JOB_ID);

			Object[] args = {jobId};
			log.info(Messages.getMsg("JobID", args));

			ArrayList<String> csvFormat = new ArrayList<String>();

			//実行状態
			csvFormat.add(StatusConstant.typeToString(((Number) info.get(JobDetailTableDefine.STATUS)).intValue()));
			//終了状態
			if(info.get(JobDetailTableDefine.END_STATUS) instanceof Number)
				csvFormat.add(EndStatusConstant.typeToString(((Number) info.get(JobDetailTableDefine.END_STATUS)).intValue()));
			else
				csvFormat.add("");
			//終了値
			if(info.get(JobDetailTableDefine.END_VALUE) instanceof Number)
				csvFormat.add(((Number) info.get(JobDetailTableDefine.END_VALUE)).toString());
			else
				csvFormat.add("");
			//セッションID
			csvFormat.add(sessionInfo.getSessionId());
			//ジョブID
			csvFormat.add((String) info.get(JobDetailTableDefine.JOB_ID));
			//ジョブ名
			csvFormat.add((String) info.get(JobDetailTableDefine.JOB_NAME));
			//ジョブ種別
			csvFormat.add(JobConstant.typeToString(((Number) info.get(JobDetailTableDefine.JOB_TYPE)).intValue()));
			//ファシリティID
			if(info.get(JobDetailTableDefine.FACILITY_ID) instanceof String)
				csvFormat.add((String) info.get(JobDetailTableDefine.FACILITY_ID));
			else
				csvFormat.add("");
			//スコープ
			if(info.get(JobDetailTableDefine.SCOPE) instanceof String)
				csvFormat.add((String) info.get(JobDetailTableDefine.SCOPE));
			else
				csvFormat.add("");
			//開始予定日時
			if(treeItem.getParent().getData() == null)
				csvFormat.add(DateFormat.getDateTimeInstance().format(sessionInfo.getScheduleDate()));
			else
				csvFormat.add("");
			//時刻
			if(info.get(JobDetailTableDefine.WAIT_RULE_TIME) != null){
				Class itemClass = info.get(JobDetailTableDefine.WAIT_RULE_TIME).getClass();
				if (itemClass == Date.class)
					csvFormat.add(new SimpleDateFormat("HH:mm").format((Date) info.get(JobDetailTableDefine.WAIT_RULE_TIME)));
				else if (itemClass == String.class)
					csvFormat.add((String) info.get(JobDetailTableDefine.WAIT_RULE_TIME));
				else if (itemClass.getSuperclass() == Number.class)
					csvFormat.add(((Number) info.get(JobDetailTableDefine.WAIT_RULE_TIME)).toString());
				else
					csvFormat.add("");
			}
			else
				csvFormat.add("");
			//開始・再実行日時
			if(info.get(JobDetailTableDefine.START_RERUN_TIME) instanceof Date)
				csvFormat.add(DateFormat.getDateTimeInstance().format((Date)info.get(HistoryTableDefine.START_RERUN_TIME)));
			else
				csvFormat.add("");
			//終了・中断日時
			if(info.get(JobDetailTableDefine.END_SUSPEND_TIME) instanceof Date)
				csvFormat.add(DateFormat.getDateTimeInstance().format((Date)info.get(HistoryTableDefine.END_SUSPEND_TIME)));
			else
				csvFormat.add("");
			//実行契機
			if(treeItem.getParent().getData() == null){
				csvFormat.add(sessionInfo.getJobTriggerType());
				csvFormat.add(sessionInfo.getTriggerInfo());
			}
			else{
				csvFormat.add("");
				csvFormat.add("");
			}

			csvOutput.add(csvFormat);
		}

		CommonTableTreeItem[] childrenTreeItem = treeItem.getChildren();
		for (CommonTableTreeItem childTreeItem : childrenTreeItem) {
			getJobDetailData(sessionInfo, childTreeItem, csvOutput);
		}
	}

	/**
	 * ジョブセッション一覧を取得する。<br>
	 * 
	 * @param fromDate 開始・再実行日時（開始）
	 * @param toDate 開始・再実行日時（終了）
	 * @return ジョブセッション一覧
	 */
	protected JobHistoryList getSessionList(Date fromDate, Date toDate) {

		JobController job = EjbConnectionManager.getConnectionManager().getJobController();

		JobHistoryList info = null;
		try {
			JobHistoryFilter filter = new JobHistoryFilter();
			
			//開始・再実行日時（開始）を設定
			if(fromDate instanceof Date){
				filter.setStartFromDate(fromDate);
			}

			//開始・再実行日時（終了）を設定
			if(toDate instanceof Date){
				filter.setStartToDate(toDate);
			}

			int maxlist = Integer.parseInt(Config.getConfig("history.job.max.list"));

			info = job.getHistoryList(filter, maxlist);
		} catch (Exception e) {
			log.error(Messages.getMsg("ConnectManagerFailed"), e);
			System.exit(14);
		}
		return info;
	}

	/**
	 * ジョブ詳細情報を取得する。<br>
	 * 
	 * @return ジョブ詳細情報
	 */
	protected CommonTableTreeItem getJobDetail(String sessionId) {

		JobController job = EjbConnectionManager.getConnectionManager().getJobController();

		CommonTableTreeItem item = null;
		try {
			item = job.getDetailList(sessionId);
		} catch (Exception e) {
			log.error(Messages.getMsg("ConnectManagerFailed"), e);
			System.exit(14);
		}
		return item;
	}

	/**
	 * ジョブノード詳細一覧を取得する。<br>
	 * 
	 * @return ジョブノード詳細一覧
	 */
	protected ArrayList getNodeList(String sessionId, String jobUnitId, String jobId) {

		JobController job = EjbConnectionManager.getConnectionManager().getJobController();

		ArrayList list = null;
		try {
			list = job.getNodeDetailList(sessionId, jobUnitId, jobId, Locale.getDefault());
		} catch (Exception e) {
			log.error(Messages.getMsg("ConnectManagerFailed"), e);
			System.exit(14);
		}
		return list;
	}

	/**
	 * ジョブノード詳細情報取得（再帰呼び出し）
	 * 
	 * @param sessionInfo セッション情報
	 * @param treeItem ジョブツリー
	 * @param csvOutput CSV出力文字列配列
	 */
	public void getJobNodeData(JobHistory sessionInfo, CommonTableTreeItem treeItem, ArrayList<ArrayList<String>> csvOutput) {

		//子ツリーを取得する
		if (treeItem.getData() instanceof ArrayList){
			ArrayList info = treeItem.getData();

			if(((Number) info.get(JobDetailTableDefine.JOB_TYPE)).intValue() == JobConstant.TYPE_JOB){
				String sessionId = sessionInfo.getSessionId();
				String jobUnitId = sessionInfo.getJobunitId();
				String jobId = (String)info.get(JobDetailTableDefine.JOB_ID);
				String jobName = (String)info.get(JobDetailTableDefine.JOB_NAME);

				ArrayList list = getNodeList(sessionId, jobUnitId, jobId);
				if(list instanceof ArrayList){
					Iterator itr = list.iterator();
					while(itr.hasNext()){
						JobNodeDetail line = (JobNodeDetail)itr.next();

						ArrayList<String> csvFormat = new ArrayList<String>();

						csvFormat.add(StatusConstant.typeToString((line.getStatus())));
						//戻り値
						if(line.getEndValue() instanceof Integer)
							csvFormat.add((line.getEndValue().toString()));
						else
							csvFormat.add("");
						//セッションID
						csvFormat.add(sessionId);
						csvFormat.add(jobId);
						csvFormat.add(jobName);
						//ファシリティID
						if(line.getFacilityId() instanceof String)
							csvFormat.add(line.getFacilityId());
						else
							csvFormat.add("");
						//ファシリティ名
						if(line.getNodeName() instanceof String)
							csvFormat.add(line.getNodeName());
						else
							csvFormat.add("");
						//開始・再実行日時
						if(line.getStartDate() instanceof Date)
							csvFormat.add(DateFormat.getDateTimeInstance().format(line.getStartDate()));
						else
							csvFormat.add("");
						//終了・中断日時
						if(line.getEndDate() instanceof Date)
							csvFormat.add(DateFormat.getDateTimeInstance().format(line.getEndDate()));
						else
							csvFormat.add("");
						//メッセージ
						if(line.getMessage() instanceof String)
							csvFormat.add(CheckString.checkReturn(line.getMessage()));
						else
							csvFormat.add("");

						csvOutput.add(csvFormat);
					}
				}
			}
		}

		CommonTableTreeItem[] childrenTreeItem = treeItem.getChildren();
		for (CommonTableTreeItem childTreeItem : childrenTreeItem) {
			getJobNodeData(sessionInfo, childTreeItem, csvOutput);
		}
	}

	/**
	 * ジョブノード詳細一覧用のCSVフォーマットのヘッダ文字列を作成する。<br>
	 * 
	 * @return CSVフォーマット文字列
	 */
	public ArrayList<String> createNodeCsvHeader() {
		ArrayList<String> csvLine = new ArrayList<String>();

		csvLine.add(com.clustercontrol.util.Messages.getString("run.status"));
		csvLine.add(com.clustercontrol.util.Messages.getString("return.value"));
		csvLine.add(com.clustercontrol.util.Messages.getString("session.id"));
		csvLine.add(com.clustercontrol.util.Messages.getString("job.id"));
		csvLine.add(com.clustercontrol.util.Messages.getString("job.name"));
		csvLine.add(com.clustercontrol.util.Messages.getString("facility.id"));
		csvLine.add(com.clustercontrol.util.Messages.getString("facility.name"));
		csvLine.add(com.clustercontrol.util.Messages.getString("start.rerun.time"));
		csvLine.add(com.clustercontrol.util.Messages.getString("end.suspend.time"));
		csvLine.add(com.clustercontrol.util.Messages.getString("message"));

		return csvLine;
	}
}