/*******************************************************************************
* Copyright 2014 Tobias Welther
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package de.tobiyas.racesandclasses.chat.channels.container;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import de.tobiyas.racesandclasses.RacesAndClasses;
import de.tobiyas.racesandclasses.chat.ChatFormatter;
import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.AbstractTraitHolder;
import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.race.RaceContainer;
import de.tobiyas.racesandclasses.playermanagement.player.RaCPlayer;
import de.tobiyas.racesandclasses.playermanagement.player.RaCPlayerManager;
import de.tobiyas.racesandclasses.util.chat.ChannelLevel;
import de.tobiyas.racesandclasses.util.consts.PermissionNode;
import de.tobiyas.util.config.YAMLConfigExtended;
import de.tobiyas.util.player.PlayerUtils;
public class ChannelContainer {
private final RacesAndClasses plugin;
private String channelName;
private ChatFormatter channelFormat;
private String channelPassword;
private RaCPlayer channelAdmin = null;
private ChannelLevel channelLevel;
private ArrayList<RaCPlayer> participants;
private MuteContainer muteContainer;
private BanContainer banContainer;
public ChannelContainer(String channelName, ChannelLevel level) throws ChannelInvalidException{
plugin = RacesAndClasses.getPlugin();
this.channelName = channelName;
this.channelLevel = level;
String prefix = "&f[";
String suffix = "&f]";
this.channelPassword = "";
participants = new ArrayList<RaCPlayer>();
muteContainer = new MuteContainer();
banContainer = new BanContainer();
adaptFormatingToLevel();
channelFormat.setPrefix(prefix);
channelFormat.setSuffix(suffix);
rescanPartitions(null);
ChannelTicker.registerChannel(this);
if(this.channelLevel == ChannelLevel.RaceChannel){
boolean raceExists = plugin.getRaceManager().getHolderByName(this.channelName) != null;
if(!raceExists){
throw new ChannelInvalidException();
}
}
}
private ChannelContainer(String channelName, ChannelLevel level, YAMLConfigExtended config){
participants = new ArrayList<RaCPlayer>();
this.channelLevel = level;
this.channelName = channelName;
plugin = RacesAndClasses.getPlugin();
config.load();
String channelPre = "channel." + level.name() + "." + channelName;
String prefix = config.getString(channelPre + ".prefix" , "&f[");
String suffix = config.getString(channelPre + ".suffix" , "&f]");
//Chanel formating
String channelColor = config.getString(channelPre + ".channelColor", plugin.getConfigManager().getChannelConfig().getConfig_channel_default_color());
String stdFormat = config.getString(channelPre + ".channelFormat", plugin.getConfigManager().getChannelConfig().getConfig_channel_default_format());
RaceContainer raceContainer = (RaceContainer) plugin.getRaceManager().getHolderByName(channelName);
boolean forceOverride = channelLevel == ChannelLevel.RaceChannel && raceContainer != null;
if(forceOverride){
channelColor = raceContainer.getRaceChatColor();
stdFormat = raceContainer.getRaceChatFormat();
}
channelPassword = config.getString(channelPre + ".channelPassword", "");
try{
UUID id = UUID.fromString(config.getString(channelPre + ".channelAdmin", ""));
channelAdmin = RaCPlayerManager.get().getPlayer(id);
}catch(IllegalArgumentException exp){}
muteContainer = new MuteContainer(config, channelPre);
banContainer = new BanContainer(config, channelPre);
List<String> tempList = config.getStringList(channelPre + ".members");
for(String uuid : tempList){
try{
UUID id = UUID.fromString(uuid);
RaCPlayer player = RaCPlayerManager.get().getPlayer(id);
participants.add(player);
}catch(Throwable exp){}
}
channelFormat = new ChatFormatter(channelName, channelColor, channelLevel, stdFormat);
channelFormat.setPrefix(prefix);
channelFormat.setSuffix(suffix);
if(!config.getBoolean(channelPre + ".saveLoad", false)) rescanPartitions(null);
config.set(channelPre + ".saveLoad", false);
config.save();
ChannelTicker.registerChannel(this);
}
private void adaptFormatingToLevel(){
String stdFormat = "";
String stdColor = "";
switch(channelLevel){
case GlobalChannel:
stdColor = plugin.getConfigManager().getChannelConfig().getConfig_globalchat_default_color();
stdFormat = plugin.getConfigManager().getChannelConfig().getConfig_globalchat_default_format();
break;
case WorldChannel:
stdColor = plugin.getConfigManager().getChannelConfig().getConfig_worldchat_default_color();
stdFormat = plugin.getConfigManager().getChannelConfig().getConfig_worldchat_default_format();
break;
case RaceChannel:
RaceContainer raceContainer = (RaceContainer) plugin.getRaceManager().getHolderByName(channelName);
if(raceContainer == null){
stdColor = plugin.getConfigManager().getChannelConfig().getConfig_racechat_default_color();
stdFormat = plugin.getConfigManager().getChannelConfig().getConfig_racechat_default_format();
}else{
stdColor = raceContainer.getRaceChatColor();
stdFormat = raceContainer.getRaceChatFormat();
}
break;
case LocalChannel:
stdColor = plugin.getConfigManager().getChannelConfig().getConfig_localchat_default_color();
stdFormat = plugin.getConfigManager().getChannelConfig().getConfig_localchat_default_format();
break;
default:
stdColor = plugin.getConfigManager().getChannelConfig().getConfig_channel_default_color();
stdFormat = plugin.getConfigManager().getChannelConfig().getConfig_channel_default_format();
}
channelFormat = new ChatFormatter(channelName, stdColor, channelLevel, stdFormat);
}
public void setPassword(String password){
if(channelLevel == ChannelLevel.PasswordChannel){
this.channelPassword = password;
}
}
protected String getPassword(){
return channelPassword;
}
public void banAndRemovePlayer(RaCPlayer player, int time){
banContainer.banPlayer(player, time);
if(isMember(player)){
removePlayerFromChannel(player, false);
}
}
public void unbanPlayer(RaCPlayer player){
banContainer.unbanPlayer(player);
}
public void mutePlayer(RaCPlayer player, int time){
muteContainer.mutePlayer(player, time);
}
public void unmutePlayer(RaCPlayer player){
muteContainer.unmutePlayer(player);
}
public void setAdmin(RaCPlayer player){
if(!participants.contains(player)){
participants.add(player);
}
channelAdmin = player;
}
public RaCPlayer getAdmin(){
return channelAdmin;
}
public void saveChannel(YAMLConfigExtended config){
if(channelLevel == ChannelLevel.LocalChannel) return;
List<String> participants = new LinkedList<String>();
for(RaCPlayer id : this.participants){
if(id == null) continue;
participants.add(id.getUniqueId().toString());
}
config.load();
String channelPre = "channel." + channelLevel.name() + "." + channelName;
config.createSection(channelPre);
config.set(channelPre + ".prefix" , channelFormat.getPrefix());
config.set(channelPre + ".suffix" , channelFormat.getSuffix());
config.set(channelPre + ".channelColor" , channelFormat.getColor());
if(participants.size() > 0) config.set(channelPre + ".members" , participants);
config.set(channelPre + ".channelFormat", channelFormat.getFormat());
config.set(channelPre + ".channelPassword", channelPassword);
config.set(channelPre + ".channelAdmin", channelAdmin);
config.set(channelPre + ".saveLoad", true);
banContainer.saveContainer(config, channelPre);
muteContainer.saveContainer(config, channelPre);
config.save();
}
public static ChannelContainer constructFromYml(YAMLConfigExtended config, String channelName, ChannelLevel level) throws ChannelInvalidException{
try{
return new ChannelContainer(channelName, level, config);
}catch(Exception exp){
throw new ChannelInvalidException();
}
}
public void addPlayerToChannel(RaCPlayer player, String password, boolean notify){
if(participants.contains(player)){
player.sendMessage(ChatColor.RED + "You are already member of this channel.");
return;
}
int isBanned = banContainer.isBanned(player);
if(isBanned != -1){
String time = getTimeString(isBanned);
player.sendMessage(ChatColor.RED + "You are banned from this channel for: " + ChatColor.LIGHT_PURPLE + time);
return;
}
if(channelLevel == ChannelLevel.RaceChannel){
AbstractTraitHolder container = plugin.getRaceManager().getHolderOfPlayer(player);
if(container == null || !container.getDisplayName().equalsIgnoreCase(channelName)){
player.sendMessage(ChatColor.RED + "You don't belong to this race.");
return;
}
}
if(channelLevel == ChannelLevel.WorldChannel){
if(!player.getWorld().getName().equalsIgnoreCase(channelName)){
player.sendMessage(ChatColor.RED + "You are not on this world.");
return;
}
}
if(!channelPassword.equals("")){
if(!password.equals(channelPassword)){
if(player != null)
player.sendMessage(ChatColor.RED + "Wrong password.");
return;
}
}
participants.add(player);
if(player != null){
if(notify){
String joinMessage = plugin.getConfigManager().getChannelConfig().getConfig_PlayerJoinFormat();
if(!joinMessage.isEmpty()) sendMessageInChannel(player.getPlayer(), "", joinMessage);
}
}
}
public void removePlayerFromChannel(RaCPlayer player, boolean notify){
if(!participants.contains(player) && player != null){
player.sendMessage(ChatColor.RED + "You are no member of this channel.");
return;
}
if(player != null){
if(notify){
String leaveMessage = plugin.getConfigManager().getChannelConfig().getConfig_PlayerLeaveFormat();
if(!leaveMessage.isEmpty()) sendMessageInChannel(player.getPlayer(), "", leaveMessage);
}
}
participants.remove(player);
if(channelLevel == ChannelLevel.PasswordChannel || channelLevel == ChannelLevel.PrivateChannel || channelLevel == ChannelLevel.PublicChannel){
if(participants.size() == 0){
plugin.getChannelManager().removeChannel(this.channelName);
return;
}else{
if(player.equals(channelAdmin)){
RaCPlayer oldChannelAdmin = channelAdmin;
RaCPlayer newChannelAdmin = participants.get(0);
setAdmin(newChannelAdmin);
sendMessageInChannel(null, "Channel-Admin changed from: " + ChatColor.RED + oldChannelAdmin + " TO " + newChannelAdmin, "");
}
}
}
}
public ArrayList<RaCPlayer> getAllParticipants(){
return participants;
}
public void sendMessageInChannel(CommandSender sender, String message, String forceFormat){
if(forceFormat.isEmpty()) return;
Player player = (sender instanceof Player) ? (Player)sender : null;
RaCPlayer racPlayer = RaCPlayerManager.get().getPlayer(player);
if(channelLevel == ChannelLevel.LocalChannel && sender instanceof Player) rescanPartitions((Player) sender);
if(player != null){
int isMuted = muteContainer.isMuted(racPlayer);
if(isMuted != -1){
String time = getTimeString(isMuted);
sender.sendMessage(ChatColor.RED + "You are muted in this channel for: " + ChatColor.LIGHT_PURPLE + time);
return;
}
}
Set<Player> players = new HashSet<Player>();
for(RaCPlayer member : participants){
if(member != null && member.isOnline()){
players.add(member.getPlayer());
}
}
AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(!Bukkit.isPrimaryThread(), player, message, players);
event.setFormat(forceFormat);
Bukkit.getPluginManager().callEvent(event);
if(event.isCancelled()) return;
String modifiedMessage = "";
if(sender == null){
modifiedMessage = modifyMessageToPlayer(null, event.getMessage(), event.getFormat());
}else{
modifiedMessage = modifyMessageToPlayer(racPlayer, event.getMessage(), event.getFormat());
}
for(Player recipient : event.getRecipients()){
recipient.sendMessage(modifiedMessage);
}
}
private void rescanPartitions(Player localPlayer){
switch(channelLevel){
case GlobalChannel:
if(!channelName.equalsIgnoreCase("Global"))
return;
participants.clear();
for(Player player : PlayerUtils.getOnlinePlayers()){
RaCPlayer racPlayer = RaCPlayerManager.get().getPlayer(player);
participants.add(racPlayer);
}
break;
case WorldChannel:
participants.clear();
for(Player player : Bukkit.getWorld(channelName).getPlayers()){
RaCPlayer racPlayer = RaCPlayerManager.get().getPlayer(player);
participants.add(racPlayer);
}
break;
case RaceChannel:
participants.clear();
RaceContainer container = (RaceContainer) plugin.getRaceManager().getHolderByName(channelName);
if(container == null){
//channel is not valid any more.
break;
}
List<RaCPlayer> allPlayersOfRace = plugin.getRaceManager().getAllPlayersOfHolder(container);
for(RaCPlayer player : allPlayersOfRace) {
participants.add(player);
}
break;
case LocalChannel:
participants.clear();
if(localPlayer == null) return;
int distance = plugin.getConfigManager().getChannelConfig().getConfig_localchat_range();
Location loc = localPlayer.getLocation();
for(Player tempPlayer : loc.getWorld().getPlayers()){
if(loc.distance(tempPlayer.getLocation()) < distance){
RaCPlayer player = RaCPlayerManager.get().getPlayer(tempPlayer);
participants.add(player);
}
}
break;
default: return;
}
}
private String modifyMessageToPlayer(RaCPlayer player, String message, String forceFormat){
return channelFormat.format(player, message, forceFormat, true);
}
private String getTimeString(int timeInSec){
String time = "";
int orgSeconds = timeInSec * 1000;
int seconds = (int) (orgSeconds / 1000) % 60 ;
int minutes = (int) ((orgSeconds / (1000*60)) % 60);
int hours = (int) ((orgSeconds / (1000*60*60)) % 24);
if(hours != 0)
time += hours + " hours, ";
if(minutes != 0)
time += minutes + " minutes, ";
if(seconds != 0)
time += seconds + " seconds";
if(timeInSec == Integer.MAX_VALUE)
time = " ever";
return time;
}
public String getChannelName(){
return channelName;
}
public void postInfo(CommandSender sender) {
Player player = (sender instanceof Player) ? (Player) sender : null;
RaCPlayer racPlayer = RaCPlayerManager.get().getPlayer(player);
sender.sendMessage(ChatColor.YELLOW + "ChannelName: " + ChatColor.AQUA + channelName);
sender.sendMessage(ChatColor.YELLOW + "ChannelLevel: " + ChatColor.AQUA + channelLevel.name());
sender.sendMessage(ChatColor.YELLOW + "ChannelColor: " + ChatColor.translateAlternateColorCodes('&', channelFormat.getColor()) + "COLOR");
sender.sendMessage(ChatColor.YELLOW + "ChannelFormat: " + ChatColor.RESET + ChatColor.translateAlternateColorCodes('&',channelFormat.getFormat()));
if(player != null && player.getUniqueId().equals(channelAdmin)){
sender.sendMessage(ChatColor.YELLOW + "ChannelPassword: " + ChatColor.AQUA + channelPassword);
}else{
sender.sendMessage(ChatColor.YELLOW + "Has Password: " + ChatColor.AQUA + !channelPassword.equalsIgnoreCase(""));
}
if(channelAdmin != null){
sender.sendMessage(ChatColor.YELLOW + "ChannelAdmin: " + ChatColor.AQUA + channelAdmin);
}
int isMuted = player == null ? 0 : muteContainer.isMuted(racPlayer);
if(isMuted != -1)
sender.sendMessage(ChatColor.YELLOW + "Muted for: " + ChatColor.AQUA + getTimeString(isMuted));
int isBanned = player == null ? 0 : banContainer.isBanned(racPlayer);
if(isBanned != -1)
sender.sendMessage(ChatColor.YELLOW + "Banned for: " + ChatColor.AQUA + getTimeString(isBanned));
sender.sendMessage(ChatColor.YELLOW + "===== Channel Members: =====");
String memberString = "";
if(channelLevel == ChannelLevel.LocalChannel && sender instanceof Player){
rescanPartitions((Player) sender);
}
for(RaCPlayer member : participants){
RaCPlayer playerMember = RaCPlayerManager.get().getPlayer(player);
if(playerMember == null || !playerMember.isOnline()){
memberString += ChatColor.RED + "" + member + " (offline), ";
}else{
memberString += ChatColor.GREEN + "" + member + ", ";
}
}
if(memberString.length() > 0){
sender.sendMessage(memberString.substring(0, memberString.length() - 2));
}else{
sender.sendMessage(ChatColor.RED + "This channel has currently no Members.");
}
}
public ChannelLevel getChannelLevel() {
return channelLevel;
}
public boolean isMember(RaCPlayer player) {
return participants.contains(player);
}
public void tick() {
muteContainer.tick();
banContainer.tick();
}
public boolean checkPermissionMute(Player admin) {
if(channelLevel == ChannelLevel.GlobalChannel || channelLevel == ChannelLevel.RaceChannel || channelLevel == ChannelLevel.WorldChannel || channelLevel == ChannelLevel.LocalChannel){
return plugin.getPermissionManager().checkPermissionsSilent(admin, PermissionNode.channelGlobalMutePower);
}
return admin.getUniqueId().equals(this.channelAdmin);
}
public boolean checkPermissionUnmute(Player admin) {
if(channelLevel == ChannelLevel.GlobalChannel || channelLevel == ChannelLevel.RaceChannel || channelLevel == ChannelLevel.WorldChannel || channelLevel == ChannelLevel.LocalChannel){
return plugin.getPermissionManager().checkPermissionsSilent(admin, PermissionNode.channelGlobalUnmutePower);
}
return admin.getUniqueId().equals(this.channelAdmin);
}
public boolean checkPermissionBann(Player admin) {
if(channelLevel == ChannelLevel.GlobalChannel || channelLevel == ChannelLevel.RaceChannel || channelLevel == ChannelLevel.WorldChannel || channelLevel == ChannelLevel.LocalChannel){
return plugin.getPermissionManager().checkPermissionsSilent(admin, PermissionNode.channelGlobalBanPower);
}
return admin.getUniqueId().equals(this.channelAdmin);
}
public boolean checkPermissionUnban(Player admin) {
if(channelLevel == ChannelLevel.GlobalChannel || channelLevel == ChannelLevel.RaceChannel || channelLevel == ChannelLevel.WorldChannel || channelLevel == ChannelLevel.LocalChannel){
return plugin.getPermissionManager().checkPermissionsSilent(admin, PermissionNode.channelGlobalUnbanPower);
}
return admin.getUniqueId().equals(this.channelAdmin);
}
public boolean isMuted(RaCPlayer player){
return muteContainer.isMuted(player) != -1;
}
public boolean isBanned(RaCPlayer player){
return banContainer.isBanned(player) != -1;
}
/**
* Edits a property of the channel.
*
* @param playerUUID2
* @param property
* @param newValue
*/
public void editChannel(RaCPlayer player, String property, String newValue) {
if(channelLevel == ChannelLevel.PasswordChannel || channelLevel == ChannelLevel.PrivateChannel || channelLevel == ChannelLevel.PublicChannel || channelLevel == ChannelLevel.LocalChannel){
if(!player.equals(channelAdmin)){
player.sendMessage(ChatColor.RED + "You must be the channel-admin to edit the channel");
return;
}
}
boolean changed = true;
String loweredProperty = property.toLowerCase();
if("format".equals(loweredProperty)){
channelFormat.setFormat(newValue);
}else
if("color".equals(loweredProperty)){
channelFormat.setColor(newValue);
}else
if("admin".equals(loweredProperty)){
changed = changeAdmin(player, newValue);
}else
if("prefix".equals(loweredProperty)){
channelFormat.setPrefix(newValue);
}else
if("suffix".equals(loweredProperty)){
channelFormat.setSuffix(newValue);
}else
if("password".equals(loweredProperty)){
if(channelLevel == ChannelLevel.PasswordChannel){
channelPassword = newValue;
}
}else{
changed = false;
}
if(changed){
player.sendMessage(ChatColor.LIGHT_PURPLE + property + ChatColor.GREEN + " was changed to: " + ChatColor.LIGHT_PURPLE + newValue);
}else{
player.sendMessage(ChatColor.LIGHT_PURPLE + property + ChatColor.RED + " could not be found or your new Argument is invalid.");
player.sendMessage(ChatColor.RED + "Valid properties are: " + ChatColor.LIGHT_PURPLE + "format, color, prefix, suffix, admin, password");
}
}
/**
* Changes the Admin of a Channel to a new one.
* This is not possible in Password / Private / Public channels.
*
* @param oldAdmin, that is removed
* @param newAdmin, that is the new Admin
* @return
*/
private boolean changeAdmin(RaCPlayer playerUUID, String newAdmin){
if(channelLevel == ChannelLevel.PasswordChannel ||
channelLevel == ChannelLevel.PrivateChannel ||
channelLevel == ChannelLevel.PublicChannel)
return false;
RaCPlayer newAdminRaCPlayer = null;
boolean isFoundInList = false;
for(RaCPlayer member : participants){
if(member.getName().equals(newAdmin)){
isFoundInList = true;
newAdminRaCPlayer = member;
break;
}
}
if(isFoundInList){
this.sendMessageInChannel(null, "New Admin of this channel is: " + ChatColor.LIGHT_PURPLE + newAdmin, "");
channelAdmin = newAdminRaCPlayer;
return true;
}
return false;
}
/**
* The Event is edited due to the channel.
*
* @param event to edit.
*/
public void editEvent(AsyncPlayerChatEvent event) {
List<Player> members = new LinkedList<Player>();
rescanPartitions(event.getPlayer());
for(RaCPlayer member : participants){
if(member != null && member.isOnline()) members.add(member.getPlayer());
}
//setting receipients
event.getRecipients().clear();
event.getRecipients().addAll(members);
//setting format.
String format = channelFormat.getFormat();
RaCPlayer racPlayer = RaCPlayerManager.get().getPlayer(event.getPlayer());
format = channelFormat.format(racPlayer, event.getMessage(), "", false);
event.setFormat(format);
}
/**
* Sends an completely unformatted message.
*
* @param message to send
*/
public void sendUnformatedMessage(String message) {
for(RaCPlayer player : participants){
player.sendMessage(message);
}
}
}