com.comphenix.undyingsun.CommandUndying.java Source code

Java tutorial

Introduction

Here is the source code for com.comphenix.undyingsun.CommandUndying.java

Source

/*
 *  UndyingSum - Bukkit server plugin that allows for decoupling the server and client clock.
 *  Copyright (C) 2013 Kristian S. Stangeland
 *
 *  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; 
 *  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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
 *  02111-1307 USA
 */

package com.comphenix.undyingsun;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;

import com.comphenix.undyingsun.temporal.TimeOfDay;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

/**
 * Represenst the undying sun command.
 * @author Kristian
 */
class CommandUndying implements TabExecutor {
    public static final String PERMISSION_WRITE_CONF = "undyingsun.config.write";
    public static final String PERMISSION_READ_CONF = "undyingsun.config.read";

    public static final String NAME = "undying";

    // The configuration
    private UndyingConfiguration config;

    // The sub commands
    private enum SubCommand {
        RELOAD("reload"), SERVER_TIME("servertime"), CLIENT_TIME("clienttime"), SERVER_SPEED(
                "serverspeed"), CLIENT_SPEED("clientspeed");

        private final String commandName;

        private SubCommand(String commandName) {
            this.commandName = commandName;
        }

        /**
         * Retrieve the command name of this subcommand.
         * @return The command name.
         */
        public String getCommandName() {
            return commandName;
        }

        @Override
        public String toString() {
            return commandName;
        }

        /**
         * Attempt to parse a given subcommand.
         * @param text - the text to parse.
         * @return The command, or NULL if not found.
         */
        public static SubCommand findExact(String text) {
            for (SubCommand cmd : values()) {
                if (cmd.getCommandName().equalsIgnoreCase(text)) {
                    return cmd;
                }
            }
            return null;
        }
    }

    /**
     * Construct a new command handler.
     * @param config - the configuration.
     */
    public CommandUndying(UndyingConfiguration config) {
        this.config = config;
    }

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        // Ensure we are dealing with our root command
        if (NAME.equals(command.getName())) {
            if (args.length > 0) {
                handleCommand(sender, args[0], subList(args, 1));
            } else {
                // Print every valid sub command
                sender.sendMessage(ChatColor.GOLD + "Possible sub-commands: "
                        + StringUtils.join(onTabComplete(sender, command, label, args), ", "));
            }
            return true;
        }
        return false;
    }

    /**
     * Handle a sub command.
     * @param sender - the sender.
     * @param commandName - the sub command name.
     * @param args - the arguments.
     */
    private void handleCommand(CommandSender sender, String commandName, List<String> args) {
        final SubCommand subCommand = SubCommand.findExact(commandName);

        switch (subCommand) {
        case RELOAD:
            config.reloadConfig();
            sender.sendMessage(ChatColor.GOLD + "Reloading configuration.");
            break;
        case CLIENT_TIME:
        case SERVER_TIME:
            handleTime(sender, subCommand, args);
            break;
        case CLIENT_SPEED:
        case SERVER_SPEED:
            handleSpeed(sender, subCommand, args);
            break;
        default:
            sender.sendMessage(ChatColor.RED + "No sub-command with the name " + commandName);
        }
    }

    /**
     * Handle the server time or the client time subcommand.
     * @param sender - the sender.
     * @param command - the sub-command.
     * @param args - the arguments.
     */
    private void handleTime(CommandSender sender, SubCommand command, List<String> args) {
        boolean server = command == SubCommand.SERVER_TIME;

        if (args.size() == 0) {
            // Check permission
            if (!sender.hasPermission(PERMISSION_READ_CONF)) {
                sender.sendMessage(ChatColor.RED + "Insufficient permission.");
            } else {
                sender.sendMessage("Fixed time: "
                        + TimeOfDay.toTimeString(server ? config.getServerTime() : config.getClientTime()));
            }

        } else if (args.size() == 1) {
            if (!sender.hasPermission(PERMISSION_WRITE_CONF)) {
                sender.sendMessage(ChatColor.RED + "Insufficient permission.");
                return;
            }

            TimeOfDay time = CommandTimeParser.parse(args.get(0));

            // Update configuration
            if (server)
                config.setServerTime(time);
            else
                config.setClientTime(time);
            config.saveConfig();

            // Notify sender
            sender.sendMessage(
                    ChatColor.GOLD + "New fixed " + (server ? "server" : "client") + " time: " + time.getAlias());

        } else {
            sender.sendMessage(ChatColor.RED + "Too many arguments.");
        }
    }

    /**
     * Handle the server speed or the client speed subcommand.
     * @param sender - the sender.
     * @param command - the sub-command.
     * @param args - the arguments.
     */
    private void handleSpeed(CommandSender sender, SubCommand command, List<String> args) {
        boolean server = command == SubCommand.SERVER_SPEED;

        if (args.size() == 0) {
            if (!sender.hasPermission(PERMISSION_READ_CONF)) {
                sender.sendMessage(ChatColor.RED + "Insufficient permission.");
            } else {
                sender.sendMessage(
                        "Current speed: " + (server ? config.getServerSpeed() : config.getClientSpeed()));
            }

        } else if (args.size() == 1) {
            if (!sender.hasPermission(PERMISSION_WRITE_CONF)) {
                sender.sendMessage(ChatColor.RED + "Insufficient permission.");
                return;
            }

            try {
                double speed = Double.parseDouble(args.get(0));

                if (server)
                    config.setServerSpeed(speed);
                else
                    config.setClientSpeed(speed);
                config.saveConfig();

                // Notify sender
                sender.sendMessage(ChatColor.GOLD + "New " + (server ? "server" : "client") + " speed: " + speed);

            } catch (NumberFormatException e) {
                // Incorrect input
                sender.sendMessage(ChatColor.RED + args.get(0) + " is not a number.");
            }
        } else {
            sender.sendMessage(ChatColor.RED + "Too many arguments.");
        }
    }

    @Override
    public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
        // Don't display tab complete for players without the permission
        if (!sender.hasPermission(PERMISSION_READ_CONF)) {
            return null;
        }

        // Only respond to the expected command
        if (NAME.equals(command.getName()) && args.length > 0) {
            String text = args[0];
            SubCommand exact = SubCommand.findExact(text);

            if (exact == SubCommand.SERVER_TIME || exact == SubCommand.CLIENT_TIME) {
                // Note that this doesn't include numbers
                return handleTimeComplete(subList(args, 1));
            } else if (exact == null) {
                return findByPrefix(asStrings(SubCommand.values()), text);
            }
        }
        return null;
    }

    /**
     * Determine every possible time input at argument 0.
     * @param args - the current arguments.
     * @return Every possible time input, or NULL if none are possible.
     */
    private List<String> handleTimeComplete(List<String> args) {
        if (args.size() == 1) {
            String text = args.get(0);
            TimeOfDay exact = TimeOfDay.fromAlias(text);

            if (exact == null) {
                return findByPrefix(asStrings(Iterables.concat(TimeOfDay.VALUES, CommandTimeParser.DISABLED)),
                        text);
            }
        }
        return null;
    }

    /**
     * Filter the given input iterable by elements matching a specific prefix, and collect them into a list.
     * @param prefix - the prefix.
     * @return A list of every matching element, or NULL.
     */
    public static List<String> findByPrefix(Iterable<String> input, String prefix) {
        List<String> result = null;

        for (String entry : input) {
            if (entry.startsWith(prefix)) {
                if (result == null)
                    result = Lists.newArrayList();
                result.add(entry);
            }
        }
        return result;
    }

    /**
     * Retrieve the string value of all the entries in the array.
     * @param array - the array to convert.
     * @return The string value of each entry.
     */
    private Iterable<String> asStrings(Object[] array) {
        return asStrings(Arrays.asList(array));
    }

    /**
     * Retrieve the string value of all the entries in the iterable.
     * @param iterable - the iterable to convert.
     * @return The string value of each entry.
     */
    private Iterable<String> asStrings(Iterable<? extends Object> iterable) {
        return Iterables.transform(iterable, Functions.toStringFunction());
    }

    /**
     * Retrieve a view of the given array as a list.
     * @param input - the input array.
     * @param beginIndex - the starting index (inclusive) or the list.
     * @return The resulting view.
     */
    private List<String> subList(String[] input, int beginIndex) {
        if (input.length < beginIndex)
            return Collections.emptyList();
        return Arrays.asList(input).subList(beginIndex, input.length);
    }
}