/*******************************************************************************
* Rhythos Editor is a game editor and project management tool for making RPGs on top of the Rhythos Game system.
*
* Copyright (C) 2013 David Maletz
*
* 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 3 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; 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 program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mrpg.editor;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import mrpg.world.Cell;
import mrpg.world.Tile;
import mrpg.world.World;
public class History {
private final ArrayList<Entry> entries = new ArrayList<Entry>();
private int redoAt = 0;
public Listener listener;
public World world;
public void clearHistory(){
entries.clear(); redoAt = 0;
if(listener != null) listener.historyChanged();
}
public boolean addEntry(Entry e){
if(e.active.size() == 0) return false;
if(entries.size() > 0) entries.get(entries.size()-1).compact();
entries.subList(redoAt, entries.size()).clear(); entries.add(e); redoAt = entries.size();
if(listener != null) listener.historyChanged();
return true;
}
public void undo(){
if(redoAt > 0){
if(entries.size() > 0) entries.get(entries.size()-1).compact();
redoAt--; entries.get(redoAt).undo(world);
if(listener != null) listener.historyChanged();
}
}
public void redo(){
if(redoAt < entries.size()){
if(entries.size() > 0) entries.get(entries.size()-1).compact();
entries.get(redoAt).redo(world); redoAt++;
if(listener != null) listener.historyChanged();
}
}
public boolean hasUndo(){return redoAt > 0;}
public int redoPos(){return redoAt;}
public boolean hasRedo(){return redoAt < entries.size();}
public static interface Listener {
public void historyChanged();
};
private static class TileChange {
public Tile oldTile, newTile;
public TileChange(Tile old, Tile _new){oldTile = old; newTile = _new;}
}
private static class ChangedTile {
public final Tile oldTile, newTile; public final short x, y;
public ChangedTile(int _x, int _y, Tile old, Tile _new){x = (short)_x; y = (short)_y; oldTile = old; newTile = _new;}
}
public static class Entry {
private final int level; private HashMap<Point, TileChange> active;
private ChangedTile[] changed = null;
public Entry(int _level){level = _level; active = new HashMap<Point, TileChange>();}
public void changeTile(int x, int y, Tile oldTile, Tile newTile){
if(oldTile == newTile) return;
Point p = new Point(x, y);
TileChange t = active.get(p);
if(t == null) active.put(p, new TileChange(oldTile, newTile));
else {
if(t.oldTile == newTile) active.remove(p); else t.newTile = newTile;
}
}
public void compact(){
if(active != null){
changed = new ChangedTile[active.size()];
int i = 0; for(Map.Entry<Point, TileChange> e : active.entrySet()){
Point p = e.getKey(); TileChange c = e.getValue();
changed[i++] = new ChangedTile(p.x, p.y, c.oldTile, c.newTile);
}
active = null;
}
}
public void undo(World w){
for(ChangedTile t : changed){Cell c = w.getCell(t.x, t.y); if(c != null) c.setTile(t.oldTile, level);}
}
public void redo(World w){
for(ChangedTile t : changed) {Cell c = w.getCell(t.x, t.y); if(c != null) c.setTile(t.newTile, level);}
}
}
}