gt:         List<String> nicks = new ArrayList<String>();
context: /* 
   * Copyright (C) 2015 www.phantombot.net
   *
   * Credits: mast3rplan, gmt2001, PhantomIndex, GloriousEggroll
   * gloriouseggroll@gmail.com, phantomindex@gmail.com
   *
   * 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 me.mast3rplan.phantombot.jerklib;
  
  import java.util.*;
  import java.util.concurrent.ConcurrentLinkedQueue;
  import me.mast3rplan.phantombot.jerklib.ModeAdjustment.Action;
  import me.mast3rplan.phantombot.jerklib.events.TopicEvent;
  
  /**
   * A Class to represent a <b>joined</b> IRC channel. This class has methods to
   * interact with IRC Channels like say() , part() , getChannelModes() etc.
   * <p/>
   * You will never need to create an instance of this class manually. Instead it
   * will be created for you and stored in the Session when you successfully join
   * a channel.
   *
   * @author mohadib
   * @see Session
   * @see Session#getChannel(String)
   * @see Session#getChannels()
   * @see me.mast3rplan.phantombot.jerklib.events.JoinCompleteEvent
   */
  public class Channel
  {
      /* channel name */
  
      private String name;
      private Session session;
      private Map<String, List<ModeAdjustment>> userMap;
      private List<ModeAdjustment> channelModes = new ArrayList<ModeAdjustment>();
      private TopicEvent topicEvent;
      private ConcurrentLinkedQueue<String> messages = new ConcurrentLinkedQueue<>();
      private ConcurrentLinkedQueue<String> prioritymessages = new ConcurrentLinkedQueue<>();
      private Timer sayTimer = new Timer();
      private Boolean allowSendMessages = false;
      private long msginterval = 1600;
  
      class MessageTask extends TimerTask
      {
  
          Channel chan;
          long lastMessage = 0;
  
          public MessageTask(Channel c)
          {
              super();
              chan = c;
              
              Thread.setDefaultUncaughtExceptionHandler(com.gmt2001.UncaughtExceptionHandler.instance());
          }
  
          @Override
          public void run()
          {
              long now = System.currentTimeMillis();
              if (now - lastMessage >= msginterval)
              {
                  String pmsg = chan.prioritymessages.poll();
                  if (pmsg != null)
                  {
                      chan.session.sayChannel(chan, pmsg);
  
                      lastMessage = now;
                  } else
                  {
                      String msg = chan.messages.poll();
                      if (msg != null)
                      {
                          if (allowSendMessages || msg.startsWith(".timeout ") || msg.startsWith(".ban ")
                                  || msg.startsWith(".unban ") || msg.equals(".clear") || msg.equals(".mods"))
                          {
                              chan.session.sayChannel(chan, msg);
                          }
  
                          lastMessage = now;
                      }
                  }
              }
          }
      }
  
      /**
       * This should only be used internally and for testing
       *
       * @param name - Name of Channel
       * @param session - Session Channel belongs to
       */
      public Channel(String name, Session session)
      {
          /* create a map that will match exact and key to lowercase */
          userMap = new HashMap<String, List<ModeAdjustment>>()
          {
              @Override
              public List<ModeAdjustment> get(Object key)
              {
                  List<ModeAdjustment> rList = super.get(key);
                  if (key != null && rList == null)
                  {
                      rList = super.get(key.toString().toLowerCase());
                  }
                  return rList;
              }
  
              @Override
              public List<ModeAdjustment> remove(Object key)
              {
                  List<ModeAdjustment> rList = super.remove(key);
                  if (key != null && rList == null)
                  {
                      rList = super.remove(key.toString().toLowerCase());
                  }
                  return rList;
              }
  
              @Override
              public boolean containsKey(Object key)
              {
                  boolean b = super.containsKey(key);
                  if (!b)
                  {
                      b = super.containsKey(key.toString().toLowerCase());
                  }
                  return b;
              }
          };
  
          this.name = name;
          this.session = session;
  
          Thread.setDefaultUncaughtExceptionHandler(com.gmt2001.UncaughtExceptionHandler.instance());
          
          sayTimer.schedule(new MessageTask(this), 300, 100);
      }
  
      public void setAllowSendMessages(Boolean allow)
      {
          allowSendMessages = allow;
      }
  
      /**
       * Updates Channel's modes.
       * <p/>
       * Only tracks channel modes that apply to users in the channel if the mode
       * is in the nick prefix map received in numeric 005. If no numeric is
       * passed o,v,h are used by default.
       * <p/>
       * So basically modes that do not change the apperance of a nick with a
       * prefix are not tracked if the mode applies to a user. Example: q and b
       * are not tracked.
       * <p/>
       * If the mode does not apply to a user in the channel , the mode will
       * always be tracked. Example: i is tracked
       *
       * @param modes - list of ModeAdjustments
       */
      void updateModes(List<ModeAdjustment> modes)
      {
          ServerInformation info = session.getServerInformation();
          List<String> nickModes = new ArrayList<String>(info.getNickPrefixMap().values());
  
          for (ModeAdjustment mode : modes)
          {
              if (nickModes.contains(String.valueOf(mode.getMode())) && userMap.containsKey(mode.getArgument()))
              {
                  updateMode(mode, userMap.get(mode.getArgument()));
              } /* filter out channel modes that apply to users that are not in prefix map */ /* like +b - this behviour might not be desired , time will tell */ else if (mode.getMode() != 'q' && mode.getMode() != 'b')
              {
                  updateMode(mode, channelModes);
              }
          }
      }
  
      /**
       * If Action is MINUS and the same mode exists with a PLUS Action then just
       * remove the PLUS mode ModeAdjustment from the collection.
       * <p/>
       * If Action is MINUS and the same mode with PLUS does not exist then add
       * the MINUS mode to the ModeAdjustment collection
       * <p/>
       * if Action is PLUS and the same mode exists with a MINUS Action then
       * remove MINUS mode and add PLUS mode
       * <p/>
       * If Action is PLUS and the same mode with MINUS does not exist then just
       * add PLUS mode to collection
       *
       * @param mode
       */
      private void updateMode(ModeAdjustment mode, List<ModeAdjustment> modes)
      {
          int index = indexOfMode(mode.getMode(), modes);
  
          if (mode.getAction() == Action.MINUS)
          {
              if (index != -1)
              {
                  ModeAdjustment ma = modes.remove(index);
                  if (ma.getAction() == Action.MINUS)
                  {
                      modes.add(ma);
                  }
              } else
              {
                  modes.add(mode);
              }
          } else
          {
              if (index != -1)
              {
                  modes.remove(index);
              }
              modes.add(mode);
          }
      }
  
      /**
       * Finds index of a mode in a List of ModeAdjustments
       *
       * @param mode mode to find
       * @param modes list to search
       * @return index or -1 if not found
       */
      private int indexOfMode(char mode, List<ModeAdjustment> modes)
      {
          for (int i = 0; i < modes.size(); i++)
          {
              ModeAdjustment ma = modes.get(i);
              if (ma.getMode() == mode)
              {
                  return i;
              }
          }
          return -1;
      }
  
      /**
       * Get a list of user's channel modes Returns an empty list if the nick does
       * not exist.
       *
       * @param nick
       * @return list of ModeAdjustments for user
       */
      public List<ModeAdjustment> getUsersModes(String nick)
      {
          if (userMap.containsKey(nick))
          {
              return new ArrayList<ModeAdjustment>(userMap.get(nick));
          } else
          {
              return new ArrayList<ModeAdjustment>();
          }
      }
  
      /**
       * Gets a list of users in channel with a given mode set. A user will only
       * match if they have the exact mode set. Non existance of +(mode) does not
       * imply that the user is -(mode)
       * <p/>
       * So searching for -v would almost always return an empty list.
       *
       * @param action
       * @param mode
       * @return List of nicks with mode/action set
       */
      public List<String> getNicksForMode(Action action, char mode)
      {
  