package com.forgeessentials.permissions.commands;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.permission.PermissionContext;
import net.minecraftforge.permission.PermissionLevel;
import net.minecraftforge.permission.PermissionManager;
import org.apache.commons.lang3.StringUtils;
import com.forgeessentials.api.APIRegistry;
import com.forgeessentials.api.permissions.AreaZone;
import com.forgeessentials.api.permissions.FEPermissions;
import com.forgeessentials.api.permissions.WorldZone;
import com.forgeessentials.api.permissions.Zone;
import com.forgeessentials.commons.selections.AreaBase;
import com.forgeessentials.commons.selections.AreaShape;
import com.forgeessentials.core.commands.ForgeEssentialsCommandBase;
import com.forgeessentials.core.misc.TranslatedCommandException;
import com.forgeessentials.util.events.EventCancelledException;
import com.forgeessentials.util.output.ChatOutputHandler;
import com.forgeessentials.util.selections.SelectionHandler;
public class CommandZone extends ForgeEssentialsCommandBase
{
public static final String PERM_NODE = "fe.perm.zone";
public static final String PERM_ALL = PERM_NODE + Zone.ALL_PERMS;
public static final String PERM_LIST = PERM_NODE + ".list";
public static final String PERM_INFO = PERM_NODE + ".info";
public static final String PERM_DEFINE = PERM_NODE + ".define";
public static final String PERM_REDEFINE = PERM_NODE + ".redefine";
public static final String PERM_DELETE = PERM_NODE + ".delete";
public static final String PERM_SETTINGS = PERM_NODE + ".settings";
// Variables for auto-complete
private static final String[] parseMainArgs = { "help", "list", "select", "define", "redefine", "delete", "exit", "entry" };
private boolean tabCompleteMode = false;
private List<String> tabComplete;
@Override
public String getCommandName()
{
return "area";
}
@Override
public String[] getDefaultAliases()
{
return new String[] { "zone" };
}
public void parse(ICommandSender sender, Queue<String> args)
{
if (tabCompleteMode && args.size() == 1)
{
tabComplete = getListOfStringsMatchingLastWord(args.peek(), parseMainArgs);
return;
}
if (args.isEmpty())
{
help(sender);
}
else
{
// Get world
WorldZone worldZone = null;
if (sender instanceof EntityPlayerMP)
{
worldZone = APIRegistry.perms.getServerZone().getWorldZone(((EntityPlayerMP) sender).dimension);
}
String arg = args.remove().toLowerCase();
switch (arg)
{
case "help":
help(sender);
break;
case "select":
parseSelect(sender, worldZone, args);
break;
case "info":
parseInfo(sender, worldZone, args);
break;
case "list":
parseList(sender, worldZone, args);
break;
case "define":
case "redefine":
parseDefine(sender, worldZone, args, arg.equals("redefine"));
break;
case "delete":
parseDelete(sender, worldZone, args);
break;
case "exit":
case "entry":
parseEntryExitMessage(sender, worldZone, args, arg.equals("entry"));
break;
default:
throw new TranslatedCommandException(FEPermissions.MSG_UNKNOWN_SUBCOMMAND, arg);
}
}
}
private static AreaZone getAreaZone(WorldZone worldZone, String arg)
{
try
{
Zone z = APIRegistry.perms.getZoneById(arg);
if (z != null && z instanceof AreaZone)
return (AreaZone) z;
}
catch (NumberFormatException e)
{
/* none */
}
return worldZone.getAreaZone(arg);
}
private static void parseList(ICommandSender sender, WorldZone worldZone, Queue<String> args)
{
if (!PermissionManager.checkPermission(sender, PERM_LIST))
{
ChatOutputHandler.chatError(sender, FEPermissions.MSG_NO_COMMAND_PERM);
return;
}
final int PAGE_SIZE = 12;
int limit = 1;
if (!args.isEmpty())
{
try
{
limit = Integer.parseInt(args.remove());
}
catch (NumberFormatException e)
{
limit = 1;
}
}
ChatOutputHandler.chatConfirmation(sender, "List of areas (page #" + limit + "):");
limit *= PAGE_SIZE;
if (worldZone == null)
{
for (WorldZone wz : APIRegistry.perms.getServerZone().getWorldZones().values())
{
for (AreaZone areaZone : wz.getAreaZones())
{
if (areaZone.isHidden())
continue;
if (limit >= 0)
{
if (limit <= PAGE_SIZE)
ChatOutputHandler.chatConfirmation(sender, "#" + areaZone.getId() + ": " + areaZone.toString());
limit--;
}
else
{
break;
}
}
}
}
else
{
for (AreaZone areaZone : worldZone.getAreaZones())
{
if (areaZone.isHidden())
continue;
if (limit >= 0)
{
if (limit <= PAGE_SIZE)
ChatOutputHandler.chatConfirmation(sender, "#" + areaZone.getId() + ": " + areaZone.toString());
limit--;
}
else
{
break;
}
}
}
}
private void parseDefine(ICommandSender sender, WorldZone worldZone, Queue<String> args, boolean redefine)
{
if (!PermissionManager.checkPermission(sender, PERM_DEFINE))
{
if (!redefine || !PermissionManager.checkPermission(sender, PERM_REDEFINE))
{
ChatOutputHandler.chatError(sender, FEPermissions.MSG_NO_COMMAND_PERM);
return;
}
}
if (worldZone == null)
{
throw new TranslatedCommandException("No world found");
}
if (args.isEmpty())
{
throw new TranslatedCommandException("Missing arguments!");
}
if (tabCompleteMode && args.size() == 1)
{
if (!redefine)
return;
for (Zone z : APIRegistry.perms.getZones())
{
if (z instanceof AreaZone)
{
if (z.getName().startsWith(args.peek()))
tabComplete.add(z.getName());
if (Integer.toString(z.getId()).startsWith(args.peek()))
tabComplete.add(Integer.toString(z.getId()));
}
}
return;
}
String zoneName = args.remove();
AreaZone zone = getAreaZone(worldZone, zoneName);
if (!redefine && zone != null)
{
throw new TranslatedCommandException(String.format("Area \"%s\" already exists!", zoneName));
}
else if (redefine && zone == null)
{
throw new TranslatedCommandException(String.format("Area \"%s\" does not exist!", zoneName));
}
if (tabCompleteMode)
{
if (args.size() == 1)
{
tabComplete = getListOfStringsMatchingLastWord(args.peek(), AreaShape.valueNames());
}
return;
}
AreaBase area = null;
AreaShape shape = null;
if (!args.isEmpty())
{
shape = AreaShape.getByName(args.remove());
if (shape == null)
shape = AreaShape.BOX;
}
if (!(sender instanceof EntityPlayerMP))
{
throw new TranslatedCommandException("Command not usable from console. Try /zone set <name> <coords> instead");
}
area = SelectionHandler.selectionProvider.getSelection((EntityPlayerMP) sender);
if (area == null)
throw new TranslatedCommandException("No selection available. Please select a region first.");
PermissionContext context = new PermissionContext(sender).setTargetStart(area.getLowPoint().toVec3()).setTargetEnd(area.getHighPoint().toVec3());
if (!PermissionManager.checkPermission(context, PERM_DEFINE))
{
throw new TranslatedCommandException("You don't have the permission to define an area.");
}
if (redefine && zone != null)
{
zone.setArea(area);
if (shape != null)
zone.setShape(shape);
ChatOutputHandler.chatConfirmation(sender, String.format("Area \"%s\" has been redefined.", zoneName));
}
else
{
try
{
zone = new AreaZone(worldZone, zoneName, area);
if (shape != null)
zone.setShape(shape);
ChatOutputHandler.chatConfirmation(sender, String.format("Area \"%s\" has been defined.", zoneName));
}
catch (EventCancelledException e)
{
ChatOutputHandler.chatError(sender, String.format("Defining area \"%s\" has been cancelled.", zoneName));
}
}
}
private void parseDelete(ICommandSender sender, WorldZone worldZone, Queue<String> args)
{
if (!PermissionManager.checkPermission(sender, PERM_DELETE))
{
ChatOutputHandler.chatError(sender, FEPermissions.MSG_NO_COMMAND_PERM);
return;
}
if (worldZone == null)
{
throw new TranslatedCommandException("No world found");
}
if (args.isEmpty())
{
throw new TranslatedCommandException("Missing arguments!");
}
if (tabCompleteMode)
{
for (Zone z : APIRegistry.perms.getZones())
{
if (z instanceof AreaZone)
{
if (z.getName().startsWith(args.peek()))
tabComplete.add(z.getName());
if (Integer.toString(z.getId()).startsWith(args.peek()))
tabComplete.add(Integer.toString(z.getId()));
}
}
return;
}
String zoneName = args.remove();
AreaZone zone = getAreaZone(worldZone, zoneName);
if (zone == null)
{
ChatOutputHandler.chatError(sender, String.format("Area \"%s\" has does not exist!", zoneName));
return;
}
zone.getWorldZone().removeAreaZone(zone);
ChatOutputHandler.chatConfirmation(sender, String.format("Area \"%s\" has been deleted.", zoneName));
}
private void parseSelect(ICommandSender sender, WorldZone worldZone, Queue<String> args)
{
if (!PermissionManager.checkPermission(sender, PERM_INFO))
{
ChatOutputHandler.chatError(sender, FEPermissions.MSG_NO_COMMAND_PERM);
return;
}
if (!(sender instanceof EntityPlayerMP))
throw new TranslatedCommandException(FEPermissions.MSG_NO_CONSOLE_COMMAND);
EntityPlayerMP player = (EntityPlayerMP) sender;
if (worldZone == null)
throw new TranslatedCommandException("No world found");
if (args.isEmpty())
throw new TranslatedCommandException("Missing arguments!");
if (tabCompleteMode)
{
for (Zone z : APIRegistry.perms.getZones())
{
if (z instanceof AreaZone)
{
if (z.getName().startsWith(args.peek()))
tabComplete.add(z.getName());
if (Integer.toString(z.getId()).startsWith(args.peek()))
tabComplete.add(Integer.toString(z.getId()));
}
}
return;
}
String zoneName = args.remove();
AreaZone zone = getAreaZone(worldZone, zoneName);
if (zone == null)
{
ChatOutputHandler.chatError(sender, String.format("Area \"%s\" has does not exist!", zoneName));
return;
}
AreaBase area = zone.getArea();
SelectionHandler.selectionProvider.setDimension(player, worldZone.getDimensionID());
SelectionHandler.selectionProvider.setStart(player, area.getLowPoint());
SelectionHandler.selectionProvider.setEnd(player, area.getHighPoint());
SelectionHandler.sendUpdate(player);
ChatOutputHandler.chatConfirmation(sender, String.format("Area \"%s\" has been selected.", zoneName));
}
private void parseInfo(ICommandSender sender, WorldZone worldZone, Queue<String> args)
{
if (!PermissionManager.checkPermission(sender, PERM_INFO))
{
ChatOutputHandler.chatError(sender, FEPermissions.MSG_NO_COMMAND_PERM);
return;
}
if (worldZone == null)
throw new TranslatedCommandException("No world found");
if (args.isEmpty())
throw new TranslatedCommandException("Missing arguments!");
if (tabCompleteMode)
{
for (Zone z : APIRegistry.perms.getZones())
{
if (z instanceof AreaZone)
{
if (z.getName().startsWith(args.peek()))
tabComplete.add(z.getName());
if (Integer.toString(z.getId()).startsWith(args.peek()))
tabComplete.add(Integer.toString(z.getId()));
}
}
return;
}
String zoneName = args.remove();
AreaZone zone = getAreaZone(worldZone, zoneName);
if (zone == null)
{
ChatOutputHandler.chatError(sender, String.format("Area \"%s\" has does not exist!", zoneName));
return;
}
AreaBase area = zone.getArea();
ChatOutputHandler.chatConfirmation(sender, String.format("Area \"%s\"", zoneName));
ChatOutputHandler.chatNotification(sender, " start = " + area.getLowPoint().toString());
ChatOutputHandler.chatNotification(sender, " end = " + area.getHighPoint().toString());
}
private void parseEntryExitMessage(ICommandSender sender, WorldZone worldZone, Queue<String> args, boolean isEntry)
{
if (tabCompleteMode)
{
if (args.size() == 1 && "clear".startsWith(args.peek().toLowerCase()))
tabComplete.add("clear");
return;
}
if (!PermissionManager.checkPermission(sender, PERM_SETTINGS))
{
ChatOutputHandler.chatError(sender, FEPermissions.MSG_NO_COMMAND_PERM);
return;
}
if (worldZone == null)
{
throw new TranslatedCommandException("No world found");
}
if (args.isEmpty())
{
throw new TranslatedCommandException("Missing arguments!");
}
String zoneName = args.remove();
AreaZone zone = getAreaZone(worldZone, zoneName);
if (zone == null)
{
throw new TranslatedCommandException(String.format("Area \"%s\" does not exist!", zoneName));
}
if (args.isEmpty())
{
zone.getGroupPermission(Zone.GROUP_DEFAULT, isEntry ? FEPermissions.ZONE_ENTRY_MESSAGE : FEPermissions.ZONE_EXIT_MESSAGE);
}
else
{
String msg = StringUtils.join(args, " ");
if (msg.equalsIgnoreCase("clear"))
msg = null;
zone.setGroupPermissionProperty(Zone.GROUP_DEFAULT, isEntry ? FEPermissions.ZONE_ENTRY_MESSAGE : FEPermissions.ZONE_EXIT_MESSAGE, msg);
}
}
@Override
public void processCommandPlayer(EntityPlayerMP sender, String[] args)
{
LinkedList<String> argsList = new LinkedList<String>(Arrays.asList(args));
tabCompleteMode = false;
parse(sender, argsList);
}
private static void help(ICommandSender sender)
{
ChatOutputHandler.chatConfirmation(sender, "/zone list [page]: Lists all zones");
ChatOutputHandler.chatConfirmation(sender, "/zone info <zone>|here: Zone information");
ChatOutputHandler.chatConfirmation(sender, "/zone define|redefine <zone-name>: define or redefine a zone.");
ChatOutputHandler.chatConfirmation(sender, "/zone delete <zone-id>: Delete a zone.");
ChatOutputHandler.chatConfirmation(sender, "/zone entry|exit <zone-id> <message|clear>: Set the zone entry/exit message.");
}
@Override
public String getPermissionNode()
{
return PERM_NODE;
}
@Override
public boolean canConsoleUseCommand()
{
return false;
}
@Override
public List<String> addTabCompletionOptions(ICommandSender sender, String[] args)
{
LinkedList<String> argsList = new LinkedList<String>(Arrays.asList(args));
tabCompleteMode = true;
tabComplete = new ArrayList<String>();
parse(sender, argsList);
return tabComplete;
}
@Override
public String getCommandUsage(ICommandSender sender)
{
return "/zone: Displays command help";
}
@Override
public PermissionLevel getPermissionLevel()
{
return PermissionLevel.OP;
}
}