package jrummikub.view.impl;

import java.awt.Color;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.text.DecimalFormat;
import java.util.Collections;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;

import jrummikub.control.turn.TurnMode;
import jrummikub.model.Position;
import jrummikub.model.Stone;
import jrummikub.util.Event;
import jrummikub.util.IEvent;
import jrummikub.util.Pair;
import jrummikub.view.IPlayerPanel;

/**
 * Implementation of the player panel
 */
@SuppressWarnings("serial")
class PlayerPanel extends JPanel implements IPlayerPanel {
	private final static int SIDE_PANEL_INSET = 10;
	private final static int SIDE_PANEL_SEPARATOR = 5;
	private final static float SIDE_PANEL_FIRST_LINE_HEIGHT = 0.375f;
	private final static int SIDE_PANEL_MAX_WIDTH = 180;
	private final static float HAND_ROW_BUTTON_RATIO = 0.03f;
	private final static float MAX_BUTTON_FONT_SIZE = 12;

	private final static DecimalFormat secondFormat = new DecimalFormat("00");

	private HandPanel hand;

	private JPanel leftPanel, rightPanel;

	private JLabel currentPlayerNameLabel;
	private JLabel hasLaidOutLabel;
	private JButton sortByGroupsButton;
	private JButton sortByRunsButton;
	private JButton handRowUpButton;
	private JButton handRowDownButton;
	private JProgressBar timeBar;
	private JButton endTurnButton;
	private JButton keepStonesButton;
	private JButton redealButton;
	private JButton pauseButton;

	private Event sortByGroupsEvent = new Event();
	private Event sortByRunsEvent = new Event();
	private Event endTurnEvent = new Event();
	private Event redealEvent = new Event();
	private Event pauseEvent = new Event();
	private int leftPanelWidth;

	HandPanel getHandPanel() {
		return hand;
	}

	/**
	 * Sets the current player name
	 * 
	 * @param playerName
	 *          the player name
	 */
	void setCurrentPlayerName(String playerName) {
		currentPlayerNameLabel.setText(playerName);
	}

	void setCurrentPlayerColor(Color color) {
		currentPlayerNameLabel.setIcon(ImageUtil.createColorIcon(color, 12, 1));
	}

	void setHasLaidOut(boolean hasLaidOut) {
		if (hasLaidOut) {
			hasLaidOutLabel.setText("ist rausgekommen");
		} else {
			hasLaidOutLabel.setText("ist nicht rausgekommen");
		}
	}

	@Override
	public void setTime(int time, int totalTime) {
		timeBar.setMaximum(totalTime);
		timeBar.setValue(time);
		timeBar.setString(Integer.toString(time / 60) + ":"
				+ secondFormat.format(time % 60));

		if (time <= 10)
			timeBar.setForeground(Color.RED);
		else
			timeBar.setForeground(UIManager.getColor("ProgressBar.foreground"));
	}

	@Override
	public IEvent getSortByGroupsEvent() {
		return sortByGroupsEvent;
	}

	@Override
	public IEvent getSortByRunsEvent() {
		return sortByRunsEvent;
	}

	@Override
	public IEvent getEndTurnEvent() {
		return endTurnEvent;
	}

	@Override
	public IEvent getRedealEvent() {
		return redealEvent;
	}

	IEvent getPauseEvent() {
		return pauseEvent;
	}

	private void createLeftPanel() {
		leftPanel = new JPanel();
		leftPanel.setLayout(null);
		leftPanel.setBorder(new EmptyBorder(SIDE_PANEL_INSET, SIDE_PANEL_INSET,
				SIDE_PANEL_INSET, SIDE_PANEL_INSET));

		currentPlayerNameLabel = new JLabel();
		currentPlayerNameLabel.setHorizontalAlignment(JLabel.CENTER);
		currentPlayerNameLabel.setVerticalAlignment(JLabel.CENTER);
		currentPlayerNameLabel.putClientProperty("html.disable", Boolean.TRUE);
		leftPanel.add(currentPlayerNameLabel);

		hasLaidOutLabel = new JLabel();
		hasLaidOutLabel.setHorizontalAlignment(JLabel.CENTER);
		hasLaidOutLabel.setVerticalAlignment(JLabel.CENTER);
		leftPanel.add(hasLaidOutLabel);

		sortByGroupsButton = createButton(leftPanel,
				"<html><center>Nach Sammlungen sortieren", new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent arg0) {
						sortByGroupsEvent.emit();
					}
				});

		sortByRunsButton = createButton(leftPanel,
				"<html><center>Nach Reihen sortieren", new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent arg0) {
						sortByRunsEvent.emit();
					}
				});

		leftPanel.addComponentListener(new LeftPanelResizeListener());
	}

	private void createRightPanel() {
		rightPanel = new JPanel();
		rightPanel.setLayout(null);
		rightPanel.setBorder(new EmptyBorder(SIDE_PANEL_INSET, SIDE_PANEL_INSET,
				SIDE_PANEL_INSET, SIDE_PANEL_INSET));

		handRowUpButton = createButton(rightPanel, "<html><center>\u25B2",
				new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						hand.rowUp();
					}
				});

		handRowDownButton = createButton(rightPanel, "<html><center>\u25BC",
				new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						hand.rowDown();
					}
				});

		timeBar = new JProgressBar(0, 60);
		timeBar.setStringPainted(true);
		rightPanel.add(timeBar);

		createRightPanelButtons();

		rightPanel.addComponentListener(new RightPanelResizeListener());
	}

	private void createRightPanelButtons() {
		endTurnButton = createButton(rightPanel, "---", new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				endTurnEvent.emit();
			}
		});

		keepStonesButton = createButton(rightPanel,
				"<html><center>Steine<br>behalten", new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						endTurnEvent.emit();
					}
				});

		redealButton = createButton(rightPanel, "<html><center>Neu<br>geben",
				new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						redealEvent.emit();
					}
				});

		pauseButton = createButton(rightPanel, null, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				pauseEvent.emit();
			}
		});
	}

	private JButton createButton(JPanel panel, String caption,
			ActionListener listener) {
		JButton button = new JButton(caption);
		button.setFont(button.getFont().deriveFont(0));
		button.setMargin(new Insets(0, 0, 0, 0));
		button.addActionListener(listener);
		panel.add(button);
		return button;
	}

	void rescale() {
		Insets insets = getInsets();
		int x = insets.left, y = insets.top, width = getWidth() - insets.left
				- insets.right, height = getHeight() - insets.top - insets.bottom;
		
		int boardWidth = hand.rescale(height);
		int handButtonWidth = (int) (width * HAND_ROW_BUTTON_RATIO);
		int meanPanelWidth = (width - boardWidth) / 2;
		leftPanelWidth = meanPanelWidth - handButtonWidth / 2;
		int rightPanelWidth = meanPanelWidth + handButtonWidth / 2;

		leftPanel.setBounds(x, y, leftPanelWidth, height);
		hand.setBounds(x + leftPanelWidth, y, boardWidth, height);
		rightPanel.setBounds(x + leftPanelWidth + boardWidth, y, rightPanelWidth,
				height);

		leftPanel.validate();
		rightPanel.validate();
	}
	
	int getLeftPanelWidth() {
		return leftPanelWidth;
	}

	void updateButtons() {
		handRowUpButton.setEnabled(hand.canRowUp());
		handRowUpButton.setForeground(hand.canRowUp() ? Color.BLACK : Color.GRAY);
		handRowDownButton.setEnabled(hand.canRowDown());
		handRowDownButton.setForeground(hand.canRowDown() ? Color.BLACK
				: Color.GRAY);
	}

	/**
	 * Creates a new PlayerPanel instance
	 */
	PlayerPanel() {
		setLayout(null);

		createLeftPanel();
		add(leftPanel);

		hand = new HandPanel(this);
		add(hand);

		createRightPanel();
		add(rightPanel);
	}

	@Override
	public void setEndTurnMode(TurnMode turnMode) {

		switch (turnMode) {
			case MAY_REDEAL:
				endTurnButton.setVisible(false);
				keepStonesButton.setVisible(true);
				redealButton.setVisible(true);
				break;
			case INSPECT_ONLY:
				endTurnButton.setText("N\u00e4chster Spieler");
				endTurnButton.setVisible(true);
				keepStonesButton.setVisible(false);
				redealButton.setVisible(false);
				break;
			case NORMAL_TURN:
				endTurnButton.setText("Zug beenden");
				endTurnButton.setVisible(true);
				keepStonesButton.setVisible(false);
				redealButton.setVisible(false);
				break;
		}
	}

	void showButtons(boolean show) {
		currentPlayerNameLabel.setVisible(show);
		hasLaidOutLabel.setVisible(show);
		sortByGroupsButton.setVisible(show);
		sortByRunsButton.setVisible(show);
		timeBar.setVisible(show);
		pauseButton.setVisible(show);

		if (!show) {
			handRowDownButton.setForeground(Color.GRAY);
			handRowDownButton.setEnabled(false);
			handRowUpButton.setForeground(Color.GRAY);
			handRowUpButton.setEnabled(false);
			endTurnButton.setVisible(false);
			redealButton.setVisible(false);
			keepStonesButton.setVisible(false);
		}
	}

	void enableButtons(boolean enable) {
		sortByGroupsButton.setEnabled(enable);
		sortByRunsButton.setEnabled(enable);
		if (!enable) {
			setEndTurnMode(TurnMode.NORMAL_TURN);
			endTurnButton.setText("<html><center>Spieler denkt nach");
			hand.setStones(Collections.<Pair<Stone, Position>> emptyList());
			handRowDownButton.setForeground(Color.GRAY);
			handRowDownButton.setEnabled(false);
			handRowUpButton.setForeground(Color.GRAY);
			handRowUpButton.setEnabled(false);
		}
		endTurnButton.setEnabled(enable);
		redealButton.setEnabled(enable);
		keepStonesButton.setEnabled(enable);
		hand.setEnabled(enable);
	}

	private class LeftPanelResizeListener extends ComponentAdapter {
		@Override
		public void componentResized(ComponentEvent e) {
			Insets insets = leftPanel.getInsets();
			int x = insets.left, y = insets.top, width = leftPanel.getWidth()
					- insets.left - insets.right, height = leftPanel.getHeight()
					- insets.top - insets.bottom;

			if (width > SIDE_PANEL_MAX_WIDTH) {
				x += (width - SIDE_PANEL_MAX_WIDTH) / 4;
				width = width / 2 + SIDE_PANEL_MAX_WIDTH / 2;
			}

			int labelHeight = (int) ((height - SIDE_PANEL_SEPARATOR) * SIDE_PANEL_FIRST_LINE_HEIGHT);
			int oneLabelHeight = labelHeight / 2;
			int buttonWidth = (width - SIDE_PANEL_SEPARATOR) / 2;
			int buttonHeight = height - SIDE_PANEL_SEPARATOR - labelHeight;
			float fontSize = (float) Math.sqrt(buttonWidth * buttonHeight) / 6;
			if (fontSize > MAX_BUTTON_FONT_SIZE)
				fontSize = MAX_BUTTON_FONT_SIZE;

			currentPlayerNameLabel.setBounds(x, y, width, oneLabelHeight);
			hasLaidOutLabel.setBounds(x, y + oneLabelHeight, width, oneLabelHeight);
			sortByGroupsButton.setBounds(x, y + labelHeight + SIDE_PANEL_SEPARATOR,
					buttonWidth, buttonHeight);
			sortByRunsButton.setBounds(x + buttonWidth + SIDE_PANEL_SEPARATOR, y
					+ labelHeight + SIDE_PANEL_SEPARATOR, buttonWidth, buttonHeight);

			currentPlayerNameLabel.setFont(currentPlayerNameLabel.getFont()
					.deriveFont(fontSize));
			hasLaidOutLabel.setFont(hasLaidOutLabel.getFont().deriveFont(fontSize));
			sortByGroupsButton.setFont(sortByGroupsButton.getFont().deriveFont(
					fontSize));
			sortByRunsButton.setFont(sortByRunsButton.getFont().deriveFont(fontSize));
		}
	}

	private class RightPanelResizeListener extends ComponentAdapter {
		@Override
		public void componentResized(ComponentEvent e) {
			int handButtonWidth = (int) (getWidth() * HAND_ROW_BUTTON_RATIO);

			Insets insets = rightPanel.getInsets();
			int x = insets.left + handButtonWidth, y = insets.top, width = rightPanel
					.getWidth() - insets.left - insets.right - handButtonWidth, height = rightPanel
					.getHeight() - insets.top - insets.bottom;

			if (width > SIDE_PANEL_MAX_WIDTH) {
				x += (width - SIDE_PANEL_MAX_WIDTH) / 4;
				width = width / 2 + SIDE_PANEL_MAX_WIDTH / 2;
			}

			int firstLineHeight = (int) ((height - SIDE_PANEL_SEPARATOR) * SIDE_PANEL_FIRST_LINE_HEIGHT);
			int buttonWidth = width;
			int smallButtonWidth = (width - SIDE_PANEL_SEPARATOR) / 2;
			int buttonHeight = height - SIDE_PANEL_SEPARATOR - firstLineHeight;
			float fontSize = (float) Math.sqrt(buttonWidth * buttonHeight) / 5;
			float smallFontSize = (float) Math.sqrt(smallButtonWidth * buttonHeight) / 5;
			if (fontSize > MAX_BUTTON_FONT_SIZE) {
				fontSize = MAX_BUTTON_FONT_SIZE;
			}
			if (smallFontSize > MAX_BUTTON_FONT_SIZE) {
				smallFontSize = MAX_BUTTON_FONT_SIZE;
			}

			rescaleUpDownButtons(handButtonWidth, fontSize);

			rescaleTimeBar(x, y, width, firstLineHeight);

			endTurnButton.setBounds(x, y + firstLineHeight + SIDE_PANEL_SEPARATOR,
					buttonWidth, buttonHeight);
			endTurnButton.setFont(endTurnButton.getFont().deriveFont(fontSize));

			redealButton.setBounds(x, y + firstLineHeight + SIDE_PANEL_SEPARATOR,
					smallButtonWidth, buttonHeight);
			redealButton.setFont(redealButton.getFont().deriveFont(smallFontSize));
			keepStonesButton.setBounds(x + smallButtonWidth + SIDE_PANEL_SEPARATOR, y
					+ firstLineHeight + SIDE_PANEL_SEPARATOR, smallButtonWidth,
					buttonHeight);
			keepStonesButton.setFont(keepStonesButton.getFont().deriveFont(
					smallFontSize));

		}

		private void rescaleTimeBar(int x, int y, int width, int firstLineHeight) {
			timeBar.setBounds(x, y, width - firstLineHeight - SIDE_PANEL_SEPARATOR,
					firstLineHeight);
			pauseButton.setBounds(x + width - firstLineHeight, y, firstLineHeight,
					firstLineHeight);
			pauseButton.setIcon(ImageUtil
					.createPauseIcon((int) (firstLineHeight * 0.5f)));
		}

		private void rescaleUpDownButtons(int handButtonWidth, float fontSize) {
			handRowUpButton.setBounds(0, 0, handButtonWidth, getHeight() / 2);
			handRowUpButton.setFont(handRowUpButton.getFont().deriveFont(
					fontSize * 1.5f));
			handRowDownButton.setBounds(0, getHeight() / 2, handButtonWidth,
					getHeight() / 2);
			handRowDownButton.setFont(handRowDownButton.getFont().deriveFont(
					fontSize * 1.5f));
		}
	}
}
