/**
 * Convert from FIL to XML
 */
package jp.mydns.masahase.abaqus;

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

/**
 * Abaqusの結果ファイル(*.fil)をXMLに変換して書き出す
 * 
 * @version 1.0
 * @author MASA.H
 * 
 */
public final class Fil2Xml {

	/**
	 * 単体動作用のコード
	 * 
	 * @param args
	 *            実行時の引数
	 */
	public static void main(final String[] args) {
		if (args.length != 2) {
			System.err.println("Need 2 argument.");
			System.err.println("usage:[program name]infile outfile");
			System.exit(0);
		}
		Fil2Xml obj;
		try {
			obj = new Fil2Xml(args[0]);
			obj.setOutputFile(args[1]);
			obj.run();
		} catch (FileNotFoundException e) {
			e.printStackTrace(); // NOPMD by MASA.H on 07/09/11 16:39
		}
	}

	/**
	 * 指定されたファイル名より読み込み
	 * 
	 * @param fname
	 *            読み込み用のファイル名
	 * @throws FileNotFoundException
	 */
	public Fil2Xml(String fname) throws FileNotFoundException {
		setInputFile(fname);
	}

	/**
	 * 読み込みファイル名を設定
	 * 
	 * @param fname
	 *            読み込み用のファイル名
	 * @throws FileNotFoundException
	 */
	public void setInputFile(final String fname) throws FileNotFoundException {
		r_file = new ReadFil();
		r_file.setFileName(fname);
		assert r_file.isType();
	}

	private transient ReadFil r_file;

	/**
	 * 書き出すファイル名を指定
	 * 
	 * @param fname
	 *            ファイル名
	 * @throws FileNotFoundException
	 */
	public void setOutputFile(final String fname) throws FileNotFoundException {
		w_file = new FileOutputStream(fname);
	}

	/**
	 * 本処理
	 */
	public void run() {
		if (r_file != null && w_file != null) {
			try {
				final Document xml_doc = initXmlDocument();
				Object[] record;
				int recordKey;
				final Node rootNode = xml_doc.createElement("AbaqusResult");
				rootNode.appendChild(xml_doc.createComment("made by fil2xml"));

				System.out.println("Start analyzing...");
				while (true) {
					try {
						recordKey = r_file.getNextRecordKey();
						assert recordKey > 0;
						record = r_file.getRecordContents();
						assert record != null;
						final Element pnRecord = convRecord(xml_doc, record,
								recordKey);
						rootNode.appendChild(pnRecord);
					} catch (EOFException e) {
						break;
					}
				}
				System.out.println("Analyzing Finished.");

				xml_doc.appendChild(rootNode);

				System.out.println("Start Writing XMLfile...");
				writeXml(xml_doc);
				w_file.close();
				w_file = null; // NOPMD by MASA.H on 07/09/11 16:39
				System.out.println("Writing XMLfile finished.");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * 結果ファイルよりレコードを取り出し内部表現に変換
	 * 
	 * @param xml_doc
	 * @param record
	 * @param recordKey
	 * @return
	 */
	private Element convRecord(final Document xml_doc, final Object[] record,
			final int recordKey) {
		final Element pnRecord = xml_doc.createElement("Record");
		pnRecord.setAttribute("Key", Integer.valueOf(recordKey).toString());
		assert record.length >= 0;
		for (int i = 0; i < record.length; i++) {
			if (record[i] instanceof String) {
				final Element cnRecord = xml_doc.createElement("String");
				final Text ctNode = xml_doc.createTextNode((String) record[i]);
				cnRecord.appendChild(ctNode);
				pnRecord.appendChild(cnRecord);
			} else if (record[i] instanceof Double) {
				final Element cnRecord = xml_doc.createElement("Float");
				final Text ctNode = xml_doc
						.createTextNode(record[i].toString());
				cnRecord.appendChild(ctNode);
				pnRecord.appendChild(cnRecord);
			} else if (record[i] instanceof Long) {
				final Element cnRecord = xml_doc.createElement("Integer");
				final Text ctNode = xml_doc
						.createTextNode(record[i].toString());
				cnRecord.appendChild(ctNode);
				pnRecord.appendChild(cnRecord);
			} else if (record[i] instanceof Integer) {
				final Element cnRecord = xml_doc.createElement("Integer");
				final Text ctNode = xml_doc
						.createTextNode(record[i].toString());
				cnRecord.appendChild(ctNode);
				pnRecord.appendChild(cnRecord);
			} else {
				final Element cnRecord = xml_doc.createElement("Other");
				final Text ctNode = xml_doc
						.createTextNode(record[i].toString());
				cnRecord.appendChild(ctNode);
				pnRecord.appendChild(cnRecord);
			}
		}
		return pnRecord;
	}

	/**
	 * XMLを処理するための初期化処理
	 * 
	 * @return
	 * @throws ParserConfigurationException
	 */
	private Document initXmlDocument() throws ParserConfigurationException {
		final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		final DocumentBuilder db = dbf.newDocumentBuilder(); // NOPMD by
		// MASA.H on
		// 07/09/11
		// 16:39
		return db.newDocument();
	}

	/**
	 * XMLの内部表現をファイルに書き出す
	 * 
	 * @param xml_doc
	 * @throws TransformerFactoryConfigurationError
	 * @throws TransformerConfigurationException
	 * @throws TransformerException
	 */
	private void writeXml(final Document xml_doc)
			throws TransformerFactoryConfigurationError,
			TransformerConfigurationException, TransformerException {
		final TransformerFactory tff = TransformerFactory.newInstance();
		final Transformer tf = tff.newTransformer(); // NOPMD by MASA.H on
		// 07/09/11 16:39
		final DOMSource src = new DOMSource();
		src.setNode(xml_doc);
		final StreamResult target = new StreamResult();
		target.setOutputStream(w_file);
		tf.transform(src, target);
	}

	private transient FileOutputStream w_file;

}
