package server;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import card.Card;
import player.BasePlayer;

public abstract class BaseGame {
	/*
	 * COLORS:
	 * GREEN
	 * RED
	 * YELLOW
	 * WHITE
	 * BLUE
	 * (COLORED)
	 */

	public static final byte[] MAGIC = { 1, 3, 3, 7 };
	public static final byte MOVE_INVALID = 0;
	public static final byte MOVE_VALID = 1;
	public static final byte MOVE_UPDATE = 5;
	public static final byte MOVE_WON = 6;
	public static final byte MOVE_LOST = 7;
	public static final byte MOVE_DRY = 1 << 6;
	public static final byte MOVE_PLACE_CARD = 2;
	public static final byte MOVE_TRASH_CARD = 3;
	public static final byte MOVE_HINT = 4;
	public static final byte HINT_COLOR = 0;
	public static final byte HINT_VALUE = 1;
	public static final byte CONNECTION_VALID = 8;
	public static final byte CONNECTION_INVALID = 9;

	final static int GREEN = 0;
	final static int RED = 1;
	final static int YELLOW = 2;
	final static int WHITE = 3;
	final static int BLUE = 4;
	//final static int COLORED = 5;
	final static int COLORS = 5;
	final static int N_CARDS = 50;
	final static int MAX_HINTS = 8;
	final static int MAX_FLASHS = 3;

	int nrOfPlayers = 0;
	static int CARDS_PER_PLAYER;
	int cardsInDeck;

	int hints;
	int flashs;
	Card[][] deck;
	int[] deckCounter;
	List<Card> trash;
	BasePlayer[] players;
	int currentPlayer;
	
	volatile boolean keepRunning;
	
	int port;

	List<String> history;

	public BaseGame(){
		keepRunning = true;
		//init();
	}
	
	protected void init(){
		createHistory();
		CARDS_PER_PLAYER = (nrOfPlayers <= 3) ? 5 : 4;
		hints = MAX_HINTS;
		flashs = 0;
		cardsInDeck = N_CARDS;
	}

	protected abstract void createHistory();
	protected abstract void createTrash();
	protected void createDeck(){
		deck = new Card[COLORS][5];
		deckCounter = new int[5];
		for (int i=0; i<deck.length; ++i){
			for (int j=0; j<deck[i].length; ++j){
				deck[i][j] = Card.DUMMY_CARD;
			}
		}
		for (int i = 0; i < 5; ++i) {
			deckCounter[i] = 0;
		}
	}

	protected boolean hintAvailable(){
		return hints > 0;
	}


	protected void createPlayers() {
		players = new BasePlayer[nrOfPlayers];
		for(int i=0; i<nrOfPlayers; ++i){
			players[i] = new BasePlayer(i, CARDS_PER_PLAYER, "Player " + i);
		}
	}

	public BasePlayer getPlayer(int index){
		return players[index];
	}
	
	/**
	 * Returns the state of the game at a given @param move index
	 * @param move the index of the move you want to get.
	 * Positive values are interpreted as index from the start (0 is the initial game).
	 * Negative values are interpreted as index from the end (-1 is the last state).
	 */
	public List<String> getHistory(int move){
		final int index = move>=0 ? move : history.size()+move;
		return history.subList(0, index);
	}
	
	protected abstract void receive(DataInputStream inStream);

	class SocketListenerThread implements Runnable {
		Socket socket;
		DataInputStream inStream;

		public SocketListenerThread(Socket socket){
			this.socket = socket;
			try {
				inStream = new DataInputStream(socket.getInputStream());
			} catch (IOException e) {
				throw new RuntimeException(e); // TODO wer faengt das?
			}
		}
		
		@Override
		public void run() {
			while(keepRunning){
				receive(inStream);
			}
		}
	}
}