/**
 * 
 */
package jp.mydns.masahase.abaqus;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;

import jp.mydns.masahase.AbaqusResult.ElementType;
import jp.mydns.masahase.AbaqusResult.NodeRefType;
import jp.mydns.masahase.AbaqusResult.NodeType;
import jp.mydns.masahase.InherentStrain.ElementsType;
import jp.mydns.masahase.InherentStrain.InherentStrainType;
import jp.mydns.masahase.InherentStrain.NodesType;
import jp.mydns.masahase.InherentStrain.ObjectFactory;
import jp.mydns.masahase.InherentStrain.StrainDataType;
import jp.mydns.masahase.operateXML.AbaqusResult;

/**
 * well-formedなXMLにされた結果ファイルから固有ひずみを取り出し保存する。
 * 
 * <p>
 * {@link Fil2Xml_xjc}で書き出されたXMLファイルから読み出して名前空間
 * &lt;http://www.masahase.mydns.jp/InherentStrain/&gt;で定義されたXMLファイルを書き出す。
 * </p>
 * <p>
 * この際、簡単のため以下の条件をつける
 * <ul>
 * <li>3次元の直交座標系限定</li>
 * <li>固有ひずみを取得するエレメント集合に"PSE"という名前をつけておくこと(つけてもつけなくてもよくなった)</li>
 * <li>溶接線は全体座標でy軸と位置、向きとも同一</li>
 * <li>要素は8節点レンガ型要素のみ</li>
 * <li>固有ひずみとして扱うPEは要素積分点で出力</li>
 * </ul>
 * </p>
 * 
 * @author MASA.H
 * 
 */
public class FilXml2PEStore {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length != 2) {
			System.err.println("Need 2 argument.");
		} else {
			try {
				System.out.println("Initilize...");
				FilXml2PEStore fxp = new FilXml2PEStore();
				fxp.setInput(new FileInputStream(args[0]));
				fxp.setOutput(new java.io.FileOutputStream(args[1]));
				System.out.println("Running...");
				fxp.run();
				System.out.println("Done.");
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

	public FilXml2PEStore() {
		
	}

	ExecutorService e;
	InputStream input;
	OutputStream output;
	double y_center;

	/**
	 * 入力ストリームをセット
	 * 
	 * @param is
	 *            入力ストリーム
	 */
	public void setInput(InputStream is) {
		input = is;
	}

	/**
	 * 出力ストリームのセット
	 * 
	 * @param os
	 *            出力ストリーム
	 */
	public void setOutput(OutputStream os) {
		output = os;
	}

	/**
	 * メイン処理
	 */
	public void run() {
		run(System.out);
	}

	public void run(java.io.PrintStream pout) {
		try {
			AbaqusResult opeAR = new AbaqusResult();
			opeAR.setInput(input);
			opeAR.readXML();
			long[] elemlist_in;
			elemlist_in = opeAR.getElements("PSE");
			if (elemlist_in.length == 0) {
				elemlist_in = opeAR.getElements();
			}
			ObjectFactory objfct = new ObjectFactory();
			InherentStrainType ist = objfct.createInherentStrainType();
			// 取得したひずみ分布を平面に投射
			{
				// ひずみ分布を投射するメッシュの生成
				pout.println("Creating new mesh.");
				createNewMesh(opeAR, elemlist_in, objfct, ist);
				pout.println("Node:" + ist.getNodes().getNum());
				pout.println("Element:" + ist.getElements().getNum());
				// ひずみテンソルの貼り付け
				{
					e = Executors.newFixedThreadPool(3);
					Future<?>[] fnlist = new Future[ist.getNodes().getNum()];
					int i_tmp = 0;
					for (jp.mydns.masahase.InherentStrain.NodeType nd : ist
							.getNodes().getNode()) {
						fnlist[i_tmp] = e.submit(new StrainDataCreater(nd,
								opeAR, objfct));
						i_tmp++;
					}
					i_tmp = 0;
					for (Future<?> fn : fnlist) {
						while (true) {
							if (fn.isDone()) {
								break;
							}
						}
						pout.print("\t"
								+ (i_tmp * 100 / ist.getNodes().getNum())
								+ "%\r");
						i_tmp++;
					}
					e.shutdown();
				}
			}
			double max_x, max_y, min_x, min_y;
			max_x = 0;
			max_y = 0;
			min_x = java.lang.Double.MAX_VALUE;
			min_y = java.lang.Double.MAX_VALUE;
			for (jp.mydns.masahase.InherentStrain.NodeType nd : ist.getNodes()
					.getNode()) {
				if (nd.getX() > max_x) {
					max_x = nd.getX();
				}
				if (nd.getY() > max_y) {
					max_y = nd.getY();
				}
				if (nd.getX() < min_x) {
					min_x = nd.getX();
				}
				if (nd.getY() < min_y) {
					min_y = nd.getY();
				}
			}
			pout.println("Xmax:" + max_x);
			ist.setXMax(Double.valueOf(max_x));
			pout.println("Xmin:" + min_x);
			ist.setXMin(Double.valueOf(min_x));
			pout.println("Ymax:" + max_y);
			ist.setYMax(Double.valueOf(max_y));
			pout.println("Ymin:" + min_y);
			ist.setYMin(Double.valueOf(min_y));

			pout.println();
			pout.println("JAXB initilize...");
			JAXBContext jc = JAXBContext
					.newInstance("jp.mydns.masahase.InherentStrain");
			Marshaller ms = jc.createMarshaller();
			pout.println("Create Marshaller.");
			ms.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			ms.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			pout.println("Marshalling..");
			ms.marshal(ist, output);
		} catch (PropertyException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (JAXBException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
	}

	/**
	 * @param opeAR
	 * @param nd
	 * @return
	 */
	private ArrayList<ElementType> search_element_include_node(
			AbaqusResult opeAR, jp.mydns.masahase.InherentStrain.NodeType nd) {
		ArrayList<ElementType> aet = new ArrayList<ElementType>();
		for (long eid : crosselemlist) {
			ElementType et_temp = opeAR.getElement(eid);
			boolean done = false;
			boolean chk = false;
			for (NodeRefType nr : et_temp.getNodeRef()) {
				if ((!done)
						&& (nr.getNodeId() == nodepair.get(nd.getId() - 1)[0] || nr
								.getNodeId() == nodepair.get(nd.getId() - 1)[1])) {
					if ((!chk)
							&& (!((nr.getNodeId() == nodepair
									.get(nd.getId() - 1)[0] && nr.getNodeId() == nodepair
									.get(nd.getId() - 1)[1])))) {
						chk = true;
					} else {
						aet.add(et_temp);
						done = true;
					}
				}
			}
		}
		return aet;
	}

	private long[][] nodelist_in;
	private ArrayList<long[]> nodepair;
	private ArrayList<Long> crosselemlist;

	/**
	 * @param opeAR
	 * @param elemlist_in
	 * @param objfct
	 * @param ist
	 * @throws Error
	 */
	private void createNewMesh(AbaqusResult opeAR, long[] elemlist_in,
			ObjectFactory objfct, InherentStrainType ist) throws Error {
		nodelist_in = new long[elemlist_in.length][8];
		for (int i = 0; i < elemlist_in.length; i++) {
			ElementType et = opeAR.getElement(elemlist_in[i]);
			if (et == null)
				throw new java.lang.RuntimeException("element lost:"
						+ elemlist_in[i] + ":" + i);
			if (!et.getType().contains("C3D8")) {
				continue;
			}
			for (int j = 0; j < 8; j++) {
				nodelist_in[i][j] = et.getNodeRef().get(j).getNodeId();
			}
		}
		// 古いメッシュのy方向の範囲の取得
		double x_max = 0, x_min = 100000000;
		double y_max = 0, y_min = 100000000;
		double z_max = 0, z_min = 100000000;
		for (long[] nodes : nodelist_in) {
			for (long nodeid : nodes) {
				NodeType nt = opeAR.getNode(nodeid);
				if (nt.getC1() > x_max) {
					x_max = nt.getC1();
				} else if (nt.getC1() < x_min) {
					x_min = nt.getC1();
				}
				if (nt.getC2() > y_max) {
					y_max = nt.getC2();
				} else if (nt.getC2() < y_min) {
					y_min = nt.getC2();
				}
				if (nt.getC3() > z_max) {
					z_max = nt.getC3();
				} else if (nt.getC3() < z_min) {
					z_min = nt.getC3();
				}
			}
		}
		y_center = 0.5 * (y_max + y_min);
		crosselemlist = new ArrayList<Long>();
		// 新しいメッシュのノードを作る古いメッシュにおけるノードのペアの探索
		// 断面を含むエレメントのリストアップ
		nodepair = new ArrayList<long[]>();
		searchNodePair(opeAR, elemlist_in);
		// 新しいメッシュのためのノードを生成
		NodesType nst = ist.getNodes();
		if (nst == null) {
			nst = objfct.createNodesType();
			ist.setNodes(nst);
		}
		if (nodepair.isEmpty()) {
			throw new java.lang.RuntimeException("no node pair found.");
		}
		makeNode(opeAR, objfct, nst);
		if (nst.getNode() == null) {
			throw new java.lang.RuntimeException("no node made.");
		} else {
			nst.setNum(nst.getNode().size());
		}
		// エレメント生成
		ElementsType est = ist.getElements();
		if (est == null) {
			est = objfct.createElementsType();
			ist.setElements(est);
		}
		// 元のメッシュを参考にエレメントを生成
		for (int i = 0; i < crosselemlist.size(); i++) {
			jp.mydns.masahase.InherentStrain.ElementType et = objfct
					.createElementType();
			et.setId(est.getElement().size() + 1);
			ArrayList<Long> nl = new ArrayList<Long>();
			// あるエレメントに属するノードのリストアップ
			listup_nodes_in_element(opeAR, i, nl);
			// ノードのソート
			sort_nodeslist(nst, nl);
			if (nl.size() > 0)
				guess_element_type(objfct, est, i, et, nl, nst);
		}
		// check
		ArrayList<jp.mydns.masahase.InherentStrain.ElementType> remove_list;
		remove_list = new ArrayList<jp.mydns.masahase.InherentStrain.ElementType>();
		for (jp.mydns.masahase.InherentStrain.ElementType et : est.getElement()) {
			jp.mydns.masahase.InherentStrain.NodeType nd1, nd2, nd3;
			nd1 = ist.getNodes().getNode().get(et.getNodeId().get(0) - 1);
			nd2 = ist.getNodes().getNode().get(et.getNodeId().get(1) - 1);
			nd3 = ist.getNodes().getNode().get(et.getNodeId().get(2) - 1);
			if ((nd1.getX() == nd2.getX() && nd1.getX() == nd3.getX())
					|| (nd1.getY() == nd2.getY() && nd1.getY() == nd3.getY())) {
				remove_list.add(et);
			}
		}
		for (jp.mydns.masahase.InherentStrain.ElementType et : remove_list) {
			est.getElement().remove(et);
		}
		est.setNum(est.getElement().size());
	}

	/**
	 * @param objfct
	 * @param est
	 * @param i
	 * @param et
	 * @param nl
	 * @throws Error
	 */
	private void guess_element_type(ObjectFactory objfct, ElementsType est,
			int i, jp.mydns.masahase.InherentStrain.ElementType et,
			ArrayList<Long> nl, NodesType nst) throws Error {
		double[] center = new double[2];
		Long[] nl_array = new Long[nl.size()];
		for (int j = 0; j < nl.size(); j++) {
			nl_array[j] = nl.get(j);
		}
		double[] angle = new double[nl_array.length];
		for (Long nid : nl_array) {
			center[0] += nst.getNode().get(nid.intValue() - 1).getX();
			center[1] += nst.getNode().get(nid.intValue() - 1).getY();
		}
		center[0] = center[0] / nl_array.length;
		center[1] = center[1] / nl_array.length;
		for (int j = 0; j < nl_array.length; j++) {
			angle[j] = Math.atan2(nst.getNode().get(nl_array[j].intValue() - 1)
					.getY()
					- center[1], nst.getNode().get(nl_array[j].intValue() - 1)
					.getX()
					- center[0]);
		}
		int[] sorted_nd = new int[nl_array.length];
		for (int j = 0; j < nl_array.length; j++) {
			sorted_nd[j] = j;
		}
		for (int j = 0; j < nl_array.length - 1; j++) {
			for (int k = j + 1; k < nl_array.length; k++) {
				if (angle[sorted_nd[j]] > angle[sorted_nd[k]]) {
					int int_buf = sorted_nd[j];
					sorted_nd[j] = sorted_nd[k];
					sorted_nd[k] = int_buf;
				} else if (angle[sorted_nd[j]] == angle[sorted_nd[k]]) {
					double r1, r2;
					r1 = (nst.getNode().get(
							nl_array[sorted_nd[j]].intValue() - 1).getX() - center[0])
							* (nst.getNode().get(
									nl_array[sorted_nd[j]].intValue() - 1)
									.getX() - center[0])
							+ (nst.getNode().get(
									nl_array[sorted_nd[j]].intValue() - 1)
									.getY() - center[1])
							* (nst.getNode().get(
									nl_array[sorted_nd[j]].intValue() - 1)
									.getY() - center[1]);
					r2 = (nst.getNode().get(
							nl_array[sorted_nd[k]].intValue() - 1).getX() - center[0])
							* (nst.getNode().get(
									nl_array[sorted_nd[k]].intValue() - 1)
									.getX() - center[0])
							+ (nst.getNode().get(
									nl_array[sorted_nd[k]].intValue() - 1)
									.getY() - center[1])
							* (nst.getNode().get(
									nl_array[sorted_nd[k]].intValue() - 1)
									.getY() - center[1]);
					if (r2 < r1) {
						int int_buf = sorted_nd[j];
						sorted_nd[j] = sorted_nd[k];
						sorted_nd[k] = int_buf;
					}
				}
			}
		}

		switch (nl.size()) {
        case 1:
            break;
        case 2:
            break;
		case 3:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.setType("C2D3");
			est.getElement().add(et);
			break;
		case 4:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			break;
		case 5:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[4]].intValue());
			et.setType("C2D3");
			est.getElement().add(et);
			break;
		case 6:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[4]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			break;
		case 7:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[4]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[6]].intValue());
			et.setType("C2D3");
			est.getElement().add(et);
			break;
		case 8:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[4]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[6]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[7]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			break;
		case 9:
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[1]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[2]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[3]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[4]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[5]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[6]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[7]].intValue());
			et.setType("C2D4");
			est.getElement().add(et);
			est.getElement().add(et);
			et = objfct.createElementType();
			et.setId(est.getElement().size() + 1);
			et.getNodeId().add(nl_array[sorted_nd[0]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[7]].intValue());
			et.getNodeId().add(nl_array[sorted_nd[8]].intValue());
			et.setType("C2D3");
			est.getElement().add(et);
			break;
		default:
			throw new Error("Unexpected Mesh:" + nl + ":elem:"
					+ crosselemlist.get(i));
		}
	}

	/**
	 * @param nst
	 * @param nl
	 */
	private void sort_nodeslist(NodesType nst, ArrayList<Long> nl) {
		{
			double x = 0, y = 0;
			for (Long id : nl) {
				x += nst.getNode().get(id.intValue() - 1).getX();
				y += nst.getNode().get(id.intValue() - 1).getY();
			}
			x = x / nl.size();
			y = y / nl.size();
			Long[] ndbuf = nl.toArray(new Long[0]);
			// バブルソート
			while (true) {
				int count = 0;
				for (int j = 0; j < nl.size() - 1; j++) {
					double arg1, arg2;
					arg1 = Math
							.atan(nst.getNode().get(ndbuf[j].intValue() - 1)
									.getY()
									/ nst.getNode()
											.get(ndbuf[j].intValue() - 1)
											.getX());
					arg2 = Math.atan(nst.getNode().get(
							ndbuf[j + 1].intValue() - 1).getY()
							/ nst.getNode().get(ndbuf[j + 1].intValue() - 1)
									.getX());
					if (arg2 < arg1) {
						count++;
						long tmp = ndbuf[j];
						ndbuf[j] = ndbuf[j + 1];
						ndbuf[j + 1] = tmp;
					}
				}
				if (count == 0) {
					break;
				}
			}
			nl.clear();
			for (long id : ndbuf) {
				nl.add(id);
			}
		}
	}

	/**
	 * @param opeAR
	 * @param i
	 * @param nl
	 */
	private void listup_nodes_in_element(AbaqusResult opeAR, int i,
			ArrayList<Long> nl) {
		for (long[] pair : nodepair) {
			boolean chk = false;
			boolean done = false;
			for (NodeRefType nr : opeAR.getElement(crosselemlist.get(i))
					.getNodeRef()) {
				if (nr.getNodeId() == pair[0] || nr.getNodeId() == pair[1]) {
					if ((chk || (nr.getNodeId() == pair[0] && nr.getNodeId() == pair[1]))
							&& !done
							&& !nl.contains(Long
									.valueOf(nodepair.indexOf(pair) + 1))) {
						nl.add(Long.valueOf(nodepair.indexOf(pair) + 1));
						done = true;
					}
					chk = true;
				}
			}
		}
	}

	/**
	 * @param opeAR
	 * @param elemlist_in
	 */
	/*
	 * private void listup_elements_on_cs(AbaqusResult opeAR, long[]
	 * elemlist_in) { for (int i = 0; i < elemlist_in.length; i++) { //
	 * リストアップ済みかどうか boolean done; done = false; boolean chk = false; ElementType
	 * et; et = opeAR.getElement(i + 1); for (long[] pair : nodepair) { for
	 * (NodeRefType nr : et.getNodeRef()) { if (!done && (nr.getNodeId() ==
	 * pair[0] || nr.getNodeId() == pair[1])) { if (chk || (nr.getNodeId() ==
	 * pair[0] && nr.getNodeId() == pair[1])) { crosselemlist.add(et.getId());
	 * done = true; } else { chk = true; } } } chk = false; } } }
	 */

	/**
	 * @param opeAR
	 * @param objfct
	 * @param nst
	 */
	private void makeNode(AbaqusResult opeAR, ObjectFactory objfct,
			NodesType nst) {
		for (int i = 0; i < nodepair.size(); i++) {
			jp.mydns.masahase.InherentStrain.NodeType nt = objfct
					.createNodeType();
			nt.setId(i + 1);
			double x1 = opeAR.getNode(nodepair.get(i)[0]).getC1();
			double x2 = opeAR.getNode(nodepair.get(i)[1]).getC1();
			double y1 = opeAR.getNode(nodepair.get(i)[0]).getC2();
			double y2 = opeAR.getNode(nodepair.get(i)[1]).getC2();
			double z1 = opeAR.getNode(nodepair.get(i)[0]).getC3();
			double z2 = opeAR.getNode(nodepair.get(i)[1]).getC3();
			double dy = y1 - y2;
			double dx = x1 - x2;
			double dz = z1 - z2;
			//if (dy < 1.0e-3 && dy > -1.0e-3) {
				nt.setX((x1+x2)*0.5);
				nt.setY((z1+z2)*0.5);
			//} else {
			//	nt.setX((dy * x1 - dx * y1) / dy);
			//	nt.setY((dy * z1 - dz * y1) / dy);
			//}
            try{
            assert nt.getX()<1.0e10;
            assert nt.getX()>-1.0e10;
            assert nt.getY()<1.0e10;
            assert nt.getY()>-1.0e10;
            }catch (AssertionError e){
                System.out.println(x1);
                System.out.println(y1);
                System.out.println(z1);
                System.out.println(x2);
                System.out.println(y2);
                System.out.println(z2);
                e.printStackTrace();
            }
			nst.getNode().add(nt);
		}
	}

	/**
	 * @param opeAR
	 * @param elemlist_in
	 * @param nodelist_in
	 * @param y_center
	 */
	private void searchNodePair(AbaqusResult opeAR, long[] elemlist_in) {
		for (int i = 0; i < elemlist_in.length; i++) {
			boolean chkpt = true;
			NodeType[] nt = new NodeType[8];
			for (int j = 0; j < 8; j++) {
				nt[j] = opeAR.getNode(nodelist_in[i][j]);
			}
			if ((nt[0].getC2() - y_center) * (nt[1].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[0].getId();
				tmp[1] = nt[1].getId();
				nodepair.add(tmp);
				crosselemlist.add(elemlist_in[i]);
				chkpt = false;
			}
			if ((nt[1].getC2() - y_center) * (nt[2].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[1].getId();
				tmp[1] = nt[2].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[2].getC2() - y_center) * (nt[3].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[2].getId();
				tmp[1] = nt[3].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[0].getC2() - y_center) * (nt[3].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[0].getId();
				tmp[1] = nt[3].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[4].getC2() - y_center) * (nt[5].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[4].getId();
				tmp[1] = nt[5].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[5].getC2() - y_center) * (nt[6].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[5].getId();
				tmp[1] = nt[6].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[6].getC2() - y_center) * (nt[7].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[6].getId();
				tmp[1] = nt[7].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[4].getC2() - y_center) * (nt[7].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[4].getId();
				tmp[1] = nt[7].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[0].getC2() - y_center) * (nt[4].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[0].getId();
				tmp[1] = nt[4].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[1].getC2() - y_center) * (nt[4].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[1].getId();
				tmp[1] = nt[4].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[2].getC2() - y_center) * (nt[6].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[2].getId();
				tmp[1] = nt[6].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			if ((nt[3].getC2() - y_center) * (nt[7].getC2() - y_center) < 0) {
				long[] tmp = new long[2];
				tmp[0] = nt[3].getId();
				tmp[1] = nt[7].getId();
				nodepair.add(tmp);
				if (chkpt) {
					crosselemlist.add(elemlist_in[i]);
					chkpt = false;
				}
			}
			for (NodeType ntt : nt) {
				if (ntt.getC2() == y_center) {
					long[] tmp = new long[2];
					tmp[0] = ntt.getId();
					tmp[1] = ntt.getId();
					nodepair.add(tmp);
					if (chkpt) {
						crosselemlist.add(elemlist_in[i]);
						chkpt = false;
					}
				}
			}
			// 重複の削除
			for (int k = 0; k < nodepair.size(); k++) {
				long[] pbuf_k = nodepair.get(k);
				for (int j = k + 1; j < nodepair.size(); j++) {
					long[] pbuf_j = nodepair.get(j);
					if ((pbuf_k[0] == pbuf_j[0] && pbuf_k[1] == pbuf_j[1])
							|| (pbuf_k[0] == pbuf_j[1] && pbuf_k[1] == pbuf_j[0])) {
						nodepair.remove(j);
					}
				}
			}
		}
		if (nodepair.isEmpty()) {
			throw new java.lang.RuntimeException("no node pair found."
					+ "[y_center:" + y_center + "]");
		}
	}

	protected class StrainDataCreater implements Runnable {
		public StrainDataCreater(jp.mydns.masahase.InherentStrain.NodeType ndt,
				AbaqusResult opeAR, ObjectFactory objfct) {
			nd = ndt;
			this.opeAR = opeAR;
			this.objfct = objfct;
		}

		private final jp.mydns.masahase.InherentStrain.NodeType nd;
		private final AbaqusResult opeAR;
		private final ObjectFactory objfct;

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			double[] newValue = new double[6];
			StrainDataType sdt = objfct.createStrainDataType();
			if (crosselemlist.isEmpty()) {
				throw new java.lang.RuntimeException("Faild Create Mesh");
			}
			// 貼り付ける新しいノードを含む古いエレメントを探索
			ArrayList<ElementType> aet = search_element_include_node(opeAR, nd);
			{
				for (int i = 0; i < newValue.length; i++) {
					newValue[i] = 0;
				}
				for (ElementType et : aet) {
					long eid = et.getId();
					int isize = 1;
					if (et.getType().equalsIgnoreCase("C3D8")) {
						isize = 8;
					}
					Object[][] IntegValue = new Object[isize][];
					Object[][] IntegCoord = new Object[isize][];
					// 元のメッシュから 情報の読み取り
					for (int i = 0; i < isize; i++) {
						IntegValue[i] = opeAR.getElementOutput_integ(eid,
								i + 1, "PE");
						if (IntegValue[i] == null) {
							throw new Error("Can't get value.eid=" + eid + "["
									+ (i + 1) + ":PE]");
						}
						IntegCoord[i] = opeAR.getElementOutput_integ(eid,
								i + 1, 1, 1, "COORD");
						if (IntegCoord[i] == null)
							IntegCoord[i] = opeAR.getElementOutput_integ(eid,
									i + 1, "COORD");
						if (IntegCoord[i] == null) {
							throw new Error("Can't get value.eid=" + eid + "["
									+ (i + 1) + ":COORD]");
						}
					}

					double[][] iCoord = new double[isize][3];
					for (int i = 0; i < isize; i++) {
						for (int j = 0; j < 3; j++) {
							iCoord[i][j] = (Double) IntegCoord[i][j];
						}
					}
					/*
					 * double[] oldX = { x, y, z }; double[] newX = FemFunc
					 * .invertFormFunction8Blick(oldX, iCoord); for (int i = 0;
					 * i < newValue.length; i++) { double[] iValue = new
					 * double[8]; for (int j = 0; j < 8; j++) { iValue[j] =
					 * (Double) IntegValue[j][i]; } newValue[i] +=
					 * FemFunc.formFunction8Blick( newX[0], newX[1], newX[2],
					 * iValue); }
					 */
					// その要素での平均を加算
					if (isize > 1) {
						for (int i = 0; i < newValue.length; i++) {
							double[] iValue = new double[isize];
							for (int j = 0; j < isize; j++) {
								iValue[j] = (Double) IntegValue[j][i];
							}
							// ガウス積分
							double integ = 0;
							for (double d : iValue) {
								integ += d;
							}
							newValue[i] += integ / iValue.length;
						}
					} else {
						for (int i = 0; i < newValue.length; i++) {
							newValue[i] += (Double) IntegValue[0][i];
						}
					}
				}
				// 加算した要素数で割りその点での平滑化した値とする
				for (int i = 0; i < newValue.length; i++) {
					newValue[i] /= aet.size();
					if (newValue[i] == java.lang.Double.NaN) {
						throw new java.lang.RuntimeException("Fail Calc."
								+ aet.size());
					}
				}
			}
			sdt.setX(newValue[0]);
			sdt.setY(newValue[1]);
			sdt.setZ(newValue[2]);
			sdt.setXy(newValue[3]);
			sdt.setXz(newValue[4]);
			sdt.setYz(newValue[5]);
			nd.setStrainData(sdt);
		}

	}
}
