package jrummikub.view.impl;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollBar;
import javax.swing.JViewport;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;

import jrummikub.model.GameSettings;
import jrummikub.model.IPlayer;
import jrummikub.model.PlayerSettings;
import jrummikub.view.ISidePanel;

@SuppressWarnings("serial")
class SidePanel extends JPanel implements ISidePanel {
	// private InfoPanel infoPanel;
	private PlayerListPanel playerListPanel;
	private BottomScrollPane playerListScrollPane;
	private JLabel initialMeldLabel;
	private JLabel setNumberLabel;
	private JLabel highestValueLabel;
	private JLabel handStonesLabel;
	private JLabel jokerLabel;
	private JLabel noLimitsLabel;
	private JLabel colorLabel;
	private JProgressBar heapBar;
	private GameSettings gameSettings;

	SidePanel() {
		setLayout(new GridBagLayout());

		GridBagConstraints c = new GridBagConstraints();

		InfoPanel infoPanel = new InfoPanel(createGameInfoPanel(),
				createRuleInfoPanel());
		c.gridx = 0;
		c.gridy = 0;
		c.weightx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		infoPanel.setBorder(new MatteBorder(0, 0, 1, 0, Color.GRAY));
		add(infoPanel, c);

		playerListPanel = new PlayerListPanel();
		c.gridx = 0;
		c.gridy = 1;
		c.weighty = 1;
		c.weightx = 1;
		c.fill = GridBagConstraints.BOTH;

		playerListScrollPane = new BottomScrollPane(playerListPanel);

		add(playerListScrollPane, c);

	}

	@Override
	public void setGameSettings(GameSettings settings) {
		gameSettings = settings;
		initialMeldLabel.setText("" + settings.getInitialMeldThreshold());
		setNumberLabel.setText("" + settings.getStoneSetNumber());
		highestValueLabel.setText("1 - " + settings.getHighestValue());
		handStonesLabel.setText("" + settings.getNumberOfStonesDealt());
		jokerLabel.setText("" + settings.getJokerNumber());
		colorLabel.setText("" + settings.getStoneColors().size());
		noLimitsLabel.setVisible(settings.isNoLimits());
	}

	@Override
	public void setHeapCapacity(int capacity) {
		heapBar.setMaximum(capacity);
	}

	@Override
	public void setHeapSize(int size) {
		heapBar.setValue(size);
		if (size > 0) {
			heapBar.setIndeterminate(false);
			heapBar.setString("" + size);
		} else {
			heapBar.setIndeterminate(true);
			heapBar.setString("leer");
		}
	}

	private JPanel createGameInfoPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout());

		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 0;
		c.anchor = GridBagConstraints.WEST;
		panel.add(new JLabel("Stapel: "), c);
		c.gridx = 1;
		c.weightx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		heapBar = new JProgressBar();
		heapBar.setPreferredSize(new Dimension(16, 16));
		panel.add(heapBar, c);

		heapBar.setStringPainted(true);

		return panel;
	}

	private JPanel createRuleInfoPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout());
		initialMeldLabel = createRuleLine(panel, "Auslegeschranke", 0);
		setNumberLabel = createRuleLine(panel, "Steins\u00e4tze", 1);
		highestValueLabel = createRuleLine(panel, "Steinwert", 2);
		handStonesLabel = createRuleLine(panel, "Startsteine", 3);
		jokerLabel = createRuleLine(panel, "Joker", 4);
		colorLabel = createRuleLine(panel, "Farben", 5);

		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 6;
		c.gridwidth = 2;
		c.weightx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.anchor = GridBagConstraints.CENTER;
		noLimitsLabel = new JLabel("No Limits");
		noLimitsLabel.setHorizontalAlignment(SwingConstants.CENTER);
		panel.add(noLimitsLabel, c);

		return panel;
	}

	private JLabel createRuleLine(JPanel panel, String name, int line) {
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = line;
		c.weightx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.anchor = GridBagConstraints.WEST;
		JLabel nameLabel = new JLabel(name + ": ");
		nameLabel.setPreferredSize(new Dimension(0, nameLabel
				.getPreferredSize().height));
		panel.add(nameLabel, c);
		JLabel label = new JLabel("");
		label.setHorizontalAlignment(SwingConstants.RIGHT);
		c.weightx = 0;
		c.gridx = 1;
		c.anchor = GridBagConstraints.EAST;
		panel.add(label, c);
		return label;
	}

	class BottomScrollPane extends JPanel {
		JComponent content;
		JViewport viewport;
		JScrollBar scrollBar;
		boolean scrollToBottom;

		public BottomScrollPane(JComponent content) {
			setLayout(new GridBagLayout());
			GridBagConstraints c = new GridBagConstraints();
			c.weightx = 1;
			c.weighty = 1;
			c.fill = GridBagConstraints.BOTH;
			viewport = new JViewport();
			add(viewport, c);
			this.content = content;
			viewport.setView(content);
			scrollBar = new JScrollBar(JScrollBar.VERTICAL);
			scrollBar.setBorder(new LineBorder(Color.BLACK, 0));
			c.weightx = 0;
			add(scrollBar, c);

			ComponentAdapter resizeListener = new ComponentAdapter() {
				@Override
				public void componentResized(ComponentEvent e) {
					onResize();
				}
			};

			addComponentListener(resizeListener);

			content.addComponentListener(resizeListener);

			scrollBar.addAdjustmentListener(new AdjustmentListener() {
				@Override
				public void adjustmentValueChanged(AdjustmentEvent arg0) {
					scrollViewport();
				}
			});
			scrollToBottom();
		}

		void scrollToBottom() {
			scrollToBottom = true;
		}

		private void onResize() {
			int oldValue = 0;
			if (!scrollToBottom) {
				oldValue = scrollBar.getMaximum()
						- scrollBar.getVisibleAmount() - scrollBar.getValue();
			}
			scrollToBottom = false;

			int max = content.getHeight();
			int extent = viewport.getHeight();
			int value = Math.max(0, max - extent - oldValue);
			scrollBar.setVisible(extent != max);
			scrollBar.setValues(value, extent, 0, max);
			scrollViewport();
		}

		private void scrollViewport() {
			viewport.setViewPosition(new Point(0, scrollBar.getValue()));
		}
	}

	static class InfoPanel extends JPanel {
		JPanel ruleInfoPanel;
		JPanel gameInfoPanel;
		JCheckBox showRules;
		JProgressBar heapBar;

		InfoPanel(JPanel gameInfo, JPanel ruleInfo) {
			ruleInfoPanel = ruleInfo;
			gameInfoPanel = gameInfo;
			setLayout(new GridBagLayout());
			GridBagConstraints c = new GridBagConstraints();
			c.gridx = 0;
			c.weightx = 1;
			c.fill = GridBagConstraints.HORIZONTAL;
			c.anchor = GridBagConstraints.WEST;

			c.insets = new Insets(4, 8, 4, 8);
			add(gameInfoPanel, c);

			showRules = new JCheckBox("Regeln");
			showRules.setSelected(true);
			setupTriangleIcons(showRules);
			c.insets = new Insets(0, 4, 0, 4);
			add(showRules, c);

			showRules.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg) {
					boolean selected = showRules.isSelected();
					ruleInfoPanel.setVisible(selected);
					showRules.setPressedIcon(selected ? showRules.getIcon()
							: showRules.getSelectedIcon());
				}
			});

			c.insets = new Insets(4, 8, 4, 8);
			add(ruleInfoPanel, c);
		}

		private void setupTriangleIcons(JCheckBox test) {
			BufferedImage img1 = new BufferedImage(8, 8,
					BufferedImage.TYPE_3BYTE_BGR);
			BufferedImage img2 = new BufferedImage(8, 8,
					BufferedImage.TYPE_3BYTE_BGR);

			Graphics2D g = img1.createGraphics();

			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
			g.setColor(getBackground());
			g.fillRect(0, 0, 8, 8);
			g.setColor(Color.BLACK);

			Polygon p = new Polygon();
			p.addPoint(0, 0);
			p.addPoint(8, 4);
			p.addPoint(0, 8);
			g.fillPolygon(p);

			g = img2.createGraphics();

			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
			g.setColor(getBackground());
			g.fillRect(0, 0, 8, 8);
			g.setColor(Color.BLACK);

			p = new Polygon();
			p.addPoint(0, 0);
			p.addPoint(4, 8);
			p.addPoint(8, 0);
			g.fillPolygon(p);

			test.setIcon(new ImageIcon(img1));
			test.setSelectedIcon(new ImageIcon(img2));
			test.setPressedIcon(new ImageIcon(img1));
			test.setRolloverEnabled(false);
			test.setFocusPainted(false);
		}
	}

	class PlayerListItem extends JPanel {
		PlayerListItem(IPlayer player) {
			setLayout(new GridBagLayout());
			setBorder(new EmptyBorder(0, 4, 0, 4));
			PlayerSettings settings = player.getPlayerSettings();

			GridBagConstraints c = new GridBagConstraints();
			c.gridx = 1;
			c.gridy = 0;
			c.gridheight = 1;
			c.gridwidth = 2;
			c.weightx = 1;
			c.fill = GridBagConstraints.HORIZONTAL;
			c.insets = new Insets(4, 2, 0, 2);

			JLabel playerName = new JLabel(settings.getName());
			playerName.setIcon(ImageUtil.createColorIcon(settings.getColor(),
					12, 1));
			playerName.putClientProperty("html.disable", Boolean.TRUE);
			add(playerName, c);

			addLastTurnInfo(player);

			if (gameSettings.getSeeHandSize()) {
				addHandSizeInfo(player);
			}
		}

		private void addLastTurnInfo(IPlayer player) {
			GridBagConstraints c = new GridBagConstraints();
			c.gridwidth = 2;
			c.weightx = 1;
			c.fill = GridBagConstraints.HORIZONTAL;
			c.insets = new Insets(2, 2, 2, 2);
			c.gridx = 1;
			c.gridy = 1;
			c.anchor = GridBagConstraints.WEST;
			String status = "Stein gezogen";
			if (player.wasLastTurnInvalid()) {
				status = "ungültiger Zug";
				if (!player.getLaidOut()) {
					status = "ungültig, nicht rausgekommen";
				}
			} else {
				if (!player.getLaidOut()) {
					status = "nicht rausgekommen";
				} else if (player.getLastTurnStoneCount() == 1) {
					status = "1 Stein abgelegt";
				} else if (player.getLastTurnStoneCount() > 1) {
					status = player.getLastTurnStoneCount()
							+ " Steine abgelegt";
				}
			}

			JLabel playerStatus = new JLabel(status);
			add(playerStatus, c);
		}

		private void addHandSizeInfo(IPlayer player) {
			JLabel handSizeLabel = new JLabel("Handsteine: ");
			JLabel handSizeInfo = new JLabel("" + player.getHand().getSize());
			GridBagConstraints c = new GridBagConstraints();
			c.gridx = 1;
			c.gridy = 2;
			c.weightx = 1;
			c.gridwidth = 1;
			c.insets = new Insets(2, 2, 2, 2);
			c.anchor = GridBagConstraints.WEST;
			add(handSizeLabel, c);

			c.gridx = 2;
			c.weightx = 0;
			c.insets = new Insets(2, 4, 2, 4);
			c.anchor = GridBagConstraints.EAST;
			add(handSizeInfo, c);
		}
	}

	class PlayerListPanel extends JPanel {
		JPanel startSpacer;
		List<PlayerListItem> listItems = new ArrayList<PlayerListItem>();

		PlayerListPanel() {
			setBackground(Color.GRAY);
			setLayout(new GridBagLayout());

			GridBagConstraints c = new GridBagConstraints();
			startSpacer = new JPanel();
			startSpacer.setBackground(Color.GRAY);
			startSpacer.setPreferredSize(new Dimension(0, 0));
			c.gridx = 0;
			c.gridy = 0;
			c.weightx = 1;
			c.weighty = 1;
			c.fill = GridBagConstraints.BOTH;
			add(startSpacer, c);

		}

		void setPlayers(List<IPlayer> players) {
			for (PlayerListItem item : listItems) {
				remove(item);
			}
			listItems.clear();
			GridBagConstraints c = new GridBagConstraints();
			c.gridx = 0;
			c.gridy = 0;
			c.weightx = 1;
			c.fill = GridBagConstraints.HORIZONTAL;
			for (IPlayer player : players) {
				c.gridy++;
				c.insets = new Insets(c.gridy == 1 ? 0 : 1, 0, 0, 0);
				PlayerListItem item = new PlayerListItem(player);
				listItems.add(item);
				add(item, c);
			}
		}

		@Override
		public Dimension getPreferredSize() {
			Dimension oldPref = super.getPreferredSize();
			return new Dimension(0, oldPref.height);
		}
	}

	@Override
	public void setPlayers(List<IPlayer> players) {
		playerListPanel.setPlayers(players);

	}

}
