/** 兵士ひとりひとり、矢の一本一本にいたるまでスレッドをわりふるのは、なにかと、めんどう。
そこで時間とともにうつりかわるユニットは、すべて、このRunnableリストクラスのスレッドひとつをつかって一元的に管理する。 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.*;

public class RunnableUnitList implements Runnable {

	Thread unitThread = null;
	Board board; //そのユニットが配置される盤。

	RunnableUnitNode last;	// 最後の要素。
	int length;	// 要素数。

	public RunnableUnitList(Board b) {
		board = b;
		last = null;
		length = 0;
	}
	public RunnableUnitList(RunnableUnit u, Board b) {
		board = b;
		last = null;
		length = 0;
		add(u);
	}

	public void start() {
		if (unitThread == null)
			unitThread = new Thread(this);
		unitThread.start();
	}

	public void show(Graphics g, int squareSizeX, int squareSizeY, Component viewer) {

		if (last != null) {
			RunnableUnitNode nUnit = last;


			// リストにぶらさがっている最初の要素から、最後の要素まで、順番にshowを呼び出す。
			do {
				if( nUnit.next.item != null ) {
					nUnit.next.item.show(g, squareSizeX, squareSizeY, viewer);

					nUnit = nUnit.next;
				} else {
				// もしノードからユニットが消滅していたらリストから削除。

					length--;
					// 現在、リストにたった一つしか要素がなく、これを削除するとリストが空になるのなら、リストのlastにnullを代入。
					if (nUnit.next == nUnit.next.next) {
						last = null;
						nUnit.next = null;	//自己参照をやめることでガーベッジコレクションに自身を削除させる。
						nUnit = nUnit.next;
					} else {
						// 削除する要素がリストの最端末の要素なら、lastの指し示す先も修正。
						if (nUnit.next == last)
							last = nUnit;
						nUnit.next = nUnit.next.next;
					}
				}


			} while (nUnit != last);
		}
	}

	public void run() {

		while (0 < board.getSpeed() ) {

			if (last != null) {

				RunnableUnitNode nUnit = last;

				// リストにぶらさがっている最初の要素から、最後の要素まで、
				// 順番にrunを呼び出す。
				do {
					if( nUnit.next.item != null ) {
						nUnit.next.item.run();
						nUnit = nUnit.next;
					}
					else {
						// もしノードからユニットが消滅していたらリストから削除。
						length--;

						// 現在、リストにたった一つしか要素がなく、
						// これを削除するとリストが空になるのなら、
						// リストのlastにnullを代入。
						if (nUnit.next == nUnit.next.next) {
							last = null;
							nUnit.next = null;	//自己参照をやめることでガーベッジコレクションに自身を削除させる。
							nUnit = nUnit.next;
						} else {
							// 削除する要素がリストの最端末の要素なら、lastの指し示す先も修正。
							if (nUnit.next == last)
								last = nUnit;
							nUnit.next = nUnit.next.next;
						}
					}

				} while (nUnit != last && 0 < board.getSpeed() );
			}

			// 現在速度に応じてウエイトをおく。
			try
			{
				unitThread.sleep( board.getSpeed());
			}
			catch (InterruptedException e)
			{
			}

		}
		unitThread = null;
	}

	public void allRemove() {
		if (last != null)
			last.next = null;
		last = null;
		length = 0;
	}

	/** 引数によって指定された要素だけを削除するメソッド。(ノードはそのまま)
	 *削除というよりは、nullを代入するだけでは、あるが。
	 *返値:true。指定された要素を無事削除できたとき。
	 *返値:false。指定された要素がリスト内に存在しないなど、なんらかの理由で削除できなかったとき。
	*/
	public boolean remove(RunnableUnit funit) {

		if (last != null) {

			RunnableUnitNode node_check = last;

			do {

				// もし、このノードがぶらさげてる要素が、指定の要素だった場合は削除処理をしてtrueを返す。
				if (node_check.next.item == funit) {

					node_check.next.item = null;
					return true;
				}
				node_check = node_check.next;

			} while(node_check != last);
		}

		// リスト上に、指定された要素が見つからなかった場合はfalseを返して終了。
		return false;
	}


	/** 引数によって指定された要素をノードごと削除するメソッド。
	 *返値:true。指定された要素を無事削除できたとき。
	 *返値:false。指定された要素がリスト内に存在しないなど、なんらかの理由で削除できなかったとき。
	*/
	public boolean removeNodeAndUnit(RunnableUnit funit) {

		if (last != null) {

			RunnableUnitNode node_check = last;

			do {

				// もし、このノードがぶらさげてる要素が、指定の要素だった場合は削除処理をしてtrueを返す。
				if (node_check.next.item == funit) {

					// 現在リストにたった一つしか要素がなく、これを削除するとリストが空になるのなら、リストのlastにnullを代入。
					if (node_check.next == node_check.next.next) {
						last = null;
						node_check.next = null;	//自己参照をやめることでガーベッジコレクションに自身を削除させる。
						length = 0;
					} else {
						if (node_check.next == last)
							last = node_check;
						node_check.next = node_check.next.next;
						// 削除する要素がリストの最端末の要素なら、lastの指し示す先も修正。
					length--;
					}
					return true;
				}
				node_check = node_check.next;

			} while(node_check != last);
		}

		// リスト上に、指定された要素が見つからなかった場合はfalseを返して終了。
		return false;
	}


	/** リストの最後尾に要素を追加。 */
	public void add(RunnableUnit funit) {

		RunnableUnitNode node_newUnit = new RunnableUnitNode(funit);

		if (last != null) {
			node_newUnit.next = last.next;
			last.next = node_newUnit;
		} else
			node_newUnit.next = node_newUnit;

		last = node_newUnit;
		length++;

	}

	/** 最初から数えてi番目の要素を返す。 */
	public RunnableUnit get(int i) {
		RunnableUnitNode retUnitNode;

		if (0 > i || i >= length)
			return null;
		else {
			retUnitNode = last.next;
			for (; i != 0; i--)
				retUnitNode = retUnitNode.next;

			return retUnitNode.item;
		}
	}

	public int getLength() { return length; }

	class RunnableUnitNode {

		RunnableUnitNode next;
		RunnableUnit item;

		public RunnableUnitNode(RunnableUnit rUnit) {
			item = rUnit;
		}
	}

}