package org.ultralogger.util;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Player;
public class RollbackCommandExecutor {
private static ArrayList<Player> players = new ArrayList<Player>();
private static ArrayList<ArrayList<Location>> undoList = new ArrayList<ArrayList<Location>>();
private static ArrayList<ArrayList<BlockState>> states = new ArrayList<ArrayList<BlockState>>();
/**Undo all in the area
*
* @param p
* @param from
* @param to
*/
public static void undo(Player p,Location from,Location to){
int good =0;
int max =0;
World w = from.getWorld();
int minX = 0;
int minY = 0;
int minZ = 0;
int maxX = 0;
int maxY = 0;
int maxZ = 0;
if(from.getX()>to.getX()){
maxX=(int) from.getX();
minX=(int) to.getX();
}
else{
maxX=(int) to.getX();
minX=(int) from.getX();
}
if(from.getY()>to.getY()){
maxY=(int) from.getY();
minY=(int) to.getY();
}
else{
maxY=(int) to.getY();
minY=(int) from.getY();
}
if(from.getZ()>to.getZ()){
maxZ=(int) from.getZ();
minZ=(int) to.getZ();
}
else{
maxZ=(int) to.getZ();
minZ=(int) from.getZ();
}
maxX++;
maxY++;
maxZ++;
int newY = minY;
int newZ = minZ;
for(;minX!=maxX;minX++){
newY=minY;
newZ=minZ;
for(;newY!=maxY;newY++){
newZ=minZ;
for(;newZ!=maxZ;newZ++){
Location loc = new Location(w,minX,newY,newZ);
max++;
if(undoThis(p,loc))
good++;
}
}
}
p.sendMessage(ChatColor.GOLD+" Succesfully undo change(s) "+good+"/"+max+" time(s) !");
}
/**Just exec the command
*
* @param p
* @param loc
*/
public static void undo(Player p,Location loc){
if(undoThis(p,loc))
p.sendMessage(ChatColor.GOLD+" Succesfully undo change !");
else
p.sendMessage(ChatColor.GOLD+" Failed to undo change !");
}
/**Undo the last block change at the specified loc
*
* @param p
* @param loc
* @return if succesfully undo
*/
private static boolean undoThis(Player p,Location loc){
HistoryManager h =HistoryManager.getInstance();
int x = h.getHistoricIndex(loc);
if(x>=0){
if(!players.contains(p)){
ArrayList<Location> locs =new ArrayList<Location>();
ArrayList<BlockState> state = new ArrayList<BlockState>();
locs.add(loc);
History i = h.getHistory(loc);
String happ = i.lastEvent();
if(happ==null)
return false;
i.removeLast();
if(happ.startsWith("0")){//destroyed a block
int id =Material.matchMaterial(happ.substring(happ.indexOf("+")+1)).getId();
state.add(loc.getWorld().getBlockAt(loc).getState());//save block state that were here before
loc.getWorld().getBlockAt(loc).setTypeId(id);//so place the block
}
else{//placed a block
state.add(loc.getWorld().getBlockAt(loc).getState());//save block state that were here before
loc.getWorld().getBlockAt(loc).setTypeId(0);// so destroy a block
}
players.add(0, p);
undoList.add(0, locs);
states.add(0, state);
}
else{
int y = players.indexOf(p);
ArrayList<Location> locs = undoList.get(y);
locs.add(loc);
ArrayList<BlockState> state = states.get(y);
History i = h.getHistory(loc);
String happ = i.lastEvent();
if(happ==null)
return false;
i.removeLast();
if(happ.startsWith("0")){//destroyed a block
int id =Material.matchMaterial(happ.substring(happ.indexOf("+")+1).trim()).getId();
state.add(loc.getWorld().getBlockAt(loc).getState());//save block state that were here before
loc.getWorld().getBlockAt(loc).setTypeId(id);//so place the block
}
else{//placed a block
state.add(loc.getWorld().getBlockAt(loc).getState());//save block state that were here before
loc.getWorld().getBlockAt(loc).setTypeId(0);// so destroy a block
}
}
return true;
}
else{
return false;
}
}
/**Redo all in the area
*
* @param p
* @param from
* @param to
*/
public static void redo(Player p,Location from,Location to){
int good =0;
int max =0;
World w = from.getWorld();
int minX = 0;
int minY = 0;
int minZ = 0;
int maxX = 0;
int maxY = 0;
int maxZ = 0;
if(from.getX()>to.getX()){
maxX=(int) from.getX();
minX=(int) to.getX();
}
else{
maxX=(int) to.getX();
minX=(int) from.getX();
}
if(from.getY()>to.getY()){
maxY=(int) from.getY();
minY=(int) to.getY();
}
else{
maxY=(int) to.getY();
minY=(int) from.getY();
}
if(from.getZ()>to.getZ()){
maxZ=(int) from.getZ();
minZ=(int) to.getZ();
}
else{
maxZ=(int) to.getZ();
minZ=(int) from.getZ();
}
maxX++;
maxY++;
maxZ++;
int newY = minY;
int newZ = minZ;
for(;minX!=maxX;minX++){
newY=minY;
newZ=minZ;
for(;newY!=maxY;newY++){
newZ=minZ;
for(;newZ!=maxZ;newZ++){
Location loc = new Location(w,minX,newY,newZ);
max++;
if(redoThis(p,loc))
good++;
}
}
}
p.sendMessage(ChatColor.GOLD+" Succesfully redo change(s) "+good+"/"+max+" times !");
}
/**Just exec the command
*
* @param p
* @param loc
*/
public static void redo(Player p,Location loc){
if(redoThis(p,loc))
p.sendMessage(ChatColor.GOLD+" Succesfully redo change !");
else
p.sendMessage(ChatColor.GOLD+" Failed to redo change !");
}
/**Redo the last block change at the specified loc ( one block )
*
* @param p
* @param loc
* @return if succesfully redo
*/
private static boolean redoThis(Player p,Location loc){
HistoryManager h =HistoryManager.getInstance();
if(players.contains(p)){
int index = players.indexOf(p);
boolean del = false;
if(undoList.get(index).contains(loc)){
ArrayList<Location> locs = undoList.get(index);
if(locs.size()==1)
del = true;
History i = h.getHistory(loc);
String time = DateFormat.getInstance().format(new Date(System.currentTimeMillis()))+" ";
int x = locs.indexOf(loc);
ArrayList<BlockState> state = states.get(index);
BlockState st = state.get(x);
//We restore our block state
st.update(true);
if(loc.getBlock().getTypeId()>0)
i.add("-"+time+p.getName()+" placed {"+st.getTypeId()+"}");
else if(loc.getBlock().getTypeId()<=0)
i.add("-"+time+p.getName()+" broke {"+loc.getBlock().getTypeId()+"}");
locs.remove(loc);
state.remove(st);
if(del){
states.remove(state);
undoList.remove(locs);
players.remove(p);
}
return true;
}
else{
return false;
}
}
else{
return false;
}
}
}