/*
 * Created on 22.11.2004
 *
 */
package de.farafin.snEADy.player;
import java.io.Serializable;
import de.farafin.snEADy.C_DebugMonitor;

/** This is the basic player class which your player should be extended from.
 * The interface 'Serializable' is necessary for us to controll how much ram-space a player needs.
 * Please implement it in each of your classes, there is not more to do than just implement it,
 * no realization of methods is required. Java gives this interface standard methods which we
 * use for controlling the Players ram-space.<br>
 * <br>
 * Dies ist die Basisspieler Klasse von welcher der euer Spieler abgeleitet werden soll.
 * Das Interface 'Serializable' ist nötuig, damit wir kontrollieren können wie viel ram-Speicher ein
 * Spieler benutzt. Bitte implementiert dieses Interface in jede eurer Klassen, aber ihr braucht
 * keine Methoden davon zu realisieren. Java gibt Standardmethoden vor, die wir benutzen um den  
 * Speicherverbrauch das Spielers festzustellen. 
 * 
 * @author roland, lars 
 * 
 * @version $Revision: 1.12 $
 */
public abstract class Player implements PubConstants, Serializable
{
	/** The name of the player. This string will be read if it was successfully build an instance
	 * of the player. So if you like to have a different playername then you your filename,
	 * define that in your constructor.<br>
	 * <br>
	 * Der Name des Spielers. Der String wird ausgelesen wenn erfolgreich eine Instanz vom Spieler
	 * erzeut wurde. Wenn ihr also in der Anzeige einen anderen Namen als den Dateinamen haben wollte
	 * dann setzt ihn in eurem Konstruktor. 
	 *  */
	private String name;	
	
	/** The direction the head of the snake should turn to.<br>
	 * <br>
	 * Die Richtung in die sich der Kopf der schlange drehen soll.
	 * 
	 * @see PubConstants#TURN_LEFT
	 * @see PubConstants#TURN_NONE
	 * @see PubConstants#TURN_RIGHT
	 */
	private int turnDirection;

	/** Here is the system time stored at which the players calculation method was started.
	 * It will be renewed every time the player starts his calculation.<br>  
	 * <br>
	 * Hier wird die Systemzeit gespeichert an der der Spieler seine Berechnung
	 * gestartet hat. Der wert wird jedes mal neu gesetzt wenn der Spieler seine
	 * Berechnung startet.
	 */
	private long startTime;
	
	/** The maximal amount of time in milliseconds the player is allowed to think.<br>
	 * <br>
	 * Die maximale Anzahl an Millisekunden, die der Spieler überlegen darf.
	 */
	private long maxTime;
	
	/** This is the small window for debug informations of the player<br>
	 * <br>
	 * Dies ist das kleine Fenster für die debug-ausgaben der Spieler.
	 */
	private C_DebugMonitor monitor;
	
	/** Overwrite this variable to print it in the player menu.<br>
	 * <br>
	 * Überschreibt diese Variable um sie im Player Menü anzuzeigen. 
	 */
	public static String comment = "";

	
	/** default constructor */
	public Player()
	{
		// set the name of the player to the filename. if theplayer like to change his name
		// he should do that in his own constructor because it won't read any more later. 
		this.name = this.getClass().getName();
		// the first turn Directon is none.
		this.turnDirection = TURN_NONE;
		// just to initial startTime, it will reset when the player will started.
		this.startTime = 0;
	}

	
	
	/** This method is called when the player begins to calculate his next move.
	 * It is an extra method call to compute the start time.<br>
	 * <br>
	 * Diese Funktion wird aufgerufen wenn der Spieler seine Berechnung begint.
	 * Es wird diese Funktion extra aufgerufen damit die Startzeit berechnet werden kann.
	 * 
	 * @param gInfo game informations  <br> Spiel Informationen
	 * @param lInfo level informations <br> Level Informationen
	 * @param sInfo an array of informations about all other snakes in the field. <br>
	 * Ein Array von Informationen über alle anderen Spieler auf dem Spielfeld.
	 * @param oInfo Informations about the own Snake <br>
	 * Informationen über die eigene Schlange.
	 * 
	 * @see GameInfo
	 * @see LevelInfo
	 * @see SnakeInfo
	 * @see OwnSnakeInfo
	 */
	public void startCalculation(GameInfo gInfo, LevelInfo lInfo, SnakeInfo []sInfo, OwnSnakeInfo oInfo)
	{
		// the maximum time the player is allowed to calculate its move.
		this.maxTime = gInfo.thinkingMS;
		if(gInfo.gameTime == 0) this.maxTime += gInfo.analyseMS;

		// stores the current time.
		this.startTime = System.currentTimeMillis();
		// call the calculate method of the player
		this.calculate(gInfo, lInfo, sInfo,oInfo);
	}
	
	

	/** This is the method you should implement. Here it should be decided to which value
	 * turnDirection is set. This method will be called for each player in every game cycle. 
	 * <br>
	 * Diese Methode soll von euch implementiert werden. Es muss nur entschieden werden auf welchen
	 * Wert turnDirection gesetzt wird. Die Methode wird für jeden Spieler in jedem game Zyclus
	 * ein mal aufgerufen.
	 * 
	 * @param gInfo game informations  <br> Spiel Informationen
	 * @param lInfo level informations <br> Level Informationen
	 * @param sInfo an array of informations about all other snakes in the field. <br>
	 * Ein Array von Informationen über alle anderen Spieler auf dem Spielfeld.
	 * @param oInfo Informations about the own Snake <br>
	 * Informationen über die eigene Schlange.
	 * 
	 * @see GameInfo
	 * @see LevelInfo
	 * @see SnakeInfo
	 * @see OwnSnakeInfo
	 */
	protected abstract void calculate(GameInfo gInfo, LevelInfo lInfo, SnakeInfo []sInfo, OwnSnakeInfo oInfo);
	

	
	/** this Method returns the number of milliseconds the player has left for his calculation.
	 * Note that that the internal timer of the pc is not very precise and depends on the hardware
	 * and operating system.You can estimate a precisition of around 15 - 16 milliseconds.<br>
	 *  <br>
	 * Diese Methode gibt die Anzahl an Millisekunden zurrück, die der Spieler schon überlegt.
	 * Bedenkt bitte, dass die der interne Timer des PC's nicht sehr genau ist und dass die
	 * Genauigkeit von Hardware und Betriebssystem abhängig ist. Ihr könnt von einer
	 * Genauigkeit von ungefär 15 bis 16 Millisekunden aus gehen.
	 * 
	 * @return Returns the number of millisecons that are left for calculation. */
	protected long msLeft() {return (this.maxTime + this.startTime - System.currentTimeMillis());}
	
	/** this Method returns the number of milliseconds the player has calculated jet.
	 * Note that that the internal timer of the pc is not very precise and depends on the hardware
	 * and operating system.You can estimate a precisition of around 15 - 16 milliseconds.<br>
	 * <br>
	 * Diese Methode gibt die Anzahl an Millisekunden zurrück, die der Spieler schon überlegt.
	 * Bedenkt bitte, dass die der interne Timer des PC's nicht sehr genau ist und dass die
	 * Genauigkeit von Hardware und Betriebssystem abhängig ist. Ihr könnt von einer
	 * Genauigkeit von ungefär 15 bis 16 Millisekunden aus gehen.
	 * 
	 * @return Returns the number of millisecons which the calculation of the player still runs. */
	protected long msDone() {return (System.currentTimeMillis() - this.startTime);}

	
	
	/** @return Returns the name. */
	public String getName(){return name;}
	/** @param name The name to set. */
	protected void setName(String name){this.name = name;}
		
	/** @return Returns the turnDirection. */
	public int getTurnDirection() {return turnDirection;}
	/** @param turn set the direction the player should turn to. */
	protected void setTurnDirection(int turn)
	{
		// the turn direction must be one of the three TURN_LEFT, TURN_NONE or TURN_RIGHT
		if(turn == TURN_LEFT || turn == TURN_NONE || turn == TURN_RIGHT) this.turnDirection = turn;
		else
		{
			System.out.println("WARNING: turnDirection should be set to TURN_LEFT, TURN_NONE or TURN_RIGHT. " + turn + " is none of these constants.");
			this.turnDirection = turn;
		}
	}
	
	/** This method prints your string into the debug monitor window. Because printing text is
	 * very time consumting, the text is stored in a buffer and printed when the player is
	 * done with calculation.<br>
	 * <br>
	 * Diese Methode gibt einen String in den Debug Monitor aus. Weil textausgaben sehr Zeitintensiv
	 * sind, wird der Text in einem Buffer zwischengespeichert und ausgegeben wenn der Spieler
	 * seine Berechnung beendet hat. 
	 * 
	 * @param oInfo OwnSnakeInfo, is required to identify the player who prints the text<br>
	 * @param str the string that should be printed
	 */
	protected void say(OwnSnakeInfo oInfo, String str)
	{
		//if(!this.monitor.isVisible()) this.monitor.setVisible(true);
		this.monitor.say(oInfo, str);
	}

	/** This method prints your string into the debug monitor window. The string is
	 * printed directly, without buffering. Note that printing text is very time consumting and
	 * your player will have perceptible less time to calculate if you do this too often!<br>
	 * <br>
	 * Diese Methode gibt einen String in den Debug Monitor aus. Der String wird direkt ausgegeben,
	 * ohne zwischen zu speichern. Bedenke dass Textausgabe sehr Zeitintensiv ist! Der Spieler
	 * wird spürbar weniger Zeit für seine Berechnungen haben wenn diese Methode zu oft aufgerufen wird.
	 * 
	 * @param oInfo OwnSnakeInfo, is required to identify the player who prints the text
	 * @param str the string that should be printed
	 */
	protected void sayNow(OwnSnakeInfo oInfo, String str)
	{
		//if(!this.monitor.isVisible()) this.monitor.setVisible(true);
		this.monitor.sayIm(oInfo, str);
	}
	
	/** @param monitor The monitor to set. (not very intresting for the player) */
	public void setMonitor(C_DebugMonitor monitor){this.monitor = monitor;}
}