/*
 *   Author: Florian Fink, 2014
 *   Based on Code by: veqryn
 *   
 *   This project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
 *
 *   This project is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License along with this project. If not, see http://www.gnu.org/licenses/.
 */
package usergames.othello;

import games.strategy.common.delegate.BaseEditDelegate;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.engine.gamePlayer.IPlayerBridge;
import games.strategy.grid.ui.GridGameFrame;
import games.strategy.grid.ui.GridMapData;
import games.strategy.grid.ui.GridMapPanel;
import games.strategy.grid.ui.GridPlayData;
import games.strategy.grid.ui.IGridPlayData;
import games.strategy.triplea.ui.MouseDetails;
import games.strategy.ui.ImageScrollModel;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

import usergames.othello.othelloDelegate.PlayDelegate;

/**
 * The map panel for the game Othello
 * based on GoMapPanel by veqryn
 */
public class OthelloMapPanel extends GridMapPanel {

	private static final long serialVersionUID = 4046925399892120183L;

	public OthelloMapPanel(GameData data, GridMapData mapData,
			GridGameFrame parentGridGameFrame, ImageScrollModel imageScrollModel) {
		super(data, mapData, parentGridGameFrame, imageScrollModel);
	}

	@Override
	protected Collection<Territory> getCapturesForPlay(IGridPlayData play) {
		return PlayDelegate.checkForCaptures(play,
				m_parentGridGameFrame.getActivePlayer(), m_gameData);
	}

	@Override
	protected String isValidPlay(IGridPlayData play) {
		final String error;
		try {
			m_gameData.acquireReadLock();
			error = PlayDelegate.isValidPlay(play,
					m_parentGridGameFrame.getActivePlayer(), m_gameData);
		} finally {
			m_gameData.releaseReadLock();
		}
		return error;
	}

	// draw map and pieces
	@Override
	protected void paintComponentMiddleLayer(Graphics2D g2d, int topLeftX,
			int topLeftY) {

		g2d.setColor(Color.black);
		g2d.fillRect(0, 0, m_model.getMaxWidth(), m_model.getMaxHeight());
		
		int r= m_gameData.getProperties().get("Board Color Red",128);
		int g= m_gameData.getProperties().get("Board Color Green",255);
		int b= m_gameData.getProperties().get("Board Color Blue",128);
		
		final Color tilecolor = new Color(r, g, b);
		final int maxX = m_gameData.getMap().getXDimension() - 1;
		final int maxY = m_gameData.getMap().getYDimension() - 1;

		// draw the board
		for (final Map.Entry<Territory, Polygon> entry : m_mapData
				.getTerritoryPolygons(m_gameData.getMap()).entrySet()) {
			final Polygon p = entry.getValue();
			final Territory at = entry.getKey();
			if (at == null || p == null)
				continue;
			final Color backgroundColor;
			backgroundColor = tilecolor;
			g2d.setColor(backgroundColor);
			g2d.fillPolygon(p);

			g2d.setColor(Color.black);

			if (at.getY() != 0 && at.getX() != 0)
				g2d.drawPolygon(p);
			if (at.getY() != 0 && at.getX() != maxX)
				g2d.drawPolygon(p);
			if (at.getY() != maxY && at.getX() != maxX)
				g2d.drawPolygon(p);
			if (at.getY() != maxY && at.getX() != 0)
				g2d.drawPolygon(p);

		}

		// draw stones
		for (final Map.Entry<Territory, Polygon> entry : m_mapData
				.getTerritoryPolygons(m_gameData.getMap()).entrySet()) {
			final Polygon p = entry.getValue();
			final Territory at = entry.getKey();
			if (at == null || p == null)
				continue;
			// now draw the units
			final Image image = m_images.get(at);
			if (image != null) {
				final Rectangle square = p.getBounds();
				g2d.drawImage(image, square.x, square.y, square.width,
						square.height, null, null);
			}
		}

	}

	@Override
	public void mousePressed(final MouseEvent e) {

		m_clickedAt = m_mapData.getTerritoryAt(e.getX() + m_model.getX(),
				e.getY() + m_model.getY(), m_gameData.getMap());
		
	}

	@Override
	public void mouseReleased(final MouseEvent e) {
		final Territory at = m_mapData.getTerritoryAt(
				e.getX() + m_model.getX(), e.getY() + m_model.getY(),
				m_gameData.getMap());
		
		if (at != null)
			notifyTerritorySelected(at, new MouseDetails(e, e.getX(), e.getY()));
		if (BaseEditDelegate.getEditMode(m_gameData))
			return;

		if (m_waiting != null && (m_clickedAt != null)) {
			m_waiting.countDown();
		}
	}
	
	public GridPlayData waitForPlay(final PlayerID player, final IPlayerBridge bridge, final CountDownLatch waiting) throws InterruptedException
	{
		// Make sure we have a valid CountDownLatch.
		if (waiting == null || waiting.getCount() != 1)
			throw new IllegalArgumentException("CountDownLatch must be non-null and have getCount()==1");
		// The mouse listeners need access to the CountDownLatch, so store as a member variable.
		m_waiting = waiting;
		
		boolean hasToPass=PlayDelegate.getAllPossibleMoves(player, m_gameData).isEmpty();
		
		// Wait for a play or an attempt to leave the game
		this.updateAllImages();
		if(!hasToPass){
			m_waiting.await();
		}
		if (m_clickedAt == null && !hasToPass)
		{
			// If either m_clickedAt==null or m_releasedAt==null,
			// the play is invalid and must have been interrupted.
			// So, reset the member variables, and throw an exception.
			m_clickedAt = null;
			throw new InterruptedException("Interrupted while waiting for play.");
		}
		else
		{
			// We have a valid play!
			// Reset the member variables, and return the play.
			final GridPlayData play;
			if(hasToPass){
				play=new GridPlayData(true, player);
			}
			else{
				play = new GridPlayData(m_clickedAt, player);
			}
			m_clickedAt = null;
			return play;
		}
	}

	@Override
	protected MouseMotionListener getMouseMotionListener() {
		return new MouseMotionAdapter() {
			// do nothing
		};
	}

	@Override
	public void setMouseShadowUnits(final Collection<Unit> units) {
		// do nothing
	}

}
