package pdp.scrabble.ihm.action.impl;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import pdp.scrabble.Game;
import pdp.scrabble.game.Bag;
import pdp.scrabble.game.GameEnvironment;
import pdp.scrabble.game.Letter;
import pdp.scrabble.game.Placement;
import pdp.scrabble.game.Player;
import pdp.scrabble.game.Rack;
import pdp.scrabble.game.SearchStrategy;
import pdp.scrabble.game.impl.AIConfigImpl;
import pdp.scrabble.game.SearchLevel;
import pdp.scrabble.game.AIConfig;
import pdp.scrabble.game.exception.BoardWrongWordPlace;
import pdp.scrabble.game.SearchPriority;
import pdp.scrabble.ihm.PlayerPanel;
import pdp.scrabble.ihm.action.PlayerAction;
import pdp.scrabble.utility.Debug;
import pdp.scrabble.utility.Display;
import pdp.scrabble.utility.Tool;
import static pdp.scrabble.Language.getGameLang;
import static pdp.scrabble.game.BoardCase.CASE_SIZE;
import static javax.swing.JOptionPane.QUESTION_MESSAGE;
import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
/**
*/
public class PlayerActionImpl
implements PlayerAction, MouseListener, MouseMotionListener {
/** Help actions. */
private static String[] Helps = {
getGameLang("Display rack word list"),
getGameLang("Suggest on board location")
};
/** Panel reference. */
private PlayerPanel panel = null;
/** Game reference. */
private GameEnvironment game = null;
/** Player reference which is playing. */
private Player player = null;
/** Selected letter reference. */
private Letter selectedLetter = null;
/** Selected letters for reset. */
private List<Integer> selectionToReset = new ArrayList<Integer>(7);
/** Letters index selection for switch. */
private int select1 = 0, select2 = 0;
/** Mouse cursor. */
private int mx = 0, my = 0;
/** Create a new player action.
* @param panel panel parent.
* @param game game reference.
*/
public PlayerActionImpl(PlayerPanel panel, GameEnvironment game) {
this.panel = panel;
this.game = game;
}
private void continueGame() {
synchronized (Game.MONITOR) {
Game.MONITOR.notify();
}
}
@Override
public void validate() {
try {
if (this.game.mainFrame().getGameSelection() != 2) {
this.player.validate();
this.player.getRack().fill();
this.panel.getButton("Validate").setEnabled(false);
this.panel.getButton("Cancel").setEnabled(false);
this.panel.getButton("Reset").setEnabled(false);
this.panel.getButton("Help").setEnabled(false);
this.panel.getButton("Game Over").setEnabled(true);
this.player.endTurn(true);
this.game.mainFrame().repaint();
}
}
catch (BoardWrongWordPlace bwwp) {
bwwp.show();
this.player.cancel();
this.panel.getButton("Validate").setEnabled(false);
this.panel.getButton("Cancel").setEnabled(false);
this.panel.getButton("Help").setEnabled(true);
}
this.panel.repaint();
this.continueGame();
}
@Override
public void cancel() {
this.player.cancel();
this.panel.getButton("Cancel").setEnabled(false);
this.panel.getButton("Validate").setEnabled(false);
this.panel.getButton("Reset").setEnabled(false);
this.panel.getButton("Game Over").setEnabled(true);
this.panel.repaint();
}
@Override
public void pick() {
this.player.getRack().fill();
}
@Override
public void reset() {
this.player.resetSelectedLettersRack(this.getLettersToReset());
this.panel.getButton("Reset").setEnabled(false);
this.clearLettersToReset();
this.cancel();
this.player.endTurn(true);
this.continueGame();
}
@Override
public void help() {
Object result = JOptionPane.showInputDialog(
null, getGameLang("Select help type:"), getGameLang("Help"),
QUESTION_MESSAGE, null, PlayerActionImpl.Helps, 0);
if (result != null) {
String help = (String) result;
// Displays all possible words on rack
if (help.equals(PlayerActionImpl.Helps[0])) {
this.player.resolution().showPossibilities(
this.player.getRackLettersName());
} // Suggest the best placement
else if (help.equals(PlayerActionImpl.Helps[1])) {
SearchLevel[] levels = SearchLevel.values();
String[] values = new String[levels.length];
for (int i = 0; i < levels.length; i++) {
values[i] = Tool.capitalize(levels[i].name());
}
String value = (String) JOptionPane.showInputDialog(
null, getGameLang("Select level:"),
getGameLang("Search level"), QUESTION_MESSAGE,
null, values, 0);
if (value == null) {
return;
}
SearchLevel level = SearchLevel.valueOf(value.toUpperCase());
SearchStrategy[] strategys = SearchStrategy.values();
values = new String[strategys.length];
for (int i = 0; i < strategys.length; i++) {
values[i] = Tool.capitalize(strategys[i].name());
}
value = (String) JOptionPane.showInputDialog(
null, getGameLang("Select strategy:"),
getGameLang("Search strategy"), QUESTION_MESSAGE,
null, values, 0);
if (value == null) {
return;
}
SearchStrategy strategy = SearchStrategy.valueOf(
value.toUpperCase());
SearchPriority priority = SearchPriority.HIGHER_SCORE;
AIConfig config = new AIConfigImpl(level, strategy, priority);
List<Letter> required = this.getLetterList(
"Enter the list of letter to use:");
List<Letter> excluded = this.getLetterList(
"Enter the list of excluded letter:");
this.startBestPlacementSearch(config, required, excluded);
}
}
this.panel.repaint();
}
/** Get a list of letter from string containing letter chars.
* @param message concatened letter chars.
* @return list of letters.
*/
private List<Letter> getLetterList(String message) {
List<Letter> letterList = null;
String list = JOptionPane.showInputDialog(getGameLang(message));
if (list != null && !list.isEmpty()) {
letterList = new ArrayList<Letter>(1);
int len = list.length();
Letter letter = null;
if (len > 0 && len <= Rack.MAX_RACK_LETTERS) {
for (int i = 0; i < len; i++) {
letter = this.player.getRack().getLetter(list.charAt(i));
if (letter != null) {
letterList.add(letter);
}
}
}
}
list = null;
return letterList;
}
/** Start to search the best placement using a strategy.
* @param priority search priority.
*/
private void startBestPlacementSearch(
AIConfig config, List<Letter> required, List<Letter> excluded) {
Placement best = this.player.resolution().suggestPlacement(
this.player, config, required, excluded);
if (best != null) {
Debug.console("help", "best placement", best.toString());
best.applyActions(this.player, this.game.board());
best.clearActions();
this.panel.getButton("Validate").setEnabled(true);
this.panel.getButton("Cancel").setEnabled(true);
}
else {
Display.information("Help", "Sorry, no placement found !");
}
if (required != null) {
required.clear();
}
if (excluded != null) {
excluded.clear();
}
this.game.repaint();
}
@Override
public void rules() {
this.game.mainFrame().getMenubar().getAction().rules();
}
@Override
public void gameOver() {
this.continueGame();
this.game.terminate();
}
@Override
public void setPlayer(Player player) {
this.player = player;
}
@Override
public Player getPlayer() {
return this.player;
}
@Override
public void setSelectedLetter(Letter letter) {
this.selectedLetter = letter;
}
@Override
public Letter getSelectedLetter() {
return this.selectedLetter;
}
@Override
public List<Integer> getLettersToReset() {
return Collections.unmodifiableList(this.selectionToReset);
}
@Override
public void clearLettersToReset() {
this.selectionToReset.clear();
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
this.update(e);
// Check each letter
if (this.player != null && !this.panel.isLocked()) {
int ox = 26;
int oy = 4;
for (int i = 0; i < Rack.MAX_RACK_LETTERS; i++) {
int x = 16 + ox + i * 64;
int y = 16 + oy;
// Selected letter
if (e.getButton() == MouseEvent.BUTTON1) {
this.panel.getButton("Reset").setEnabled(false);
this.selectLettersForDrop(x, y, i);
}
// Selected letters for reset
if (e.getButton() == MouseEvent.BUTTON3) {
this.selectLettersForReset(x, y, i);
}
// God Mod disabled
if (e.getButton() == MouseEvent.BUTTON2) {
// this.godMod(x, y, i);
}
}
}
}
/** Select letters in order to drop them on board.
* @param x mouse x.
* @param y mouse y.
* @param i current letter index.
*/
private void selectLettersForDrop(int x, int y, int i) {
if (!this.panel.isLocked()) {
if (this.getMouseX() >= x && this.getMouseX() <= x + CASE_SIZE
&& this.getMouseY() >= y && this.getMouseY() <= y + CASE_SIZE) {
// Is selecting
if (this.player.getSelection() == 0) {
if (this.player.getRack().getLetter(i) != null) {
this.select1 = i;
this.player.setSelection(1);
this.player.setSelectedLetter(this.player.getRack().getLetter(i));
}
} // Has selected, can switch
else if (this.player.getSelection() == 1) {
this.select2 = i;
this.player.switchLetters(this.select1, this.select2);
this.player.setSelection(0);
this.player.setSelectedLetter(null);
}
// Cancel selection reset
this.selectionToReset.clear();
}
}
}
/** Select letters in order to reset them.
* @param x mouse x.
* @param y mouse y.
* @param i current letter index.
*/
private void selectLettersForReset(int x, int y, int i) {
if (!this.panel.isLocked()) {
if (this.getMouseX() > x && this.getMouseX() < x + CASE_SIZE
&& this.getMouseY() > y && this.getMouseY() < y + CASE_SIZE) {
// Is selecting for adding to reset
this.select1 = i;
if (!this.selectionToReset.contains(this.select1)) {
this.selectionToReset.add(this.select1);
}
else {
// To avoid concurrent modification
List<Integer> selectResetCopy = new ArrayList<Integer>(7);
selectResetCopy.addAll(this.selectionToReset);
Iterator<Integer> itr = selectResetCopy.iterator();
while (itr.hasNext()) {
Integer it = itr.next();
if (it == this.select1) {
this.selectionToReset.remove(it);
}
}
}
if (this.selectionToReset.isEmpty()) {
this.panel.getButton("Reset").setEnabled(false);
}
else {
this.panel.getButton("Reset").setEnabled(true);
}
}
}
}
/** Select letters in order to reset them.
* @param x mouse x.
* @param y mouse y.
* @param i current letter index.
*/
private void godMod(int x, int y, int i) {
if (!this.panel.isLocked()) {
if (this.getMouseX() > x && this.getMouseX() < x + CASE_SIZE
&& this.getMouseY() > y && this.getMouseY() < y + CASE_SIZE) {
if (this.player.getRack().getLetter(i) != null) {
ImageIcon icon = new ImageIcon("ressources/god.jpg");
Object result = JOptionPane.showInputDialog(
this.panel, "", "God Mod", OK_CANCEL_OPTION,
icon, Bag.GOD_LETTERS, 0);
if (result != null) {
Debug.console("mousePressed", "God modify ",
Debug.formatLetter(this.player.getRack().getLetter(i))
+ " to " + (Character) result);
this.player.getRack().getLetter(i).setName((Character) result);
}
this.panel.repaint();
}
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
this.update(e);
}
@Override
public void mouseDragged(MouseEvent e) {
this.update(e);
}
@Override
public void mouseMoved(MouseEvent e) {
this.update(e);
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public int getMouseX() {
return this.mx;
}
@Override
public int getMouseY() {
return this.my;
}
/** Update on mouse changes.
* @param e mouse event.
*/
private void update(MouseEvent e) {
this.mx = e.getX();
this.my = e.getY();
this.panel.repaint();
}
}