package de.bwvaachen.beamoflightgame.model.impl;
/*
Copyright (C) 2013 - 2014 by Andreas Pauls, Georg Braun, Christian Frühholz, Marius Spix, Christopher Müller and Bastian Winzen Part of the Beam Of Lights Puzzle Project
This program 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import de.bwvaachen.beamoflightgame.helper.AbstractTileVisitor;
import de.bwvaachen.beamoflightgame.helper.ITileVisitor;
import de.bwvaachen.beamoflightgame.model.IBeamsOfLightPuzzleBoard;
import de.bwvaachen.beamoflightgame.model.ITile;
import de.bwvaachen.beamoflightgame.model.ITileState;
import de.bwvaachen.beamoflightgame.model.LightTile;
import de.bwvaachen.beamoflightgame.model.NumberTile;
public class BeamsOfLightPuzzleBoard implements IBeamsOfLightPuzzleBoard, ChangeListener, UndoableEditListener {
private int width, height;
private ITile[][] tiles;
private LinkedList<NumberTile> numberTiles;
private ConcurrentLinkedQueue<ITile> tileQueue = new ConcurrentLinkedQueue<ITile>();
private HashSet<ChangeListener> changeListeners = new HashSet<ChangeListener>();
private HashSet<UndoableEditListener> undoableEditListeners = new HashSet<UndoableEditListener>();
private int currentTurnNumber = 0 ;
private boolean isSolution = false ;
public boolean isSolution() {
return isSolution;
}
public void setSolution(boolean isSolution) {
this.isSolution = isSolution;
}
public int getCurrentTurnNumber() {
return currentTurnNumber;
}
public void setCurrentTurnNumber(int currentTurnNumber) {
this.currentTurnNumber = currentTurnNumber;
}
@Override
public void addChangeListener(ChangeListener cl) {
changeListeners.add(cl);
}
@Override
public void addUndoableEditListener(UndoableEditListener ul) {
undoableEditListeners.add(ul);
}
/**
* @author Marius
* @param tile The tile to enqueue
*
* A thread-safe method to add tiles, also if the board has not been initialized yet.
* The tiles are stored in an internal list and committed when the flush() method is called.
*/
@Override
public void enqueueTile(ITile tile) {
tileQueue.add(tile);
}
/**
* @author Marius
*
* @see enqueueTile(ITile tile)
*/
@Override
public void flush() {
for(ITile t: tileQueue) {
putTile(t);
}
}
@Override
public int getHeight() {
return height;
}
@Override
public int getNumOfNumberTiles() {
//return numberTiles.values().size();
return numberTiles.size();
}
@Override
public ITile getTileAt(int x, int y) throws IndexOutOfBoundsException {
return tiles[x][y];
}
@Override
public int getWidth() {
return width;
}
@Override
public boolean hasField(int x, int y) {
return ( (x>(-1)) && (x<getWidth()) && (y>(-1)) && (y<getHeight()) );
}
@Override
public void init(int x, int y) {
width = x;
height = y;
tiles = new ITile[width][height];
numberTiles = new LinkedList<NumberTile>();
}
@Override
public boolean isPlacementOfTileStatePossible(ITileState state,
int x, int y) {
//TODO implementation
return true;
}
@Override
public Iterator<ITile> iterator() {
return new Iterator<ITile>() {
int x = 0, y = 0;
@Override
public boolean hasNext() {
return (x < getWidth());
}
@Override
public ITile next() {
ITile next = getTileAt(x,y);
if (++y==getHeight()) {
y=0;
x++;
};
return next;
}
@Override
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
};
}
@Override
public void putTile(ITile t) {
t.accept(new ITileVisitor() {
@Override
public void visitLightTile(LightTile t) {
BeamsOfLightPuzzleBoard.this.putTileInternal(t);
}
@Override
public void visitNumberTile(NumberTile t) {
BeamsOfLightPuzzleBoard.this.putTileInternal(t);
BeamsOfLightPuzzleBoard.this.numberTiles.add(t);
}
});
}
private void putTileInternal(ITile tile) {
tiles[tile.getX()][tile.getY()] = tile;
tile.addChangeListener(this);
tile.addUndoableEditListener(this);
}
@Override
public void removeChangeListener(ChangeListener cl) {
changeListeners.remove(cl);
}
@Override
public void removeUndoableEditListener(UndoableEditListener ul) {
undoableEditListeners.remove(ul);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
for(int y=0; y<height; y++) {
for(int x=0; x<width; x++) {
sb.append(getTileAt(x,y)+" ");
}
sb.append('\n');
}
return sb.toString();
}
@Override
public void undoableEditHappened(UndoableEditEvent e) {
// Propagate the event
for(UndoableEditListener l: undoableEditListeners) {
l.undoableEditHappened(e);
}
}
@Override
public void stateChanged(ChangeEvent e) {
// Propagate the event
for(ChangeListener l: changeListeners) {
l.stateChanged(e);
}
}
/**
* @author Andi
*
*/
public IBeamsOfLightPuzzleBoard clone()
{
//Clones the instance and returns an equal one.
IBeamsOfLightPuzzleBoard ret = new BeamsOfLightPuzzleBoard();
ret.init(this.width,this.height);
for(int h =0; h< this.height;h++)
{
for(int w = 0; w<this.width;w++)
{
ITile t = this.getTileAt(w, h);
if(t instanceof NumberTile)
{
NumberTile num = (NumberTile)t;
ret.putTile(new NumberTile(ret,num.getNumber(),w,h));
}
else if (t instanceof LightTile)
{
LightTile lig = (LightTile)t;
ret.putTile(new LightTile(ret,w,h,lig.getTileState()));
}
}
}
return ret;
}
public Iterator<NumberTile> numberTileIterator() {
return Collections.unmodifiableList(numberTiles).iterator();
}
}