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.awt.event.ComponentListener;
import java.text.DecimalFormat;

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

import jrummikub.util.Event;
import jrummikub.util.IEvent;
import jrummikub.view.IPlayerPanel;

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

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

  private Board board;

  private JPanel leftPanel, rightPanel;

  private JLabel currentPlayerNameLabel;
  private JButton sortByNumberButton;
  private JButton sortByColorButton;
  private JProgressBar timeBar;
  private JButton endTurnButton;

  private Event sortByNumberEvent = new Event();
  private Event sortByColorEvent = new Event();
  private Event endTurnEvent = new Event();

  @Override
  public Board getBoard() {
    return board;
  }

  @Override
  public void setCurrentPlayerName(String playerName) {
    currentPlayerNameLabel.setText(playerName);
  }

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

  @Override
  public IEvent getSortByNumberEvent() {
    return sortByNumberEvent;
  }

  @Override
  public IEvent getSortByColorEvent() {
    return sortByColorEvent;
  }

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

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

    currentPlayerNameLabel = new JLabel();
    currentPlayerNameLabel.setHorizontalAlignment(JLabel.CENTER);
    currentPlayerNameLabel.setHorizontalTextPosition(JLabel.CENTER);
    currentPlayerNameLabel.setVerticalAlignment(JLabel.CENTER);
    currentPlayerNameLabel.setVerticalTextPosition(JLabel.CENTER);
    leftPanel.add(currentPlayerNameLabel);

    sortByNumberButton = new JButton("<html><center>Sort by number");
    sortByNumberButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        sortByNumberEvent.fire();
      }
    });
    leftPanel.add(sortByNumberButton);

    sortByColorButton = new JButton("<html><center>Sort by color");
    sortByColorButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        sortByColorEvent.fire();
      }
    });
    leftPanel.add(sortByColorButton);

    leftPanel.addComponentListener(new LeftPanelResizeListener());
  }

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

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

    endTurnButton = new JButton("End turn");
    endTurnButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        endTurnEvent.fire();
      }
    });

    rightPanel.add(endTurnButton);

    rightPanel.addComponentListener(new RightPanelResizeListener());
  }

  private 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 = board.getWidth();
    int panelWidth = (width - boardWidth) / 2;

    leftPanel.setBounds(x, y, panelWidth, height);
    board.setBounds(x + panelWidth, y, boardWidth, height);
    rightPanel.setBounds(x + panelWidth + boardWidth, y, panelWidth, height);

    leftPanel.validate();
    rightPanel.validate();
  }

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

    setBackground(Color.LIGHT_GRAY);

    createLeftPanel();
    add(leftPanel);

    board = new Board();
    add(board);

    createRightPanel();
    add(rightPanel);

    ComponentListener rescaleListener = new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        rescale();
      }
    };

    addComponentListener(rescaleListener);
    board.addComponentListener(rescaleListener);
  }

  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 firstLineHeight = (int) ((height - SIDE_PANEL_SEPARATOR) * SIDE_PANEL_FIRST_LINE_HEIGHT);
      int buttonWidth = (width - SIDE_PANEL_SEPARATOR) / 2;
      int buttonHeight = height - SIDE_PANEL_SEPARATOR - firstLineHeight;
      float fontSize = (float) Math.sqrt(buttonWidth * buttonHeight) / 5;
      if (fontSize > MAX_BUTTON_FONT_SIZE)
        fontSize = MAX_BUTTON_FONT_SIZE;

      currentPlayerNameLabel.setBounds(x, y, width, firstLineHeight);
      sortByNumberButton.setBounds(x, y + firstLineHeight
          + SIDE_PANEL_SEPARATOR, buttonWidth, buttonHeight);
      sortByColorButton.setBounds(x + buttonWidth + SIDE_PANEL_SEPARATOR, y
          + firstLineHeight + SIDE_PANEL_SEPARATOR, buttonWidth, buttonHeight);

      sortByNumberButton.setFont(sortByNumberButton.getFont().deriveFont(
          fontSize));
      sortByColorButton.setFont(sortByColorButton.getFont()
          .deriveFont(fontSize));
    }
  }

  private class RightPanelResizeListener extends ComponentAdapter {
    @Override
    public void componentResized(ComponentEvent e) {
      Insets insets = rightPanel.getInsets();
      int x = insets.left, y = insets.top, width = rightPanel.getWidth()
          - insets.left - insets.right, 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 buttonHeight = height - SIDE_PANEL_SEPARATOR - firstLineHeight;
      float fontSize = (float) Math.sqrt(buttonWidth * buttonHeight) / 5;
      if (fontSize > MAX_BUTTON_FONT_SIZE)
        fontSize = MAX_BUTTON_FONT_SIZE;

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