/*
 * Projrct F-11 - Web SCADA for Java
 * Copyright (C) 2002 Freedom, Inc. All Rights Reserved.
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

package org.F11.scada.applet.expression;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import jp.gr.javacons.jim.DataHolder;
import jp.gr.javacons.jim.Manager;
import jp.gr.javacons.jim.QualityFlag;

import org.F11.scada.WifeException;
import org.F11.scada.applet.expression.text.Format;
import org.F11.scada.applet.expression.text.FormatFactory;
import org.F11.scada.data.ConvertValue;
import org.F11.scada.data.WifeDataAnalog;
import org.F11.scada.data.WifeDataDigital;
import org.F11.scada.xwife.server.WifeDataProvider;

/**
 * 式の値を計算するクラスです
 * 計算式を逆ポーランド記法に変換し、値を取得します
 * @version 1.0
 * @author Youhei Horikawa <hori@users.sourceforge.jp>
 */
public class Expression {
//	private static Logger log = Logger.getLogger(Expression.class);
	/** 処理した項目が値項目の場合にtrue */
	private boolean termIsVariable = false;
	/** 計算式(Term)の項目リスト（逆ポーランド記法） */
	private List terms;
	/** 使用しているホルダ */
	private Set holders;
	/** 初期状態処理モード */
	private boolean isEnableInitialMode;

	/**
	 * 初期状態処理モードを true で初期化します。
	 */
	public Expression() {
		this(true);
	}
	
	/**
	 * 初期状態処理モードを設定し初期化します。isEnableInitialModeがtrueの場合、
	 * 参照ホルダのQualityFlagがGOOD,BAD以外の時は例外発生。
	 * @param isEnableInitialMode isEnableInitialModeがtrueの場合、参照ホルダのQualityFlagがGOOD,BAD以外の時は例外発生。
	 */
	public Expression(boolean isEnableInitialMode) {
		this.isEnableInitialMode = isEnableInitialMode;
	}

	/**
	 * 与えられた計算式を逆ポーランド記法の式に変換します。
	 * @param ex 計算式
	 */
	public void toPostfix(String ex) {
		terms = new ArrayList();
		Stack operations = new Stack();
		Term term = null;
		for (ExpressionTokenizer et = new ExpressionTokenizer(ex);
				et.hasMoreTokens();) {
			String token = et.nextToken();
			term = TermFactory.createTerm(token, isEnableInitialMode, operations);
			term.convHandle(token, this, operations);
		}
		term = TermFactory.createTerm("#END#", isEnableInitialMode, operations);
		term.convHandle(null, this, operations);
		holders = createHolders();
	}
	
	private Set createHolders() {
		Set ls = new HashSet();
		for (Iterator it = terms.iterator(); it.hasNext();) {
			Object o = it.next();
			if (o instanceof TermValiable) {
				ls.add(o.toString());
			}
		}
		return ls;
	}

	/**
	 * 逆ポーランド記法の式を文字列で返します。
	 * デバッグ用の関数です
	 * @return 式の文字列表現
	 */
	String getRPNString() {
		StringBuffer sb = new StringBuffer();
		for (Iterator it = terms.iterator(); it.hasNext();) {
			sb.append(it.next());
			sb.append(',');
		}
		return sb.toString();
	}

	/**
	 * 逆ポーランド記法の式からdouble値を取得します。
	 * @return 計算結果
	 */
	public double doubleValue() throws WifeException {
		return calcPostfix().doubleValue();
	}

	/**
	 * 逆ポーランド記法の式からboolean値を取得します。
	 * @return 計算結果
	 */
	public boolean booleanValue() throws WifeException {
		return calcPostfix().booleanValue();
	}

	/**
	 * 式中のプロバイダ_ホルダ名のセットを返します
	 * @return プロバイダ_ホルダ名のセット（重複なし）
	 */
	public Set getProviderHolderNames() {
		if (null != holders) {
			return holders;
		} else {
			return createHolders();
		}
	}

	/**
	 * 式中のプロバイダ_ホルダ名でvalueをフォーマットする
	 * @param value
	 * @return
	 */
	public String format(double value, String pattern) {
		ConvertValue conv = null;
		conv = getConvertValue(conv);
		if (conv != null) {
			if (pattern != null)
				return conv.convertStringValue(conv.convertInputValue(value), pattern);
			else
				return conv.convertStringValue(conv.convertInputValue(value));
		}
		if (pattern != null) {
			FormatFactory factory = new FormatFactory();
			Format format = factory.getFormat(pattern);
			return format.format(value);
		}
		return String.valueOf(value);
	}

	private ConvertValue getConvertValue(ConvertValue conv) {
		for (Iterator it = getProviderHolderNames().iterator(); it.hasNext();) {
			String tag = (String) it.next();
			int p = tag.indexOf('_');
			if (0 < p) {
				DataHolder dh =
					Manager.getInstance().findDataHolder(tag.substring(0, p), tag.substring(p + 1));
				if (dh != null) {
					ConvertValue cv = (ConvertValue) dh.getParameter(WifeDataProvider.PARA_NAME_CONVERT);
					if (cv != null) {
						if (conv == null
							|| conv.getPattern().length() <= cv.getPattern().length()) {
							conv = cv;
							break;
						}
					}
				}
			}
		}
		return conv;
	}

	/**
	 * 式中に「プロバイダ_ホルダ名」が存在するかを判定します。
	 * @param name プロバイダ_ホルダ名
	 * @return 存在する場合は true を しない場合は false を返します。
	 */
	public boolean hasDataHolder(String name) {
		return holders.contains(name);
	}

	/**
	 * 逆ポーランド記法の式を計算し、結果を返します。
	 * @return 計算結果のAbstractValiableオブジェクト
	 */
	private AbstractValiable calcPostfix() throws WifeException {
		Stack operations = new Stack();
		for (Iterator it = terms.iterator(); it.hasNext();) {
			Term s = (Term) it.next();
			s.calcHandle(this, operations);
		}
		AbstractValiable s = (AbstractValiable) operations.pop();
		return s;
	}

	// 以降のメソッドは、Termのハンドラメソッドより呼び出されます。
	private void push(Term s, Stack operations) {
		operations.push((Object) s);
	}

	private Term pop(Stack operations) {
		return (Term) operations.pop();
	}

	private boolean empty(Stack operations) {
		return operations.empty();
	}

	private Term peek(Stack operations) {
		return (Term) operations.peek();
	}

	private void setTermIsVariable(boolean termIsVariable) {
		this.termIsVariable = termIsVariable;
	}

	private boolean isTermIsVariable() {
		return termIsVariable;
	}

	/**
	 * 結果のリストへ追加します。
	 * @param s
	 */
	private void send(Term s) {
		terms.add(s);
	}

	/**
	 * 計算式の各項目のインタフェイスです
	 * <p>タイトル: </p>
	 * <p>説明: </p>
	 * <p>著作権: Copyright (c) 2002</p>
	 * <p>会社名: </p>
	 * @author 未入力
	 * @version 1.0
	 */
	private interface Term {
		public void convHandle(String token, Expression rp, Stack operations);
		public int getPriority();
		public void calcHandle(Expression rp, Stack operations) throws WifeException;
	}

	/**
	 * 値を保持する項目の基底クラスです
	 * <p>タイトル: </p>
	 * <p>説明: </p>
	 * <p>著作権: Copyright (c) 2002</p>
	 * <p>会社名: </p>
	 * @author 未入力
	 * @version 1.0
	 */
	private abstract static class AbstractValiable implements Term {
		public void convHandle(String token, Expression rp, Stack operations) {
			rp.send(this);
			rp.setTermIsVariable(true);
		}
		public void calcHandle(Expression rp, Stack operations) {
			rp.push(this, operations);
		}
		public int getPriority() {
			return 0;
		}
		public double doubleValue() throws WifeException {
			throw new WifeException(
				WifeException.WIFE_WARNING,
				WifeException.WIFE_EXPRESSION_WARNING,
				"型不一致");
		}
		public boolean booleanValue() throws WifeException {
			throw new WifeException(
				WifeException.WIFE_WARNING,
				WifeException.WIFE_EXPRESSION_WARNING,
				"型不一致");
		}
	}

	/**
	 * リファレンサを保持するクラスです
	 * @version 1.0
	 * @author Youhei Horikawa <hori@users.sourceforge.jp>
	 */
	private static class TermValiable extends AbstractValiable {
		private final String ph_name;
		private final boolean isEnableInitialMode;

		public TermValiable(String token, boolean isEnableInitialMode) {
			this.ph_name = token;
			this.isEnableInitialMode = isEnableInitialMode;
		}

		public String toString() {
			return ph_name;
		}

		/**
		 *
		 * @return リファレンサ参照アナログ値
		 */
		public double doubleValue() throws WifeException {
			DataHolder dh = null;
			int p = ph_name.indexOf('_');
			if (0 < p) {
				dh =
					Manager.getInstance().findDataHolder(
						ph_name.substring(0, p),
						ph_name.substring(p + 1));
			}
			if (dh == null) {
				throw new WifeException(
					WifeException.WIFE_ERROR,
					WifeException.WIFE_EXPRESSION_WARNING,
					"プロバイダ_ホルダ未登録:" + ph_name);
			}
			if (!(dh.getValue() instanceof WifeDataAnalog)) {
				return super.doubleValue();
			} else {
				ConvertValue conv = (ConvertValue) dh.getParameter("convert");
				switch (dh.getQualityFlag().getQuality()) {
				case QualityFlag.GOOD:
					WifeDataAnalog da = (WifeDataAnalog) dh.getValue();
					return conv.convertDoubleValue(da.doubleValue());
				case QualityFlag.BAD:
					// 通信エラー時
					throw new WifeException(
							WifeException.WIFE_WARNING,
							WifeException.WIFE_BAD_DATA_WARNING,
							"データ取得失敗:" + ph_name);
				default:
					// 未更新時
					if (isEnableInitialMode) {
						throw new WifeException(
								WifeException.WIFE_WARNING,
								WifeException.WIFE_INITIALDATA_WARNING,
								"データ未更新:" + ph_name);
					} else {
						return conv.convertDoubleValue(0);
					}
				}
			}
		}

		/**
		 *
		 * @return リファレンサ参照デジタル値
		 */
		public boolean booleanValue() throws WifeException {
			DataHolder dh = null;
			int p = ph_name.indexOf('_');
			if (0 < p) {
				dh =
					Manager.getInstance().findDataHolder(
						ph_name.substring(0, p),
						ph_name.substring(p + 1));
			}
			if (dh == null) {
				throw new WifeException(
					WifeException.WIFE_WARNING,
					WifeException.WIFE_BAD_DATA_WARNING,
					"プロバイダ_ホルダ未登録:" + ph_name);
			}
			if (!(dh.getValue() instanceof WifeDataDigital)) {
				return super.booleanValue();
			} else {
				switch (dh.getQualityFlag().getQuality()) {
				case QualityFlag.GOOD:
					WifeDataDigital wdd = (WifeDataDigital) dh.getValue();
					return wdd.isOnOff(true);
				case QualityFlag.BAD:
					// 通信エラー時
					throw new WifeException(
							WifeException.WIFE_WARNING,
							WifeException.WIFE_BAD_DATA_WARNING,
							"データ取得失敗:" + ph_name);
				default:
					// 未更新時
					if (isEnableInitialMode) {
						throw new WifeException(
								WifeException.WIFE_WARNING,
								WifeException.WIFE_INITIALDATA_WARNING,
								"データ未更新:" + ph_name);
					} else {
						return false;
					}
				}
			}
		}
	}

	/**
	 * 実数を保持するクラスです
	 * @version 1.0
	 * @author Youhei Horikawa <hori@users.sourceforge.jp>
	 */
	private static class TermDouble extends AbstractValiable {
		private double value;

		public TermDouble(double value) {
			this.value = value;
		}

		public String toString() {
			return String.valueOf(value);
		}

		public double doubleValue() {
			return value;
		}
	}

	/**
	 * 計算式の各項目を生成するファクトリクラスです
	 * @version 1.0
	 * @author Youhei Horikawa <hori@users.sourceforge.jp>
	 */
	private static class TermFactory {
		/** 定義済み項目のマップ */
		private static Map opes;
		/**
		 * 演算子の基底クラスです
		 * @version 1.0
		 * @author Youhei Horikawa <hori@users.sourceforge.jp>
		 */
		private abstract static class AbstractOperator implements Term {
			public void convHandle(String token, Expression rp, Stack operations) {
				while (true) {
					if (rp.empty(operations) || (rp.peek(operations) == TermFactory.TERM_BRA)) {
						break;
					}
					Term state = (Term) rp.peek(operations);
					if (this.getPriority() < state.getPriority()) {
						break;
					} else {
						rp.send(rp.pop(operations));
					}
				}
				rp.push(this, operations);
				rp.setTermIsVariable(false);
			}
		}
		/**
		 * 算術関数の基底クラスです
		 * @version 1.0
		 * @author Youhei Horikawa <hori@users.sourceforge.jp>
		 */
		private abstract static class AbstractFunction implements Term {
			public void convHandle(String token, Expression rp, Stack operations) {
				while (true) {
					if (rp.empty(operations) || (rp.peek(operations) == TermFactory.TERM_BRA)) {
						break;
					}
					Term state = (Term) rp.peek(operations);
					if (this.getPriority() <= state.getPriority()) {
						break;
					} else {
						rp.send(rp.pop(operations));
					}
				}
				rp.push(this, operations);
				rp.setTermIsVariable(false);
			}
			public int getPriority() {
				return 3;
			}
		}

		/** 制御定数：逆ポーランド式の終わり */
		private static final Term TERM_END = new AbstractValiable() {
			public void convHandle(String token, Expression rp, Stack operations) {
				while (!rp.empty(operations)) {
					Term state = rp.pop(operations);
					if (state == TERM_BRA) {
						throw new RuntimeException("括弧が閉じていない");
					}
					rp.send(state);
				}
				rp.send(this);
			}

			public void calcHandle(Expression rp, Stack operations) {
				AbstractValiable state = (AbstractValiable) rp.pop(operations);
				if (!rp.empty(operations)) {
					throw new RuntimeException("不正な計算式");
				}
				rp.push(state, operations);
			}

			public String toString() {
				return "#end#";
			}
		};
		/** 制御定数：ブラケット '(' */
		private static final Term TERM_BRA = new AbstractValiable() {
			public void convHandle(String token, Expression rp, Stack operations) {
				rp.push(this, operations);
				rp.setTermIsVariable(false);
			}
			public void calcHandle(Expression rp, Stack operations) {
				throw new RuntimeException("不正な計算式");
			}
			public String toString() {
				return "(";
			}
		};
		/** 制御定数：ブラケット ')' */
		private static final Term TERM_CKET = new AbstractValiable() {
			public void convHandle(String token, Expression rp, Stack operations) {
				while (!rp.empty(operations)) {
					Term state = rp.pop(operations);
					if (state == TERM_BRA) {
						rp.setTermIsVariable(true);
						return;
					} else {
						rp.send(state);
					}
				}
				throw new RuntimeException("括弧が閉じていない");
			}
			public void calcHandle(Expression rp, Stack operations) {
				throw new RuntimeException("不正な計算式");
			}
			public String toString() {
				return ")";
			}
		};
		/** 論理定数：真 */
		private static final Term TERM_TRUE = new AbstractValiable() {
			public String toString() {
				return "true";
			}
			public boolean booleanValue() {
				return true;
			}
		};
		/** 論理定数：偽 */
		private static final Term TERM_FALSE = new AbstractValiable() {
			public String toString() {
				return "false";
			}
			public boolean booleanValue() {
				return false;
			}
		};
		/** 実定数：円周率 */
		private static final Term TERM_PI = new AbstractValiable() {
			public String toString() {
				return "pi";
			}
			public double doubleValue() {
				return Math.PI;
			}
		};
		/** 算術演算子：べき乗 */
		private static final Term TERM_OPR_POW = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.pow(d2, d1)), operations);
			}
			public int getPriority() {
				return 4;
			}
			public String toString() {
				return "^";
			}
		};
		/** 算術演算子：積 */
		private static final Term TERM_OPR_MUL = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(d2 * d1), operations);
			}
			public int getPriority() {
				return 4;
			}
			public String toString() {
				return "*";
			}
		};
		/** 算術演算子：余 */
		private static final Term TERM_OPR_DIV = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(d2 / d1), operations);
			}
			public int getPriority() {
				return 4;
			}
			public String toString() {
				return "/";
			}
		};
		/** 算術演算子：和 */
		private static final Term TERM_OPR_ADD = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(d2 + d1), operations);
			}
			public void convHandle(String token, Expression rp, Stack operations) {
				if (rp.isTermIsVariable()) {
					super.convHandle(token, rp, operations);
				}
			}
			public int getPriority() {
				return 5;
			}
			public String toString() {
				return "+";
			}
		};
		/** 算術演算子：差 */
		private static final Term TERM_OPR_SUB = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(d2 - d1), operations);
			}
			public void convHandle(String token, Expression rp, Stack operations) {
				if (rp.isTermIsVariable()) {
					super.convHandle(token, rp, operations);
				} else {
					rp.push(TERM_OPR_MUL, operations);
					rp.push(new TermDouble(-1), operations);
					//	                rp.send(new TermDouble(-1));
					//	                rp.send(MultiplyOperetor.getInstance());
					rp.setTermIsVariable(false);
				}
			}
			public int getPriority() {
				return 5;
			}
			public String toString() {
				return "-";
			}
		};
		/** 論理演算子：否定 */
		private static final Term TERM_OPR_NOT = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				boolean b1 = ((AbstractValiable) rp.pop(operations)).booleanValue();
				rp.push(!b1 ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public void convHandle(String token, Expression rp, Stack operations) {
				super.convHandle(token, rp, operations);
			}
			public int getPriority() {
				return 2;
			}
			public String toString() {
				return "!";
			}
		};
		/** 論理演算子：< */
		private static final Term TERM_OPR_LT = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push((d2 < d1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 7;
			}
			public String toString() {
				return "<";
			}
		};
		/** 論理演算子：<= */
		private static final Term TERM_OPR_LE = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push((d2 <= d1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 7;
			}
			public String toString() {
				return "<=";
			}
		};
		/** 論理演算子：> */
		private static final Term TERM_OPR_GT = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push((d2 > d1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 7;
			}
			public String toString() {
				return ">";
			}
		};
		/** 論理演算子：>= */
		private static final Term TERM_OPR_GE = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push((d2 >= d1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 7;
			}
			public String toString() {
				return ">=";
			}
		};
		/** 論理演算子：== */
		private static final Term TERM_OPR_EQ = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push((d2 == d1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 8;
			}
			public String toString() {
				return "==";
			}
		};
		/** 論理演算子：!= */
		private static final Term TERM_OPR_NE = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				double d2 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push((d2 != d1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 8;
			}
			public String toString() {
				return "!=";
			}
		};
		/** 論理演算子：&& */
		private static final Term TERM_OPR_AND = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				boolean b1 = ((AbstractValiable) rp.pop(operations)).booleanValue();
				boolean b2 = ((AbstractValiable) rp.pop(operations)).booleanValue();
				rp.push((b2 && b1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 12;
			}
			public String toString() {
				return "&&";
			}
		};
		/** 論理演算子：|| */
		private static final Term TERM_OPR_OR = new AbstractOperator() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				boolean b1 = ((AbstractValiable) rp.pop(operations)).booleanValue();
				boolean b2 = ((AbstractValiable) rp.pop(operations)).booleanValue();
				rp.push((b2 || b1) ? TermFactory.TERM_TRUE : TermFactory.TERM_FALSE, operations);
			}
			public int getPriority() {
				return 13;
			}
			public String toString() {
				return "||";
			}
		};
		/** 算術関数：ABS */
		private static final Term TERM_FUN_ABS = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.abs(d1)), operations);
			}
			public String toString() {
				return "abs";
			}
		};
		/** 算術関数：SIN */
		private static final Term TERM_FUN_SIN = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.sin(d1)), operations);
			}
			public String toString() {
				return "sin";
			}
		};
		/** 算術関数：COS */
		private static final Term TERM_FUN_COS = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.cos(d1)), operations);
			}
			public String toString() {
				return "cos";
			}
		};
		/** 算術関数：TAN */
		private static final Term TERM_FUN_TAN = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.tan(d1)), operations);
			}
			public String toString() {
				return "tan";
			}
		};
		/** 算術関数：ASIN */
		private static final Term TERM_FUN_ASIN = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.asin(d1)), operations);
			}
			public String toString() {
				return "asin";
			}
		};
		/** 算術関数：ACOS */
		private static final Term TERM_FUN_ACOS = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.acos(d1)), operations);
			}
			public String toString() {
				return "acos";
			}
		};
		/** 算術関数：ATAN*/
		private static final Term TERM_FUN_ATAN = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.atan(d1)), operations);
			}
			public String toString() {
				return "atan";
			}
		};
		/** 算術関数：SQRT */
		private static final Term TERM_FUN_SQRT = new AbstractFunction() {
			public void calcHandle(Expression rp, Stack operations) throws WifeException {
				double d1 = ((AbstractValiable) rp.pop(operations)).doubleValue();
				rp.push(new TermDouble(Math.sqrt(d1)), operations);
			}
			public String toString() {
				return "sqrt";
			}
		};

		static {
			opes = new HashMap();
			// 制御定数
			opes.put(TERM_END.toString(), TERM_END);
			opes.put(TERM_BRA.toString(), TERM_BRA);
			opes.put(TERM_CKET.toString(), TERM_CKET);
			// 定数
			opes.put(TERM_TRUE.toString(), TERM_TRUE);
			opes.put(TERM_FALSE.toString(), TERM_FALSE);
			opes.put(TERM_PI.toString(), TERM_PI);
			// 算術演算子
			opes.put(TERM_OPR_POW.toString(), TERM_OPR_POW);
			opes.put(TERM_OPR_MUL.toString(), TERM_OPR_MUL);
			opes.put(TERM_OPR_DIV.toString(), TERM_OPR_DIV);
			opes.put(TERM_OPR_ADD.toString(), TERM_OPR_ADD);
			opes.put(TERM_OPR_SUB.toString(), TERM_OPR_SUB);
			// 論理演算子
			opes.put(TERM_OPR_NOT.toString(), TERM_OPR_NOT);
			opes.put(TERM_OPR_LT.toString(), TERM_OPR_LT);
			opes.put(TERM_OPR_LE.toString(), TERM_OPR_LE);
			opes.put(TERM_OPR_GT.toString(), TERM_OPR_GT);
			opes.put(TERM_OPR_GE.toString(), TERM_OPR_GE);
			opes.put(TERM_OPR_EQ.toString(), TERM_OPR_EQ);
			opes.put(TERM_OPR_NE.toString(), TERM_OPR_NE);
			opes.put(TERM_OPR_AND.toString(), TERM_OPR_AND);
			opes.put(TERM_OPR_OR.toString(), TERM_OPR_OR);
			// 算術関数
			opes.put(TERM_FUN_ABS.toString(), TERM_FUN_ABS);
			opes.put(TERM_FUN_SIN.toString(), TERM_FUN_SIN);
			opes.put(TERM_FUN_COS.toString(), TERM_FUN_COS);
			opes.put(TERM_FUN_TAN.toString(), TERM_FUN_TAN);
			opes.put(TERM_FUN_ASIN.toString(), TERM_FUN_ASIN);
			opes.put(TERM_FUN_ACOS.toString(), TERM_FUN_ACOS);
			opes.put(TERM_FUN_ATAN.toString(), TERM_FUN_ATAN);
			opes.put(TERM_FUN_SQRT.toString(), TERM_FUN_SQRT);
		}

		private TermFactory() {}

		/**
		 * 定義済み項目を検索します
		 * @param token
		 * @return
		 */
		public static Term getOperator(String token) {
			return (Term) TermFactory.opes.get(token);
		}
		/**
		 * 定義済み項目を検索し、無ければ新たにオブジェクトを生成します
		 * 先頭が数字ならばdoubleとして生成し、それ以外は変数として生成します。
		 * @param token
		 * @param
		 * @return
		 */
		public static Term createTerm(String token, boolean isEnableInitialMode, Stack operations) {
			Term state = getOperator(token.toLowerCase());
			if (state == null) {
				if (token.charAt(0) >= '0' && token.charAt(0) <= '9')
					return new TermDouble(Double.parseDouble(token));
				else
					return new TermValiable(token, isEnableInitialMode);
			}
			return state;
		}
	}
	/**
	 * 数式をトークンに分割するクラス
	 * @version 1.0
	 * @author Youhei Horikawa <hori@users.sourceforge.jp>
	 */
	private class ExpressionTokenizer {
		private String expression;
		private int nextPos;
		/**
		 * コンストラクタ
		 * @param expression
		 */
		public ExpressionTokenizer(String expression) {
			this.expression = expression;
			nextPos = 0;
		}
		/**
		 * トークンが取得可能かどうか検査します
		 * @return
		 */
		public boolean hasMoreTokens() {
			char ch;
			do {
				if (nextPos >= expression.length())
					return false;
				ch = expression.charAt(nextPos++);
			} while (isGap(ch));
			nextPos--;
			return true;
		}
		/**
		 * トークンを取得します
		 * @return
		 */
		public String nextToken() {
			char ch;
			// 先頭の空白を読み飛ばし
			do {
				if (nextPos >= expression.length())
					return null;
				ch = expression.charAt(nextPos++);
			} while (isGap(ch));
			StringBuffer token = new StringBuffer();
			if (isLeterOrNo(ch)) {
				// 英数字
				do {
					token.append(ch);
					if (nextPos >= expression.length())
						return token.toString();
					ch = expression.charAt(nextPos++);
				} while (isLeterOrNo(ch));
			} else if (isBracket(ch)) {
				// 括弧
				token.append(ch);
				nextPos++;
			} else {
				// 記号（空白か英数字か括弧まで）
				do {
					token.append(ch);
					if (nextPos >= expression.length())
						return token.toString();
					ch = expression.charAt(nextPos++);
				} while (!isGap(ch) && !isLeterOrNo(ch) && !isBracket(ch));
				// ファクトリに登録済みのオペレーションでなければ、１文字にする
				while (1 < token.length() && TermFactory.getOperator(token.toString()) == null) {
					token.deleteCharAt(token.length() - 1);
					nextPos--;
				}
			}
			nextPos--; // 次回読込み位置
			return token.toString();
		}
		/**
		 * chが括弧かどうか検査します
		 * @param ch
		 * @return
		 */
		private boolean isBracket(char ch) {
			return (0 <= "()".indexOf(ch));
		}
		/**
		 * chが区切りかどうか検査します
		 * @param ch
		 * @return
		 */
		private boolean isGap(char ch) {
			return (0 <= " \t\r\f\n,".indexOf(ch));
		}
		/**
		 * chが英数字かどうか検査します
		 * @param ch
		 * @return
		 */
		private boolean isLeterOrNo(char ch) {
			if (('a' <= ch && ch <= 'z')
				|| ('A' <= ch && ch <= 'Z')
				|| ('0' <= ch && ch <= '9')
				|| ch == '_'
				|| ch == '.') {
				return true;
			}
			return false;
		}
	}
}
