//===========================================================================
// package
//===========================================================================
package jp.gr.java_conf.bugslife.form;

//===========================================================================
// import
//===========================================================================
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.*;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.ValidatorForm;
import java.io.UnsupportedEncodingException;

import java.util.*;

import jp.gr.java_conf.bugslife.util.*;
import jp.gr.java_conf.bugslife.bug.*;

/**
 *<PRE>
 * BugDependencyFormクラス
 *
 *</PRE>
 * @author 鰐川　正寛
 * @version 1.0.0
 */
public class BugDependencyForm extends ActionForm {
//===========================================================================
// attributes
//===========================================================================
	/**
	 * アクション
	 */
	private String m_action;
	/**
	 * 故障番号
	 */
	private int m_bno;
	/**
	 * 親故障
	 */
	private String m_parentBugs;
	/**
	 * 親故障リスト
	 */
	private List m_parentBugsList = new ArrayList();
	/**
	 * 子故障
	 */
	private String m_childBugs;
	/**
	 * 子故障リスト
	 */
	private List m_childBugsList = new ArrayList();
	/**
	 * bugDependsクラス
	 */
	private BugDepends m_bugDepends = null;
	/**
	 * メッセージKEY
	 */
	private String m_messageKey;
//===========================================================================
// methods
//===========================================================================
	/**
	 * アクションの取得
	 * 
	 * @return アクション
	 */
	public String getAction()
	{
		return m_action;
	}
	/**
	 * アクションのセット
	 * 
	 * @param action アクション
	 */
	public void setAction(String action)
	{
		m_action = action;
	}
	/**
	 * 故障番号の取得
	 * 
	 * @return 故障番号
	 */
	public int getBno()
	{
		return m_bno;
	}
	/**
	 * 故障番号のセット
	 * 
	 * @param bno 故障番号
	 */
	public void setBno(int bno)
	{
		m_bno = bno;
	}
	/**
	 * 親故障番号の取得
	 * 
	 * @return 親故障
	 */
	public String getParentBugs()
	{
		return m_parentBugs;
	}
	/**
	 * 親故障リストの取得
	 * 
	 * @return 親故障リスト
	 */
	public List getParentBugsList()
	{
		return m_parentBugsList;
	}
	/**
	 * 親故障のセット
	 * 
	 * @param parentBugs 親故障
	 */
	public void setParentBugs(String parentBugs)
	{
		m_parentBugs = parentBugs;
	}
	/**
	 * 子故障の取得
	 * 
	 * @return 子故障
	 */
	public String getChildBugs()
	{
		return m_childBugs;
	}
	/**
	 * 子故障リストの取得
	 * 
	 * @return 子故障リスト
	 */
	public List getChildBugsList()
	{
		return m_childBugsList;
	}
	/**
	 * 子故障のセット
	 * 
	 * @param childBugs 子故障
	 */
	public void setChildBugs(String childBugs)
	{
		m_childBugs = childBugs;
	}
	/**
	 * BugDependsクラスの取得
	 * 
	 * @return BugDependsクラス
	 */
	public BugDepends getBugDepends()
	{
		if (m_bugDepends == null) {
			m_bugDepends = new BugDepends();
			m_bugDepends.setBno(m_bno);
			m_bugDepends.load();
		}
		return m_bugDepends;
	}
	/**
	 * 結果メッセージkeyの取得
	 * 
	 * @return 結果メッセージkey
	 */
	public String getMessageKey()
	{
		return m_messageKey;
	}
	/**
	 * 結果メッセージの取得
	 * 
	 * @return 結果メッセージ
	 */
	public String getMessage()
	{
		if (m_messageKey == null) {
			return "";
		} else {
			return Varidater.getMessage(m_messageKey);
		}
	}
	/**
	 * 結果メッセージkeyのセット
	 * 
	 * @param messageKey 結果メッセージkey
	 */
	public void setMessageKey(String messageKey)
	{
		m_messageKey = messageKey;
	}
//===========================================================================
// Public Methods
//===========================================================================
	/**
	* リセット
	*
	* @param mapping The mapping used to select this instance
	* @param request The servlet request we are processing
	*/
	public void reset(ActionMapping mapping, HttpServletRequest request) {
		m_action = null;
		m_bno = 0;
		m_parentBugs = null;
		m_parentBugsList = new ArrayList();
		m_childBugs = null;
		m_childBugsList = new ArrayList();
		m_bugDepends = null;
		m_messageKey = null;
	}
	/**
	* Validate the properties that have been set from this HTTP request,
	* and return an <code>ActionErrors</code> object that encapsulates any
	* validation errors that have been found.  If no errors are found, return
	* <code>null</code> or an <code>ActionErrors</code> object with no
	* recorded error messages.
	*
	* @param mapping The mapping used to select this instance
	* @param request The servlet request we are processing
	*/
	public ActionErrors validate(ActionMapping mapping,
								 HttpServletRequest request) {
		ActionErrors errors = new ActionErrors();
		//debug
		debug("validate");
		
		//アクション
		if (Varidater.checkRequired(m_action, "action", errors)) {
			
			//quickか？
			if (m_action.equals("update")) {
				
				//故障番号の解析
				m_parentBugsList = 
						parseChoiceBno(m_parentBugs, "bno", errors);
				m_childBugsList = 
						parseChoiceBno(m_childBugs, "bno", errors);
				
				//故障番号の存在チェック
				existBno(m_parentBugsList, "bno", errors);
				existBno(m_childBugsList, "bno", errors);
				
				if (errors.empty()) {
					//故障番号の依存関係チェック
					relationCheck(m_parentBugsList, m_childBugsList, "bno", errors);
				}
			}
		}
		
		return errors;
	}

//===========================================================================
// debug Methods
//===========================================================================
	/**
	 * デバッグ文字出力
	 *
	 * @param s 出力文字列
	 */
	private void debug(String s) {
		System.out.println("[BugDependencyForm]" + s);
	}
//===========================================================================
// parser Methods
//===========================================================================
	/**
	 * 故障番号の解析
	 * 
	 * @return 故障番号
	 */
	private List parseChoiceBno(String bnos, String name, ActionErrors errors) {
		
		List bnoList = new ArrayList();
		
		//カンマで分解しながら、中を解析していく
		StringTokenizer st = new StringTokenizer(bnos, ",");
		while (st.hasMoreTokens()) {
			String token = st.nextToken();
			//tokenは空か？
			if ((token != null) && (token.length() > 0)) {
				//空でなければ
				//数値チェック
				if (Varidater.checkNumeric(token, "#" + token, errors)) {
					//リスト追加
					bnoList.add(new Integer(token));
				}
			}
		}
		
		return bnoList;
	}

	/**
	 * 故障番号の存在チェック
	 * 
	 * @return 故障番号
	 */
	private void existBno(List list, String name, ActionErrors errors) {
		
		Iterator ite = list.iterator();
		
		Bug bug = null;
		int bno = 0;
		while (ite.hasNext()) {
			bno =((Integer)ite.next()).intValue();
			bug = Bug.getBug(bno);
			
			//存在チェック
			if (bug == null) {
				Varidater.addErrors("varid.invalid_bno", "#" + Converter.getNumberString(bno, "0000"), errors);
			}
		}
	}
	/**
	 * 故障番号の依存関係チェック
	 * 
	 * @return 故障番号
	 */
	private void relationCheck(List parentList, List childList, String name, ActionErrors errors) {
		
		ArrayList parentSet = new ArrayList();
		ArrayList childSet = new ArrayList();
		
		int bno =0;
		BugDependsTree tree = null;
		
		
		//親番号リストの重複チェック
		boolean duplicateFlag = false;
		for (int i = 0; i < parentList.size(); i++) {
			for (int j = i + 1; j < parentList.size(); j++) {
				if (((Integer)parentList.get(i)).compareTo((Integer)parentList.get(j)) == 0) {
					duplicateFlag = true;
					break;
				}
			}
			if ( ((Integer)parentList.get(i)).compareTo(new Integer(getBno())) == 0 ) {
				duplicateFlag = true;
				break;
			}
		}
		if (duplicateFlag) {
			Varidater.addErrors("varid.relationBno", name, errors);
			return;
		}
		
		//子番号リストの重複チェック
		duplicateFlag = false;
		for (int i = 0; i < childList.size(); i++) {
			for (int j = i + 1; j < childList.size(); j++) {
				if (((Integer)childList.get(i)).compareTo((Integer)childList.get(j)) == 0) {
					duplicateFlag = true;
					break;
				}
			}
			if ( ((Integer)childList.get(i)).compareTo(new Integer(getBno())) == 0 ) {
				duplicateFlag = true;
				break;
			}
		}
		if (duplicateFlag) {
			Varidater.addErrors("varid.relationBno", name, errors);
			return;
		}
		
		//全ての親Treeの作成
		Iterator parentIte = parentList.iterator();
		while (parentIte.hasNext()) {
			bno = ((Integer)parentIte.next()).intValue();
			tree = new BugDependsTree(bno);
		//	parentSet = new TreeSet(tree);
			parentSet.add(tree);
			parentSet.addAll(tree.getAllParents());
		}
		//全ての子Treeの作成
		Iterator childIte = childList.iterator();
		while (childIte.hasNext()) {
			bno = ((Integer)childIte.next()).intValue();
			tree = new BugDependsTree(bno);
		//	childSet = new TreeSet(tree);
			childSet.add(tree);
			childSet.addAll(tree.getAllChilds());
		}
		
		//親Setと子Setで同じものがあるかチェック
		if ( (parentSet != null) && (childSet != null) ) {
			for (int i = 0; i < parentSet.size(); i++) {
				for (int j = 0; j < childSet.size(); j++) {
					if (((BugDependsTree)parentSet.get(i)).getBno() == 
							((BugDependsTree)childSet.get(j)).getBno() ) {
						Varidater.addErrors("varid.relationBno", name, errors);
						return;
					}
				}
			}
		}
	}

//===========================================================================
// Test
//===========================================================================
	/**
	 *	テストメイン
	 */
	public static void main(String[] args)
	{
		System.out.println("------- << BugDependsTree Test Start >> -----------");
		unitTest1();	//dispTreeテスト
		
		System.out.println("------- << BugDependsTree Test End >> -----------");
	}
	
	/**
	 *	unitTest1
	 *
	 * 新規作成テスト
	 *
	 */
	public static void unitTest1()
	{
		System.out.println("------- unitTest1 -----------");
		
		int bno = 2;	//バグ番号
		//値のセット
		BugDependencyForm form = new BugDependencyForm();
		form.setBno(bno);
		
		List parentList = new ArrayList();
		parentList.add(new Integer(1));
		parentList.add(new Integer(6));
		List childList = new ArrayList();
		childList.add(new Integer(3));
		childList.add(new Integer(5));
		String name = "bno";
		ActionErrors errors = new ActionErrors();
		form.relationCheck(parentList, childList, name, errors);
		
		
	}

}