/*
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2005 satoshi akabane(akabane@logical-paradox.org)
 * $Id: RoutingAlgorithmTestDriver.java,v 1.3 2005/03/18 13:55:26 rampil Exp $
 */
package org.logical_paradox.testsite.oln.model;

import java.util.Iterator;
import java.util.Random;

import org.logical_paradox.testsite.oln.object.Node;
import org.logical_paradox.testsite.oln.object.Topology;

import junit.framework.TestCase;

/**
 * 経路決定処理のテスト用ドライバ
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.3 $
 */
public class RoutingAlgorithmTestDriver extends TestCase {
	/** 最大実行回数 */
	public static final int MAX_EXECUTE_COUNT = 3;
	/** 分散ネットワークの空間幅(横) */
	public static final int NETWORK_WIDTH = 640;
	/** 分散ネットワークの空間幅(縦) */
	public static final int NETWORK_HEIGHT = 480;
	public static final int MAX_DEPLOY_COUNT = 50;
	public static final int MAX_CONNECTIONS = 25;

	/** 乱数ジェネレータ */
	private final Random r = new Random(System.currentTimeMillis());

	/**
	 * Constructor for RoutingAlgorithmTestDriver.
	 * @param arg0
	 */
	public RoutingAlgorithmTestDriver(String arg0) {
		super(arg0);
	}

	/**
	 * テストドライバ001
	 * ランダムにノードを追加して、トポロジが維持されることを確認する
	 */
	public void testExecuteSimulation001() {
		Topology topology = new Topology();

		// 適当な回数繰り返し実行する
		int executeCount = Math.abs(r.nextInt()) % MAX_EXECUTE_COUNT;

		// より複雑なネットワークを作成する
		while(executeCount >= 0) {
			createTopology(topology);
			executeCount--;
		}

		System.out.println("[001] 複雑性= " + topology.getComplex() + " 最小=" + topology.getMinNodeCount() + " 最大= " + topology.getMaxNodeCount());
		// 最終的に，必ずトポロジが維持されていなければならない
		assertTrue(topology.getNodeListSize() > 1);
		assertTrue(topology.isCompleteConnectivity());
	}
	/**
	 * テストドライバ002
	 * ランダムにノードを追加した後、ランダムにノードを離脱させる。
	 * その場合にトポロジが維持され、一方向参照が発生していないことを確認する
	 */
	public void testExecuteSimulation002() {
		Topology t = new Topology();
		createTopology(t);

		assertTrue(t.getNodeListSize() > 0);
		System.out.println("[00*] 複雑性= " + t.getComplex() + " 最小=" + t.getMinNodeCount() + " 最大= " + t.getMaxNodeCount());
		assertTrue(t.isCompleteConnectivity());

		// 適当にノードを削除する
		int executeCount = Math.abs(r.nextInt() % 50 + 10);
		while(executeCount > 0 && t.getNodeListSize() > 0) {
			int ni = Math.abs(r.nextInt() % t.getNodeListSize());
			t.removeNode(t.getNode(ni));
			System.out.println("[002] 複雑性= " + t.getComplex() + " 最小=" + t.getMinNodeCount() + " 最大= " + t.getMaxNodeCount());

			// 全てのノードが相互参照になっているかどうかを確認する
			for(Iterator it = t.iteratorNodes(); it.hasNext();) {
				Node node = (Node)it.next();
				assertTrue(node.isHoldByBuddies());
			}
			assertTrue(t.getNodeListSize() <= 1 || t.isCompleteConnectivity());
			executeCount--;
		}
	}
	/**
	 * 適当にノードが配置された分散ネットワークを作成する
	 * @param topology 分散ネットワーク
	 */
	protected void createTopology(Topology topology) {
		// 分散ネットワーク上に適当にノードを配置する
		int deployCount = Math.abs(r.nextInt()) % MAX_DEPLOY_COUNT + 15;
		while(deployCount > 0) {
			// 既に分散ネットワーク上に配置されているノードを
			// 適当な数だけ選択しておく
			if(topology.getNodeListSize() > 0) {
				int chooseItems = Math.abs(r.nextInt() % topology.getNodeListSize() +1);
				// 分散ネットワーク上に少なくとも1つ以上のノードが配置されているのならば
				while(chooseItems > 0) {
					int index = Math.abs(r.nextInt() % topology.getNodeListSize());
					topology.get(index).setSelected(true);
					chooseItems--;
				}
			}
			int x = Math.abs(r.nextInt()) % NETWORK_WIDTH;
			int y = Math.abs(r.nextInt()) % NETWORK_HEIGHT;
			topology.deployNewNode(x,y);

			deployCount--;
		}
		// 分散ネットワークが完成した後，最適ノード選択処理を実行する
		topology.researchConnectivity();
	}
}
