package jp.ac.nii.icpc2010.manager;

import java.lang.reflect.Constructor;
import java.util.concurrent.TimeoutException;

import jp.ac.nii.icpc2010.players.AbstractPlayer;
import jp.ac.nii.icpc2010.players.Player;
import jp.ac.nii.icpc2010.playfield.FieldDirection;
import jp.ac.nii.icpc2010.playfield.RefPlayField;



public class TimeKeeper {

	public FieldDirection getInput(Player player, long timeout) throws InterruptedException, TimeoutException{
		FieldDirection[] buf = new FieldDirection[]{null};

		Thread playerThread = new Thread(new PlayerRunProcess(buf, player, System.currentTimeMillis() + timeout));
		//playerThread.setPriority(Thread.MAX_PRIORITY);

		long startTime = System.currentTimeMillis();
		playerThread.start();

		long waitTime = timeout + 1 - (System.currentTimeMillis() - startTime);
		while(waitTime > 0){
			try{
				playerThread.join(waitTime);
				waitTime = 0;
			}catch(InterruptedException e){
				waitTime = timeout + 1 - (System.currentTimeMillis() - startTime);
			}
		}

		// this block should be atomic.
		FieldDirection input = buf[0];
		long endTime = System.currentTimeMillis();


		playerThread.stop();
		while(playerThread.isAlive()){
			try{
				Thread.sleep(1);
			}catch(InterruptedException e){
			}
		}

		if(endTime - startTime > timeout){
			throw new TimeoutException();
		}

		return input;
	}

	public AbstractPlayer getInstance(Constructor<? extends AbstractPlayer> playerConstructor, int playerId, RefPlayField playField, long timeout, OptionsManager om) throws InterruptedException, TimeoutException{
		AbstractPlayer[] buf = new AbstractPlayer[]{null};

		Thread playerThread = new Thread(new PlayerInitProcess(buf, playerConstructor, playerId, playField, om));
		//playerThread.setPriority(Thread.MAX_PRIORITY);

		long startTime = System.currentTimeMillis();
		playerThread.start();

		long waitTime = timeout + 1 - (System.currentTimeMillis() - startTime);
		while(waitTime > 0){
			try{
				playerThread.join(waitTime);
				waitTime = 0;
			}catch(InterruptedException e){
				waitTime = timeout + 1 - (System.currentTimeMillis() - startTime);
			}
		}

		// this block should be atomic.
		AbstractPlayer player = buf[0];
		long endTime = System.currentTimeMillis();


		playerThread.stop();
		while(playerThread.isAlive()){
			try{
				Thread.sleep(1);
			}catch(InterruptedException e){
			}
		}

		if(endTime - startTime > timeout){
			throw new TimeoutException();
		}

		return player;
	}
}
