import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Server {
	public static int port_no = 5550;
	public static int intv_time = 100;
	class Player {
		String _name;
		ObjectOutputStream _os;
		Player(String name, ObjectOutputStream os){
			_name = name;
			_os = os;
		}
	}
	ArrayList<Player> _playerList = new ArrayList<Player>();
	int _turn = 0;

	public static void main(String[] args) {
		System.out.println("oldMaind - server");
		Server sv = new Server();
		sv.start();
	}
	
	public void start() {
		try {
			StartThread st0 = new StartThread();
			Thread t0 = new Thread(st0);
			t0.start();

			ServerSocket serverSocket = new ServerSocket(port_no);
			while (true){
				Socket socket = serverSocket.accept();
				ServerThread st = new ServerThread(socket);
				Thread t = new Thread(st);
				t.start();
			}
//			serverSocket.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	class StartThread implements Runnable {
		@Override
		public void run() {
			try {
				System.out.println("hit return key, if ready.");
				String cmd = new BufferedReader(new InputStreamReader(System.in)).readLine();

				System.out.println("game started");
				Integer[] card = Card.getCard();
				for ( int i = 0; i < card.length; i++ ){
					System.out.print( Card.toString(card[i]) + "," );
				}
				System.out.println("\nshuffle card");
				Thread.sleep(200);
				card = Card.shuffle(card);
				for ( int i = 0; i < card.length; i++ ){
					System.out.print( Card.toString(card[i]) + "," );
				}
				System.out.println("\ndeal card");
				Thread.sleep(200);
				List[] playerCard = Card.deal(card, _playerList.size());
				int i = 0;
				for (Player player : _playerList) {
					card = (Integer[])(playerCard[i].toArray(new Integer[0]));
					for ( int j = 0; j < card.length; j++ ){
						System.out.print( Card.toString(card[j]) + "," );
					}
					System.out.println();
					Command.send(player._os, Command.CMD_DEAL, card);
					i++;
				}
				_turn = 0;
				pickup(_turn);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}		
	}
	class ServerThread implements Runnable {
		Socket _socket;
		public ServerThread(Socket socket){
			_socket = socket;
		}
		@Override
		public void run() {
			try {
				OutputStream os = _socket.getOutputStream();
				InputStream	is = _socket.getInputStream();
				ObjectOutputStream oos = new ObjectOutputStream(os);
				ObjectInputStream ois = new ObjectInputStream(is);
				while (is.available() >= 0) {
					if (is.available() == 0){
						Thread.sleep(intv_time);
						continue;
					}
					int cmd = ois.readInt();
					Object obj = ois.readObject();
					func(cmd, obj, oos);
				} 
				_socket.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	private void func(int cmd, Object obj, ObjectOutputStream oos) throws Exception{
		switch(cmd){
		case Command.CMD_CONNECT:
			String name = (String)obj;
			System.out.println(name + " connected");
			_playerList.add(new Player(name, oos));
			break;
//		case Command.CMD_START:
//			System.out.println("game started");
//			Integer[] card = Card.getCard();
//			for ( int i = 0; i < card.length; i++ ){
//				System.out.print( Card.toString(card[i]) + "," );
//			}
//			System.out.println("\nshuffle card");
//			card = Card.shuffle(card);
//			for ( int i = 0; i < card.length; i++ ){
//				System.out.print( Card.toString(card[i]) + "," );
//			}
//			System.out.println("\ndeal card");
//			List[] playerCard = Card.deal(card, _playerList.size());
//			int i = 0;
//			for (Player player : _playerList) {
//				card = (Integer[])(playerCard[i].toArray(new Integer[0]));
//				for ( int j = 0; j < card.length; j++ ){
//					System.out.print( Card.toString(card[j]) + "," );
//				}
//				System.out.println();
//				Command.send(player._os, Command.CMD_DEAL, card);
//				i++;
//			}
//			_turn = 0;
//			pickup(_turn);
//			break;
		case Command.CMD_CARD_DEL:
			pickuped(_turn, (Integer)obj);
			_turn = nextPlayerIndex(_turn);
			pickup(_turn);
			break;
		}
	}
	private void pickup(int turn) throws Exception{
		int next = nextPlayerIndex(turn);
		Player player = _playerList.get(turn);
		Player nextPlayer = _playerList.get(next);
		String msg = nextPlayer._name + ", pick up " + player._name + "'s card";
		System.out.println(msg);
		Command.send(player._os, Command.CMD_PICKUP, msg);
	}
	private void pickuped(int turn, Integer card) throws Exception{
		int next = nextPlayerIndex(turn);
		Player player = _playerList.get(turn);
		Player nextPlayer = _playerList.get(next);
		String msg = "move [" + Card.toString(card) + "] " + player._name + " to " + nextPlayer._name;
		System.out.println(msg);
		Command.send(nextPlayer._os, Command.CMD_CARD_ADD, card);
	}
	private int nextPlayerIndex(int turn) throws Exception{
		int next = turn + 1;
		if (next >= _playerList.size()){
			next = 0;
		}
		return next;
	}
}
