package game.gui;

import game.logic.GameBoard;
import game.logic.Nemesh;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;

public class GamerGUI extends JFrame {
private static final long serialVersionUID = 1L;
	
	private GameBoard player_board;
	private JLabel labelBoard[];
	private JButton buttonLine[];
	private int color = 0;
	private JLabel player_color;
	private JLabel player_score;
	private JLabel player_name;
	private ImageIcon blackDiscIcon;
	private ImageIcon redDiscIcon;
	private boolean isPushed; /* tells us whether a push event had occurred */
	private int ourLastMove = 0;
	
	private JPanel mainPanel;
	
	public GamerGUI(GameBoard board, int color){
		this.player_board = board;
		this.isPushed = false;
		this.color = color;
		
		mainPanel = new JPanel();
		/* Six rows for the board + one row for the buttons + stats row */
		mainPanel.setLayout(new GridLayout(8,8));
		labelBoard = new JLabel[GameBoard.NumOfRows * GameBoard.NumOfColumns];
		buttonLine = new JButton[GameBoard.NumOfColumns];
		blackDiscIcon = new ImageIcon(getClass().getResource("/resources/images/black.png"));
		redDiscIcon = new ImageIcon(getClass().getResource("/resources/images/red.png"));
		
		theHandler handler = new theHandler(); // Relevant for human player only
		
		/* Labels of the board, where we will draw the discs */
		for (int i = 0; i < GameBoard.NumOfRows * GameBoard.NumOfColumns; i++){
			labelBoard[i] = new JLabel();
			labelBoard[i].setBorder(new LineBorder(Color.BLACK, 3));
			mainPanel.add(labelBoard[i]);
		}
		
		/* The button line */
		for (int i = 0; i < GameBoard.NumOfColumns; i++){
			buttonLine[i] = new JButton();
			buttonLine[i].setText("Drop!");
			buttonLine[i].addActionListener(handler);
			buttonLine[i].setEnabled(false);
			mainPanel.add(buttonLine[i]);
		}
		
		/* Resize images to normal size */
		Image temp = redDiscIcon.getImage();
		Image temp1 = blackDiscIcon.getImage();
		redDiscIcon.setImage(temp.getScaledInstance(60, 60, Image.SCALE_SMOOTH));
		blackDiscIcon.setImage(temp1.getScaledInstance(60, 60, Image.SCALE_SMOOTH));
		
		/* some statistics */
		player_color = new JLabel("Color: ");
		mainPanel.add(player_color);
		
		player_score = new JLabel("Score: ");
		mainPanel.add(player_score);
		
		player_name = new JLabel("Name: ");
		mainPanel.add(player_name);
		
		/* manage the game tabs, and switch to the game tab of the current game */
		Nemesh.GameTabs.addTab("Game #" + Nemesh.GameNumber, mainPanel);
		Nemesh.GameTabs.setSelectedIndex(Nemesh.GameNumber-1);
	}
	
	public void setScore(int score){
		player_score.setText("Score: " + score);
	}
	
	public void setName(String name){
		player_name.setText("<html><b>Name:</b><br>" + name + "</html>");
		player_name.setToolTipText(name);
	}
	
	public void setColor(String color){
		player_color.setText("Color: " + color);
	}
	
	
	/**
	 * Release all buttons except the ones that their column is full. Relevant only for
	 * human player.
	 */
	public void releaseButtons(){
		for (int i = 0; i < GameBoard.NumOfColumns; i++){
			if (!player_board.isColumnFull(i)){
			buttonLine[i].setEnabled(true);
			}
		}
	}
	
	/**
	 * Lock all buttons (during the opponent move). Relevant only for human player.
	 */
	public void lockButtons(){
		for (int i = 0; i < GameBoard.NumOfColumns; i++){
			buttonLine[i].setEnabled(false);
		}
	}
	
	/**
	 * Wait for a button push. Relevant only for human player.
	 * 
	 * @param timeLimit The time limit for the human player move.
	 * 
	 * @return The procedure returns the column Id of the button pushed.
	 * In case the wait exceeds the time limit, -1 will be returned.
	 */
	public int waitForPush(long timeLimit){
		while(!isPushed){
			if ((timeLimit - System.currentTimeMillis())/1000.0 <= 2.0){
				break;
			}
			try {
				Thread.sleep(500);
			}  catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		if (!isPushed){
			lockButtons();
			return -1;
		}
		
		this.isPushed = false;
		return this.ourLastMove;
	}
	
	/**
	 * Update the game board view for the opponent move.
	 * @param opponentColumn
	 */
	public void updateOpponentMove(int opponentColumn){
		int labelID;
		this.player_board.insertDisc(opponentColumn, 3 - this.color);
		
		/* since we've added a disk with the player, we do not need the: 6-(#disks+1)
		 * we can skip the +1 (we want to update as if there is one less disk, i.e.
		 * update the last move of the opponent)*/
		labelID = GameBoard.NumOfColumns*(GameBoard.NumOfRows-player_board.getDiscsPerColumn()[opponentColumn])+opponentColumn;
		labelBoard[labelID].setIcon((this.color == GameBoard.BlackPlayer) ? redDiscIcon : blackDiscIcon);
		labelBoard[labelID].setHorizontalAlignment(SwingConstants.CENTER);
	}
	
	/**
	 * Update the game board view for the human player move.
	 * @param ourColumn
	 */
	public void updateOurMove(int ourColumn){
		int labelID;
		
		this.player_board.insertDisc(ourColumn, this.color);
		labelID = GameBoard.NumOfColumns*(GameBoard.NumOfRows-player_board.getDiscsPerColumn()[ourColumn])+ourColumn;
		labelBoard[labelID].setIcon((this.color == GameBoard.BlackPlayer) ? blackDiscIcon : redDiscIcon);
		labelBoard[labelID].setHorizontalAlignment(SwingConstants.CENTER);
	}
	
	/**
	 * This is a private class that handles button events.
	 */
	private class theHandler implements ActionListener{
		public void actionPerformed(ActionEvent event){
			int buttonPushed = 0;
			int labelID;
			isPushed = true;
			for (int i = 0; i < GameBoard.NumOfColumns; i++){
				if (event.getSource() == buttonLine[i]){
					buttonPushed = i;
				}
			}
			
			/* 
			 * reach a label =
			 * 8*[number_of_rows-(number_of_disks(column)+1)]+column_id
			 */
			if (!player_board.isColumnFull(buttonPushed)){
				labelID = GameBoard.NumOfColumns*(GameBoard.NumOfRows-(player_board.getDiscsPerColumn()[buttonPushed]+1))+ buttonPushed;
				labelBoard[labelID].setIcon((color == GameBoard.BlackPlayer) ? blackDiscIcon : redDiscIcon);
				labelBoard[labelID].setHorizontalAlignment(SwingConstants.CENTER);
				player_board.insertDisc(buttonPushed, color);
				ourLastMove = buttonPushed;
				lockButtons();
			}
		}
	}
}