/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
//機能名称 
//			 CMI データモデル　ノードクラス
//	変更履歴
//				2003.11.26	lcg  新規作成		
//
package jp.co.ntt.lms.lo.scorm.cbtcom;

import java.util.NoSuchElementException;
import java.util.Vector;
import java.util.Iterator;
//import java.util.StringTokenizer;

/**
 * CMI データモデル　基底要素クラス
 * @author lcg
 */
public class CMINode extends CMIElement {
	
	/**
	 * 値バッファ
	 */
	protected CMIValueBuffer m_value = null;
   
	/**
	 * 子エレメントベクタ
	 */
	protected Vector m_children = null;
   
	/**
	 * カレント
	 */
	protected int m_cur;
   
	protected String m_childrenStr = null;
   
	/**
     * CMINode クラスの初期処理<br>
     * @param proto プロトタイプ・データ
     */
	public CMINode(CMIElementProto proto) {
		super(proto);
		m_children = new Vector();
		m_value = new CMIValueBuffer();
		initialize();
   }
   
	/**
     * CMINode クラスの初期処理<br>
     */
	public CMINode() {
		m_children = new Vector();
		m_value = new CMIValueBuffer();
	}
 
	/**
	 * クラスの終了処理 <BR>
	 */
	public void finalize() {
		m_childrenStr = null;
	}
	   
	/**
     * 子エレメントを追加する<br>
     * @param child 子エレメント
     */
	public void addChild(CMIElement child) {
		m_children.add( child );
		child.setParent(this);
		child.incrementLinkCount();
   }
   
	/**
     * 子エレメントを追加する<br>
     * @param child 子エレメント
     */
	public void addChildLink(CMIElement child) {
		m_children.add( child );
		child.incrementLinkCount();
	}
   
	/**
     * プロトデータを基に子供のインスタンスを作成する<br>
     * @param proto プロトデータ
     */
	public void makeChildren(CMIElementProto proto) {
		if ( proto == null ) {
   			return;
   		}
	    Vector vtrTable = proto.getMemberTable();
	    if ( vtrTable == null ) {
	    	return;
	    }
	    Iterator iterator = vtrTable.iterator();
	    while ( iterator.hasNext() ) {
	 		CMIElementProto memberProto = (CMIElementProto)iterator.next();
			CMIUtil.makeInstance(memberProto, this);
	    }
		m_proto = proto;
	}
   
	/**
     * プロトデータを基に子供のインスタンスを作成する。<br>
     * @param proto CMIElementProto プロトデータ
     */
	public void makeGlobalChildren(CMIElementProto proto) {
		if ( proto == null ) {
			return;
		}
		Vector vtrTable = proto.getMemberTable();
		if ( vtrTable == null ) {
			return;
		}
		Iterator iterator = vtrTable.iterator(); 
		while ( iterator.hasNext() ) {
			CMIElementProto memberProto = (CMIElementProto)iterator.next();
			CMIUtil.makeGlobalInstance(memberProto, this);
		}
		m_proto = proto;
	}
   
	/**
     * 子エレメントを削除する。<br>
     */
	public void deleteChild() {
	 	// リストクリア
		m_children.clear();
	}
   
	/**
     * 子エレメントを取得する。<br>
     * @param index 子エレメントのインデックス
     */
	public CMIElement getChild(int index) {
		CMIElement child = null;
		if ( m_children == null ) {
			return null;
		}
		if ( index < m_children.size() ) {
			child = (CMIElement)m_children.get( index );
		}
		return child;
	}
   
	/**
     * 子エレメントを取得する。<br>
     * @param name 子エレメントの名前
     */
	public CMIElement getChild(String name) {
	   	if ( m_children.size() == 0 || null == name || "".equals( name )) {
	   		return null;
	   	}
		CMIElement child = null;
		
		Iterator iterator = m_children.iterator();
		while ( iterator.hasNext() ){
			CMIElement  childTmp = ( CMIElement )iterator.next();
			String strName = childTmp.getName();
			if ( name.equals( strName ) ) {
				child = childTmp;
				break;
			}
		}
	    return child;
	}
   
	/**
     * 子エレメントを取得する。<br>
     * @param name 子エレメントの名前
     */
	public CMIElement getNChild(String name) {
	   	if ( null == name || "".equals(name) ){
	   		return null;
	   	}
		CMIParameterPath param = new CMIParameterPath(name);
		String strChildName = param.popFirstElement();
		CMIElement child = null;
		Iterator iterator = m_children.iterator();
		while ( iterator.hasNext() ) {
			CMIElement node = ( CMIElement ) iterator.next();
			String strName = node.getName();
			if ( strChildName.equals( strName ) ) {
				String strPath = param.getPath();
				if ( null == strPath || "".equals( strPath )) {
					child = node;
				} else {
					child = ((CMINode)node).getNChild( strPath );
				}
				break;
			}	
		}
		return child;
	}
   
	/**
	 * 子エレメント数を取得する。<br>
	 * @return int 子エレメント数
	 */
	public int getChildCount() {
	   	return m_children.size();
	}
   
	/**
	 * キーワードで子エレメントを取得する。<br>
	 * @param keyWord String キーワード
	 * @return CMIElement 子エレメント
	 */
	public CMIElement getChildByKeyWord(String keyWord) {
	    if ( null == keyWord || "".equals( keyWord ) ) {
	    	return null;
	    }
		CMIElement child = null;
	    Iterator iterator = m_children.iterator();
		keyWord = keyWord.toLowerCase();
	    while ( iterator.hasNext() ) {
			CMIElement element = (CMIElement)iterator.next();
			String strKeyWord = element.getKeyWord();
			strKeyWord = strKeyWord.toLowerCase();
			if ( keyWord.equals( strKeyWord )  ) {
				child = element;
				break;
			}
	    }
	    return child;
	}
   
	/**
	 * 子エレメントの名称リストを取得する。<br>
	 * @return String 子エレメント数
	 */
	public String getChildList() {
   	
		CMIElement child = null;
		
		StringBuffer nameList = new StringBuffer();
		
		//子エレメントの名称
		String strChildName = null;
		
		//データモデル名
		String strNodeName = getName();
		
		//バージョン情報
		int intVersion = getVersion();
		
		//nameListへの値追加フラグ
		boolean blnAddListFlag = false;

		boolean blnNumber = CMIUtil.isNumber( strNodeName );
		
		// ノード名が n の場合、親エレメントの名前を取得する
		if ( blnNumber ) {
			strNodeName = m_parent.getName();
		}
		Iterator iterator = m_children.iterator();
		while ( iterator.hasNext() ) {
			blnAddListFlag = true;
			child = ( CMIElement ) iterator.next();
			strChildName = child.getName();
			//データモデルがcmi.objectives.n の場合
			if ( "objectives".equals( strNodeName ) ) {
				//バージョンが3.4以降であれば、cmi.objectives.n.attempts
				// データモデルは存在しない
				if ( intVersion >= 3400 ) {
					if ( "attempts".equals( strChildName ) ) {
						blnAddListFlag = false;
					}
				}
				// バージョンが3.4以前であれば、cmi.objectives.n.score
				// cmi.objectives.n.status の各データモデルは存在しない
				else {
					if ( "score".equals( strChildName ) || "status".equals( strChildName ) ) {
						blnAddListFlag = false;
					}
				}
			}
			//データモデルが cmi.evaluation の場合
			else if ("evaluation".equals( strNodeName ) ) {
			// バージョン3.4以前は、cmi.evaluation.[lesson_id, date] が
			// 存在しなかったので、nameListに追加しない
				if ( intVersion < 3400 ) {
					if ( "lesson_id".equals( strNodeName ) 
 						|| "date".equals( strNodeName ) ) {
						blnAddListFlag = false;
	 				}
 				}
			 }
			if ( blnAddListFlag ) {
				if ( nameList.length() > 0 ) {
					nameList.append( "," );
				}
				nameList.append( strChildName );
			}
		}
    	return nameList.toString();
	}
   
	/**
	 * 先頭の子エレメントを取得する。<br>
	 * @return CMIElement 先頭の子エレメント数
	 */
	public CMIElement getTopChild() {
		CMIElement child = null;
		m_cur = m_children.size();
		if ( 0 < m_cur ) {
			child = ( CMIElement ) m_children.get( 0 ); 
		}
		return child;
	}
   
	/**
	 * 最後の子エレメントを取得する。<br>
	 * @return CMIElement 最後の子エレメント数
	 */
	public CMIElement getLastChild() {
		CMIElement child = null;
		m_cur = m_children.size();
		if ( m_cur > 0 ) {
			child = ( CMIElement ) m_children.get( m_cur - 1 ); 
		}
		return child;
	}
   
	/**
	 * 前の子エレメントを取得する。<br>
	 * @return CMIElement 前の子エレメント
	 */
	public CMIElement getPrevChild() {
		CMIElement child = null;

		if ( 0 < m_cur-1 && m_cur-1 <= m_children.size() ) {
			m_cur--;
			child = ( CMIElement )m_children.get( m_cur-1 );
		} else {
			m_cur = 0;
		}
		return child;
	}
   
	/**
	 * 次の子エレメントを取得する。<br>
	 * @return CMIElement 次の子エレメント
 	 */
	public CMIElement getNextChild() {
		CMIElement child = null;
	
		if ( 0 < m_cur+1 && m_cur+1 <= m_children.size() ) {
			m_cur++;
			child = ( CMIElement )m_children.get( m_cur - 1 );
		}
		else {
			m_cur = 0;
		}
		return child;
	}
   
	/**
	 * 子エレメントのシリアライズを実行し、自シリアライズを生成する。<br>
	 * @param buf StringBuffer シリアライズデータ
     */
	protected void serializeChildren(StringBuffer buf) {
		
		boolean blnFirstTime = true;
		CMIElement child = null;
		Iterator iterator = m_children.iterator();
		
		while ( iterator.hasNext() ) {
			child = ( CMIElement )iterator.next();
			if ( child != null ) {
				if ( child.isSerializable() ) {
					if ( blnFirstTime ) {
						blnFirstTime = false;
					} else {
						buf.append( "&" );
					}
					child.serialize(buf);
				} else {
					continue;
				}
			} else {
				//program error;
			}
		}
	}
   
	/**
	 * 括弧のネストを考慮して値を取り出す。<br>
	 * @param inString String 入力文字列   名前=値&名前=値&...
	 * @param head int 値の先頭位置
	 * @param value StringBuffer 取り出した値
	 * @return int ロケーション
	 */
   	protected int getNestedValue(String inString, int head, StringBuffer value) {
		int intTail = 0;
		
		String strIn = inString;
		int intEnd = strIn.length();
		String strValue = null;
		value.delete(0,value.length());
		try {		
			if ( strIn.charAt(head) != '(') {
				intTail = strIn.indexOf('&', head);
				if ( -1 == intTail ) {
					//head以降を取り出す。
					strValue = inString.substring(head);	
					head = intTail;
				} else {// inString[intTail] == '&'
					strValue = inString.substring(head, intTail );
					head = intTail + 1;
					if ( inString.length() <= head ) {
						head = -1;
					}
				}
			} else {
				int intDepth = 1;	// 括弧の深さ
				intTail = head;
				while (true) {
				int intLeft = strIn.indexOf("(", intTail + 1);
				int intRight = strIn.indexOf(")", intTail + 1);
				if( intLeft != -1) {
					if(intRight != -1) {
						intTail = (intLeft < intRight) ? intLeft : intRight;
					}else{
						intTail = intLeft;
					}
				}else{
					if(intRight == -1) {
						intTail = -1;
					}else{
						intTail = intRight;
					}
				}

				if ( intTail == -1 ) {
					// error
					String strPath = null;
					strPath = getPath();
					value.append("CMINode.getNestedValue: Unexpected end of data");
					value.append(strPath);
					throw new Exception("UnexpectedData");
				} else if ( strIn.charAt(intTail) == '(' ) {
					intDepth++;
				} else if ( strIn.charAt(intTail) == ')' ) {
					intDepth--;
					if (intDepth == 0) {
						break;
					}
				}
			}
			// inString[head] == '('
			// inString[intTail] == ')'
			head++;
			strValue = strIn.substring(head, intTail );
			head = intTail + 1;
			if ( head < strIn.length() ) {
				if ( strIn.charAt(head) == '&') {
					head++;
				}
			}
			if ( head >= strIn.length() ) {
				head = -1;
			}
		} 
		}catch (Exception Ex){
			if("UnexpectedData".equals(Ex.getMessage())) {
				setError(CMIError.ERR_PROGRAM_ERROR);
				setVendorError(getVendorData("CMINode.getNestedValue", this));
				head = -1;
			}
		}
		value.append(strValue);
		return head;
	}
   
	/**
	 * ローカル値を設定する。<br>
	 * @param name String 名前
	 * @param value String 設定値
	 * @param doCheck boolean チェックフラグ
	 */
	public void localSetValue(String name, String value, boolean doCheck) {
		CMIParameterPath param = new CMIParameterPath( name );
		
		String strTheName = param.popFirstElement();
		
		String strNodeName = getName();

		// バージョン情報の取得
		int intVersion = getVersion();

		if ( strTheName.equals( strNodeName ) ) {
			
			// 該当ノードの場合
			String strChildName = param.getNthElement(1);
			
			if ( strChildName == null || "".equals(strChildName) ) {
				// パス指定が空の場合
				if  ( isWritable( ) ) {
					if ( 3400 <= intVersion ) {
						// 製品では、規格にあるデータ型チェックを行わない。規格準拠を緩める。
						//LocalValue に値をセットする
						m_value.setLocalValue(value);	
						//NULL フラグを偽にする
						m_value.setLocalIsNull(false);
						//setValue による設定フラグを真にする
						m_bySetValue	= true;
					}
					// バージョンが3.4以前の場合は、データ型のチェックを行わない
					else {
						//LocalValue に値をセットする
						m_value.setLocalValue(value);
						//NULL フラグを偽にする
						m_value.setLocalIsNull(false);
						//setValue による設定フラグを真にする
						m_bySetValue	= true;
					}
				} else {
					// 書き込み許可なし

					// バージョン情報によりエラー情報を変更する
					// バージョン情報が3.4以降の場合
					if ( 3400 <= intVersion ) {
						// エレメントがキーワードかチェック
						if ( checkParamKeyword( strTheName ) ) {
							// エラー：エレメントはキーワード
							setError( CMIError.ERR_INVALID_SETVALUE_CMI_KEYWORD);
						} else {
							// エラー ： 読み込み専用のエレメントに値をセットしようとした
							setError( CMIError.ERR_ELEMENT_IS_READ_ONLY );
						}
					}
					// バージョン情報が3.4以前の場合
					else {
						// エラー(CMI) 引数エラー(理由：書き込み許可なし)
						setError(CMIError.ERR_INVALID_AURGUMENT_ERROR);
					}
					setVendorError(getVendorData("CMINode.localSetValue1", this));
				}
			} else {
				// パス指定が残っている場合
				CMIElement child = getChild( strChildName );

				if ( child != null ) {
					// パス指定の子エレメントがある場合
					//子のsetValueをコールする
					child.localSetValue(param.getPath(), value, doCheck);
				} else {
					// 子エレメントのパス指定が "_children" "_count" "_version"
					// いずれかである場合
					if ( "_children".equals(strChildName) || "_count".equals(strChildName) ||
					   "_version".equals(strChildName)) {
						// エラーコードは拡張して使用する
						// 規格上のエラーコードについては、あくまでAPIの規格である
						setError( CMIError.ERR_ELEMENT_IS_READ_ONLY );
					} else {
						// パス指定の子エレメントがない場合
						// エラー(CMI) 引数エラー(理由：無効パスを指定した)
						setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
					}
					setVendorError( getVendorData( "CMINode.localSetValue2", this ) );
				}
			}
		} else {
			// 自エレメント名が指定されていない場合
			// エラー(CMI) 引数エラー(理由：無効パスを指定した)
			setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
			setVendorError( getVendorData("CMINode.localSetValue3", this) );
		}
	}
   
	/**
	 * ローカル値を設定する。<br>
	 * @param name String パス名
	 * @param value String 設定値
	 */
	public void localSetValue(String name, String value) {
		localSetValue( name, value, true );
	}
   
	/**
	 * ローカル値を取得する。<br>
	 * @param name String パス名
	 * @return String 取得データ
	 */
	public String localGetValue(String name) {
		return localGetValue( name, true );
	}
   
	/**
	 * ローカル値を取得する。<br>
	 * @param name String パス名
	 * @param doCheck boolean チェックフラグ
	 * @return String 取得データ
	 */
	public String localGetValue(String name, boolean doCheck) {
   	
		String strRet = null;
		CMIParameterPath param = new CMIParameterPath( name );
		String strTheName = param.popFirstElement();
		String strNodeName = getName();
		
		if ( strTheName.equals( strNodeName ) ) {
			
			String strChildName = param.getNthElement(1);
			if  ( strChildName == null || "".equals(strChildName) ) {
				if ( isReadable() ) {
					// 読み込み許可ありの場合
					if ( isSession() ) {
						// セッションの場合
						if ( !m_value.getLessonIsNull() ) {
							//LessonValue を返す
							strRet = m_value.getLessonValue();
						}
					} else {
						// 固定の場合
						if ( !m_value.getLessonIsNull() ) {
							//LessonValue を返す
							strRet = m_value.getLessonValue();
						} else {
							if ( !m_value.getLocalIsNull() ) {
								//LocalValue を返す
								strRet = m_value.getLocalValue();
							}
						}
					}
				} else {
					// 読み込み許可なしの場合

					// バージョン情報の取得
					int intVersion = getVersion();

					// バージョン情報によりエラー情報を変更する
				
					// バージョン情報が3.4 以降の場合
					if ( 3400 <= intVersion ) {
						// エラー ： 書込みのみエラー
						setError(CMIError.ERR_ELEMENT_IS_WRITE_ONLY);
					}
					// バージョン情報が3.4以前の場合
					else {
						setError(CMIError.ERR_INVALID_AURGUMENT_ERROR);
					}
					setVendorError(getVendorData( "CMINode.localGetValue", this));
				}
			}
			else {
				if ( "_children".equals( strChildName ) ) {
					if ( m_parent != null && !m_parent.isArray() ) {
						// 親が配列を持たない場合
						m_childrenStr = getChildList();
						strRet = m_childrenStr;
					} else {
						// 親が配列を持つ場合
						setError(CMIError.ERR_INVALID_AURGUMENT_ERROR);
						setVendorError(getVendorData( "CMINode.localGetValue", this ) );
					}
				} else if ( "_version".equals( strChildName ) ) {
					// パスチェック
					String strPath = null;
					strPath = getPath(  );
					if ( ("cmi.core").equals( strPath ) ) {
						strRet = m_CBT.getVersionStr();
					} else {
						setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
						setVendorError( getVendorData("CMINode.localGetValue", this ) );
					}
				} else if ( "_count".equals( strChildName ) ) {
					setError( CMIError.ERR_ELEMENT_NOT_AN_ARRAY );
					setVendorError( getVendorData( "CMINode.localGetValue" , this ) );
				} else {  // 通常の値
					CMIElement child = getChild(strChildName);
					if ( child != null ) {
						strRet = child.localGetValue(param.getPath(), doCheck);
					} else {
						setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
						setVendorError(getVendorData( "CMINode.localGetValue", this ) );
					}
				}
			}
		}
		else {
			// パス指定の誤り
			setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
			setVendorError(getVendorData( "CMINode.localGetValue", this ) );
		}
		return strRet;
   }
   
	/**
     * localValue の値を設定する。<br>
     * @param name String パス名
     * @param value String 値
     */
	public void setLocalValue(String name, String value) {
	
		if ( null == name || "".equals(name)) {
			if ( value != null ) {
				m_value.setLocalValue(value);
				m_value.setLocalIsNull(false);
			}
		} else {
			CMIParameterPath param = new CMIParameterPath( name );
			String strChildName = param.popFirstElement(  );
			CMIElement child = getChild( strChildName );
			
			if ( child != null ) {
				child.setLocalValue( param.getPath(), value);
			} else {
				setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
				setVendorError( getVendorData( "CMINode.setLocalValue", this));
			}
		}
	}
   
	/**
	 * localValue の値を設定する。<br>
	 * @param value String 設定値
	 */
	public void setLocalValue( String value ) {
		m_value.setLocalValue(value);
		m_value.setLocalIsNull(false);
	}
   
	/**
	 * localValue の値を取得する。<br>
	 * @param name String パス名
	 * @return String localValue 値
	 */
	public String getLocalValue ( String name ) {
		String strValue = null;
		String strName = null;
		if ( name == null || "".equals(name) ) {
			strValue = m_value.getLocalValue();
		} else {
			CMIParameterPath param = new CMIParameterPath( name );
			String strChildName = param.popFirstElement();
			CMIElement child = getChild( strChildName );
			if ( child != null ) {
				strValue = child.getLocalValue( param.getPath() );
			} else {
				setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
				setVendorError( getVendorData( new String ( "CMINode.getLocalValue" ), this ) );
			}
		}

		return strValue;
	}
   
	/**
	 * localValue の値を取得する。<br>
	 * @return String localValue 値
	 */
	public String getLocalValue() {
   		return m_value.getLocalValue();
	}
   
	/**
	 * localValue の値がnullかどうか判断する<br>
	 * @return boolean 戻り値
	 */
	public boolean getIsNullValue(){
		return m_value.getLocalIsNull();
	}

	/**
	 * lessonValue の値を設定する。<br>
	 * @param value String 設定値
	 */
	public void setLessonValue(String value) {
		m_value.setLessonValue( value );
		m_value.setLessonIsNull( false );
	}
   
	/**
	 * lessonValue の値を設定する。<br>
	 * @param name String パス名
	 * @param value String 値
	 */
	public void setLessonValue(String name, String value) {
		if ( name == null || "".equals(name) ) {
			m_value.setLessonValue( value );
			m_value.setLessonIsNull( false );
		} else {
			CMIParameterPath param = new CMIParameterPath(name);
			String strChildName = param.popFirstElement();
			CMIElement child = getChild( strChildName );
	
			if ( child != null ) {
				child.setLessonValue(param.getPath(), value);
			} else {
				setError(CMIError.ERR_INVALID_AURGUMENT_ERROR);
				setVendorError(getVendorData("CMINode.setLocalValue", this));
			}
		}
	}
   
	/**
	 * lessonValue の値を取得する。<br>
	 * @return String localValue 値
	 */
	public String getLessonValue() {
		return m_value.getLessonValue();
	}
   
	/**
	 * lessonValue の値を取得する。<br>
	 * @param name パス名
	 * @return String localValue 値
	 */
	public String getLessonValue(String name) {
		String strValue = null;
		if ( null == name || "".equals(name) ) {
			strValue = m_value.getLessonValue();
		} else {
			CMIParameterPath param = new CMIParameterPath(name);
			String strChildName = param.popFirstElement();
			CMIElement child = getChild(strChildName);
	
			if ( child != null ) {
				strValue = child.getLessonValue(param.getPath());
			} else {
				setError(CMIError.ERR_INVALID_AURGUMENT_ERROR);
				setVendorError(getVendorData("CMINode.getLessonValue", this));
			}
		}
		return strValue;
	}
   
	/**
	 * localValue の値を初期化する。<br>
	 */
	public void initLocalValue() {
		m_value.setLocalValue("");
		m_value.setLocalIsNull(true);
	}
   
	/**
	 * localValue の値を初期化する。<br>
	 * @param value String localValue 値
	 */
	public void initLocalValue(String value) {
		if ( value == null || "".equals(value) ) {
			m_value.setLocalValue("");
			m_value.setLocalIsNull(true);
		} else {
			CMIParameterPath param = new CMIParameterPath(value);
			String strChildName = param.popFirstElement();
			CMIElement child = getChild( strChildName );
			if ( child != null ) {
				child.initLocalValue( param.getPath() );
			} else {
				setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
				setVendorError(getVendorData("CMINode.initLocalValue", this));
			}
		}
	}
	
	/**
	 * lessonValue の値を初期化する。<br>
	 * @param value String localValue 値
	 */
	public void initLessonValue(String value) {
		if ( null == value || "".equals(value) ) {
			m_value.setLessonValue("");
			m_value.setLessonIsNull(true);
		} else {
			CMIParameterPath param = new CMIParameterPath(value);
			String strChildName = param.popFirstElement();
			CMIElement child = getChild(strChildName);

			if ( child != null ) {
				child.initLessonValue(param.getPath());
			} else {
				setError(CMIError.ERR_INVALID_AURGUMENT_ERROR);
				setVendorError(getVendorData("CMINode.initLessonValue", this));
			}
		}
	}
	
	/**
	 * lessonValue の値を初期化する。<br>
	 */
	public void initLessonValue() {
		m_value.setLessonValue("");
		m_value.setLessonIsNull(true);
	}
   
	/**
	 * 必須入力項目のチェックを行う。<br>
	 * @return boolean 必須入力の状態
	 */
	public boolean checkMandatory() {
   	
		if ( isMandatory() ) {
			// 入力必須の場合
			if ( !m_bySetValue && m_value.getLocalIsNull() ) {
				// エラー
				setError( CMIError.ERR_INVALID_AURGUMENT_ERROR );
				setVendorError( getVendorData( "CMINode.initLessonValue", this ) );
				return false;
			}
		}
	
		int intChildCount = getChildCount();
		for ( int i = 0;  i < intChildCount; i++ ) {
			CMIElement child = getChild( i );
			if ( child != null ) {
				if ( !child.checkMandatory() ) {
					return false;
				}
			}
		}
		return true;
	}
   
	/**
	 * デフォルト値を設定する。<br>
	 */
	public void setDefaultValue() {
   	
		if ( m_proto.getDefaultData() != null ) {
			m_value.setLocalValue(m_proto.getDefaultData());
			m_value.setLocalIsNull(false);
			//setValue による設定フラグを真にする
			m_bySetValue	= true;
		}
	
		int intChildCount = getChildCount();
		for ( int i = 0; i < intChildCount; i++ ) {
			CMIElement child = getChild( i );
			if ( child != null ) {
				child.setDefaultValue();
			}
		}
	}
   
	/**
	 * セッション初期化の前処理を行う。<br>
	 */
	public void before_initialize() {
   		
		IBeforeInitializer beforeInitializer = m_proto.getBeforeInitializer();
		if ( beforeInitializer != null ) {
			//before_initializer メソッドが登録されている場合
			//メソッドをコールする
			beforeInitializer.before_Initializer(this);
		} else {
			// before_initializer メソッドが登録されていない場合
			if ( isSession() ) {
				// セッションタイプの処理
				if ( !m_bySetValue ) {
					// setValue による更新なし
					// LessonValue の値をLocalValue にコピーする
					if ( !m_value.getLessonIsNull() ) {
						m_value.setLocalValue( m_value.getLessonValue() );
					}
				} else {
					// setValue による更新あり
					//setValue による更新フラグを偽にする
					m_bySetValue = false;
				}
			} else {
				// セッションタイプ以外(固定タイプ)の処理
				// 無処理
			}

			//子エレメント全ての初期化前処理をコールする
			//子エレメント数を取得する
			int intChildCount = m_children.size();
			CMIElement child = null;
			for ( int i = 0;  i < intChildCount; i++ ) {
				child = (CMIElement)m_children.get(i);
				child.before_initialize();
			}
		}
	}
   
	/**
     * セッション初期化処理を行う。<br>
     */
	public void initialize() {
		IInitializer initializer = m_proto.getInitializer();
		if ( initializer != null ) {
			//initializer メソッドが登録されている場合
			//メソッドをコールする
			initializer.initializer(this);
		} else {
			// initializer メソッドが登録されていない場合
			if ( isSession() ) {
				// セッションタイプの処理
				// 無処理
			} else {
				// セッションタイプ以外(固定タイプ)の処理
				// 無処理
			}

			// 子エレメント全ての初期化処理をコールする
			int intChildCount = m_children.size();
			CMIElement child = null;
			for ( int i = 0;  i < intChildCount; i++ ) {
				child = (CMIElement)m_children.get(i);
				child.initialize();
			}
		}
	}
   
	/**
	 * 値からシリアライズデータを生成する。<br>
	 * @param buf StringBuffer シリアライズデータ
	 */
	public void serialize(StringBuffer buf) {
   		if ( buf == null ) {
   			buf = new StringBuffer();
   		}
   		String strName = getName();
   		buf.append(strName);
   		buf.append("=(");
		if ( isSerializable() ) {
			// serializableであれば、ノード自体の値を出力する。
			String strSerializeValue = serializeCMIValue();
			buf.append( strSerializeValue );
			buf.append(";");
		}
		//子エレメントのシリアライズを実行する
		serializeChildren(buf);
		buf.append(  ")" );
	}
   
	/**
	 * シリアライズデータを解凍し、値を設定する。<br>
	 * @param inString String シリアライズデータ
	 */
	public void deserialize(String inString) {
	
		//名前
		String strName = null;
		
		//値
		String strValue = null;
		
		StringBuffer bufValue = new StringBuffer();
		
		String strChildrenValue = null;
			
		//serializableであれば、ノード自体の値を取得設定する。
		if ( isSerializable() ) {
			
			CMITokenizer tokenizer = new CMITokenizer( inString, ";" );


			
			//ノード自体の値を取得する
			String strOwnValue = tokenizer.nextToken();
			
			//子の値を取得する
			int intOwnEnd = inString.indexOf(";");
			if(intOwnEnd == -1) {
				strChildrenValue = "";
			}else{
				strChildrenValue = inString.substring( intOwnEnd+1);
			}
			//ノード自体の値を設定する
			deserializeCMIValue(strOwnValue);
			
		} else {
			//子の値を取得する
			strChildrenValue = inString;
		}
		
		if(strChildrenValue == null || "".equals(strChildrenValue)){
			setError( CMIError.ERR_PROGRAM_ERROR );
			setVendorError( getVendorData(  "CMINode.deserialize" , this ) );
			return;
		}
		//子の値を設定する
		int intHead = 0;
		int intTail = 0;
		while ( intHead != -1 ) {
			// 要素データの名前と値を取り出す。
			intTail = strChildrenValue.indexOf( "=", intHead );
			if ( intTail == -1 ) {
				setError( CMIError.ERR_PROGRAM_ERROR );
				setVendorError( getVendorData(  "CMINode.deserialize" , this ) );
				break;
			} else {
				strName = strChildrenValue.substring( intHead, intTail );
				//'=' の次から取得
				intHead = getNestedValue( strChildrenValue, intTail + 1, bufValue );
			}
			CMIElement child = getChild( strName );
			if ( child != null ) {
				// 下位メンバに指定された名前のインスタンスがあれば、そのsetAllValue(値)を実行する。
				child.deserialize( bufValue.toString() );
			} else {
				// メンバが存在しなければ、エラーとする。
				// error
			}
		}
	}
   
	/**
	 * パラメータを取得する。<br>
	 * @param value StringBuffer 値
	 * @return int エラーコード
	 */
	public int getParamSub(StringBuffer value) {
   		if ( value == null ) {
   			value = new StringBuffer();
   		}
   		
		int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;
		value.append("[");
		String strKeyWord = getKeyWord();
		value.append( strKeyWord );
		value.append( "]" );
		value.append( STR_CRLF );
		
		int intChildCount = getChildCount();
		
		for ( int i = 0; i < intChildCount; i++ ) {
			CMIElement child = getChild( i );
			if ( child != null ) {
				intErrCode = child.getParam( value );
			} else {
				// program error;
			}
		}
		return intErrCode;
	}
   
	/**
	 * PutParamコマンド受信時に受信データを分析し、各データ毎に設定する
	 * 処理を呼び出す。<br>
	 * @param name String パス名
	 * @param inString String 受信データ
	 * @return int エラーコード
	 */
	public int putParamSub(String name, String inString) {
   	
	int intErrCode = HACPError.HACP_ERR_SUCCESSFUL;

	CMITokenizer strTokenizer = new CMITokenizer( inString, CHAR_CRLF);
	CMITokenizer strPairDivider = null;
	
	String strLine = null;
	String strKeyWord = null;
	String strValue = null;
	
	while( strTokenizer.hasMoreTokens()){
		strLine = strTokenizer.nextToken();
		if ( CMIUtil.isComment( strLine ) ) {
			continue;	
		}
		strPairDivider = new CMITokenizer( strLine, "=" );
		strKeyWord =	strPairDivider.nextToken();
		try{
			strValue = strPairDivider.nextToken();
		} catch (NoSuchElementException nseE) {
			strValue = "";
		}		
		
		CMIElement child = getChildByKeyWord( strKeyWord );
		if ( child != null ) {
			child.putParam( strKeyWord, strValue );
		} else {
			intErrCode = HACPError.HACP_ERR_INVALID_COMMAND;
		}
	}
	return intErrCode;
	}
   
	/**
	 * デバッグ(CMIデータ)を取得する。<br>
	 * @return String デバッグ(CMIデータ)
	 */
	public String getDebugCMIData() {
   	
		//パスを取得する。
	   	String strPath = getPath();
		String strVal = null;
		StringBuffer ret = new StringBuffer();
		
		ret.append( strPath );
		ret.append("：(");
		ret.append(String.valueOf(m_LinkCount));
		ret.append(")\n");
		ret.append("    Node  Value=");
		ret.append("[");
		String strSet = m_bySetValue ? " SET ": " --- ";
		ret.append(strSet);
		ret.append("]");
		StringBuffer value = new StringBuffer();
		value.append(m_value.getLocalIsNull() ? "(null)" : "");
		
		value.append("[");
		value.append( m_value.getLocalValue() );
		value.append("]");
		String strValue = value.toString();
		ret.append(value.toString());
		
		for ( int i = 0; i < ( 40 - strValue.length() ); i++ ) {
			ret.append(" ");
		}
		
		StringBuffer lessonValue = new StringBuffer();
		lessonValue.append(" / ");
		strValue = m_value.getLessonIsNull()?"(null)":"";
		lessonValue.append(strValue);
		lessonValue.append("[");
		lessonValue.append(m_value.getLessonValue());
		lessonValue.append("]");
		ret.append(lessonValue.toString());
		ret.append("\n");
	
		Iterator iterator = m_children.iterator();
		while ( iterator.hasNext() ) {
			CMIElement element = ( CMIElement )iterator.next();
			String strChild = element.getDebugCMIData();
			ret.append(strChild);
		}
		return ret.toString();
	}
   
	/**
	 * デバッグ(プロトタイプ)を取得する。<br>
	 * @return String デバッグ(CMIデータ)
	 */
	public String getDebugProto() {
	
		String strPath = null;
		
		//パスを取得する。
		strPath = getPath();	
		
		//末端 判定を取得する。
		String strLeaf = null;
		if ( isLeaf() ){
			strLeaf = "1";
		} else {
			strLeaf = "0";
		}
		
		//配列 判定を取得する。
		String strArray = null;
		if ( isArray( ) ) {
			strArray = "1";
		} else {
			strArray = "0";
		}
		
		//Get 可否判定を取得する。
		String strRead = null;
		if ( isReadable() ) {
			strRead = "1";
		} else {
			strRead = "0";
		}
		
		//Set 可否判定を取得する。
		String strWrite = null;
		if ( isWritable() ) {
			strWrite = "1";
		} else {
			strWrite ="0";
		}
		
		//必須 判定を取得する。
		String strMandatory = null;
		if ( isMandatory() ) {
			strMandatory = "1";
		} else {
			strMandatory ="0";
		}
		
		//シリアライズ判定を取得する。
		String strSerializable = null;
		if ( isSerializable() ){
			strSerializable = "1";
		} else {
			strSerializable = "0";
		}
		
		StringBuffer sbBuffer = new StringBuffer();
		
		sbBuffer.append(strPath);
		sbBuffer.append("：(");
		String strLinkCount = null;
		try {
			strLinkCount = String.valueOf( m_LinkCount );
		} catch(NumberFormatException ex){
			strLinkCount = "";
		}
		sbBuffer.append(strLinkCount);
		sbBuffer.append(")\n");
		sbBuffer.append("    ");
		
		sbBuffer.append( "Node " );
		sbBuffer.append("Leaf="+strLeaf+"/");
		sbBuffer.append("Array="+strArray+"/");
		sbBuffer.append("Readable="+strRead+"/");
		sbBuffer.append("Write="+strWrite+"/");
		sbBuffer.append("Man="+strMandatory+"/");
		sbBuffer.append("Serial="+strSerializable+"\n");
	
		Iterator iterator = m_children.iterator();
		while ( iterator.hasNext() ) {
			CMIElement element = ( CMIElement )iterator.next();
			String strChild = element.getDebugProto();
			sbBuffer.append(strChild);
		}
		return sbBuffer.toString();
	}

	/**
	 * 保持データをXML形式で取得する。<br>
	 * @param buf StringBuffer ログデータ
	 */
	public void serializeXMLLog(StringBuffer buf) {
		if ( buf == null ) {
			buf = new StringBuffer();
		}
		String strName = getName();
		buf.append("<");
		buf.append(strName);
		buf.append(">");
		//子エレメントのシリアライズを実行する
		serializeXMLChildren(buf);
		buf.append("</");
		buf.append(strName);
		buf.append(">");
		buf.append("\n");

	}

	/**
	 * 子エレメントのXMLシリアライズを実行し、タグを生成する。<br>
	 * @param buf StringBuffer シリアライズXMLデータ
	 */
	protected void serializeXMLChildren(StringBuffer buf) {
		
		boolean blnFirstTime = true;
		CMIElement child = null;
		Iterator iterator = m_children.iterator();
		
		while ( iterator.hasNext() ) {
			child = ( CMIElement )iterator.next();
			if ( child != null ) {
				child.serializeXMLLog(buf);
			} else {
				//program error;
			}
		}
	}

}
