/**
 * @(#)RidualLog.java
 *
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 *
 * RID-3 : 実行ログ
  *
 * @author  Intelligent Technology Inc.
 * @version 1.01 2002/08/01
 */
package jp.co.nri;

import java.io.File;
import java.io.FileOutputStream;

import java.util.Enumeration;
import java.util.Vector;

import org.xml.sax.InputSource;

import org.apache.xerces.parsers.DOMParser;

import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.DOMSerializer;
import org.apache.xml.serialize.XMLSerializer;

import jp.co.iti.fagot.ZApp;

import jp.co.iti.fagot.doc.DocDocument;
import jp.co.iti.fagot.doc.DocElement;
import jp.co.iti.fagot.doc.DocManager;

import jp.co.iti.fagot.util.ZResource;
import jp.co.iti.fagot.util.ZString;
import jp.co.iti.fagot.util.ZDebug;

/**
 * Ridual 実行ログ
 * サーバ側でバッチ起動時に｛起動状態｜終了ステータス｝などを保存し、
 * バッチ起動の実行記録を残すとともに、バッチ起動の排他制御を行うためのクラス
 * このクラスは、RidualScriptからのみ呼ばれる
 */
public class RidualLog {

	/**
	 * コンストラクタ
	 * @param szLog ログファイル名
	 * @param szTrc トレースファイル名
	 * @param szTim 開始時刻
	 */
	public RidualLog(String szLog, String szTrc, String szTim) {
	mLog = szLog;
	mTrc = szTrc;
	mTim = szTim;
	}

	//## 開始・終了 ###################################################
	/**
	 * 開始
	 * @param szPrj プロジェクト名
	 * @return {正常|異常}
	 */
	public boolean start( String szPrj ) {
	mPrj = szPrj;
	boolean bRet = false;
	DocDocument doc = loadDocument();
	ZResource res = ZApp.getTheApp().getResource();
	boolean bForce = res.getBoolean("rid.start.force",false);
	if ( doc != null ) {
		bRet = true;
		DocElement root = (DocElement)doc.getDocumentElement();
		Vector vec = root.findChildElements(".Log");
		Enumeration elm = vec.elements();
		while ( elm.hasMoreElements() ) {
			DocElement log = (DocElement)elm.nextElement();
			if ( log.getAttribute("Project").equals( mPrj ) &&
				 log.getAttribute("Status").equals("running") ) {
				if ( bForce ) {
					log.setAttribute("Status","stopped");
				} else {
					// 2重起動エラー
					ZDebug.trace("duplicate start");
					bRet = false;
				}
			}
		}
		DocElement cur = (DocElement)doc.createElement("Log");
		cur.setAttribute("Project", mPrj );
		cur.setAttribute("Trace"  , mTrc );
		cur.setAttribute("Start"  , mTim );
		cur.setAttribute("Status" , (bRet)?"running":"interrupt" );
		root.appendChild( cur );

		if ( saveDocument( doc ) == null ) {
			bRet = false;
		}
	}
	return bRet;
	}

	/**
	 * 実行状態チェック
	 * @param bRet {正常|異常}
	 */
	public boolean check() {
	DocDocument doc = loadDocument();
	if ( doc != null ) {
		DocElement root = (DocElement)doc.getDocumentElement();
		Vector vec = root.findChildElements(".Log");
		Enumeration elm = vec.elements();
		while ( elm.hasMoreElements() ) {
			DocElement log = (DocElement)elm.nextElement();
			if ( log.getAttribute("Project").equals( mPrj ) &&
				 log.getAttribute("Trace").equals( mTrc )   &&
				 log.getAttribute("Start").equals( mTim )   &&
				 log.getAttribute("Status").equals("running") ) {
				return true;
			}
		}
	}
	return false;
	}

	/**
	 * 終了
	 * @param bRet {正常|異常}
	 */
	public void end( boolean bRet ) {
	DocDocument doc = loadDocument();
	if ( doc != null ) {
		DocElement root = (DocElement)doc.getDocumentElement();
		Vector vec = root.findChildElements(".Log");
		Enumeration elm = vec.elements();
		while ( elm.hasMoreElements() ) {
			DocElement log = (DocElement)elm.nextElement();
			if ( log.getAttribute("Project").equals( mPrj ) &&
				 log.getAttribute("Trace").equals( mTrc )   &&
				 log.getAttribute("Start").equals( mTim )   &&
				 log.getAttribute("Status").equals("running") ) {
				// 終了時刻の設定
				log.setAttribute("End",ZString.getDateTime());
				log.setAttribute("Status",(bRet)?"done":"error");
				break;
			}
		}
		saveDocument( doc );
	}
	}

	//## DOM ##########################################################
	/**
	 * ドキュメントのロード
	 * @return ドキュメント
	 */
	protected DocDocument loadDocument() {
	File fFile = new File(mLog);
	DocDocument doc = null;
	if ( fFile.isFile() ) {
		try {
			// パース
			DOMParser parser = new DOMParser();
			parser.setProperty("http://apache.org/xml/properties/dom/document-class-name","jp.co.nri.rid.doc.RidDocument");
			parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
			InputSource in = DocManager.createInputSource(mLog);
			parser.parse(in);
			ZDebug.trace("open:"+mLog);
			doc = (DocDocument)parser.getDocument();
		} catch ( Throwable t ) {
			ZDebug.err("FileOpen failed:"+mLog);
			ZDebug.err("    "+t.toString());
		}
	}
	return doc;
	}

	/**
	 * ドキュメントのセーブ
	 */
	protected DocDocument saveDocument(DocDocument doc) {
	try {
		String  szEncoding = doc.getEncoding();
		boolean bIndenting = doc.getIndenting();
		// 出力
		ZDebug.trace("save:"+mLog);
		OutputFormat fm = new OutputFormat(doc,szEncoding,bIndenting);
		FileOutputStream out = new FileOutputStream(mLog);
		DOMSerializer ser = new XMLSerializer(out,fm).asDOMSerializer();
		ser.serialize(doc);
		return doc;
	} catch ( Throwable t ) {
		ZDebug.err("FileSave failed:"+mLog);
		ZDebug.err("    "+t.toString());
	}
	return null;
	}

	//## アトリビュート ###############################################
	/**
	 * プロジェクト名
	 */
	protected String mPrj = null;

	/**
	 * ログファイル名
	 */
	protected String mLog = null;

	/**
	 * トレースファイル名
	 */
	protected String mTrc = null;

	/**
	 * 開始時刻
	 */
	protected String mTim = null;
}
