<|start_filename|>src/com/cavariux/twitchirc/Chat/Channel.java<|end_filename|>
package com.cavariux.twitchirc.Chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.cavariux.twitchirc.Core.TwitchBot;
import com.cavariux.twitchirc.Json.JsonArray;
import com.cavariux.twitchirc.Json.JsonObject;
import com.cavariux.twitchirc.Json.JsonValue;
import com.cavariux.twitchirc.TwitchAPIConnections.ChannelQueries;

/**
 * The channel object
 *
 * @author <NAME>
 * @version 1.0-Beta
 */
public class Channel {
	
	private String urln = "http://tmi.twitch.tv/group/user/$channel$/chatters";
	private String channel;
	private TwitchBot bot;
	private static HashMap<String, Channel> channels = new HashMap<String, Channel>();
	
	public static List<Channel> getChannels() {
		return new ArrayList<Channel>(channels.values());
	}
	
	/**
	 * The constructor of the channel object
	 *
	 * @param channel The name of the Channel
	 * @param bot     The bot that will be linked with
	 */
	private Channel(String channel, TwitchBot bot) {
		this.bot = bot;
		this.channel = channel;
		channels.put(channel, this);
	}
	
	/**
	 * Get a channel from an existing variable
	 *
	 * @param channel The channel name
	 * @param bot     The bot tha use it
	 * @return The channel
	 */
	public static final Channel getChannel(String channel, TwitchBot bot) {
		if (!channel.startsWith("#"))
			channel = "#" + channel;
		if (channels.containsKey(channel))
			return channels.get(channel);
		else
			return new Channel(channel, bot);
	}
	
	/**
	 * Gets the name of the Channel (Automatic if you only put the Channel object)
	 */
	public final String toString() {
		return channel;
	}
	
	/**
	 * Ban a user of the channel (Need Mod)
	 *
	 * @param user The user that will be banned
	 */
	public final void ban(User user) {
		this.bot.sendMessage("/ban " + user, this);
	}
	
	/**
	 * Timeout a player on the chat, useful for clearing spam (Need Mod)
	 *
	 * @param user The user that will be timeout
	 * @param time The time that will get timeout (Sometimes twitch change this)
	 */
	public final void timeOut(User user, int time) {
		this.bot.sendMessage("/timeout " + user + " " + time, this);
	}
	
	/**
	 * Unban a user from the chat (Need Mod)
	 *
	 * @param user The user that will get unban
	 */
	public final void unBan(User user) {
		this.bot.sendMessage("/unban " + user, this);
	}
	
	/**
	 * Slowmode on the chat (Need Mod)
	 *
	 * @param sec seconds of cooldown between messages of a user
	 */
	public final void slowMode(int sec) {
		this.bot.sendMessage("/slow " + sec, this);
	}
	
	/**
	 * Turns off the slowmode (Need Mod)
	 */
	public final void slowOff() {
		this.bot.sendMessage("/slowoff", this);
	}
	
	/**
	 * Turns the chat on subscribers only (Need Mod) (The channel needs partner with twitch)
	 */
	public final void subscribersOnly() {
		this.bot.sendMessage("/subscribers", this);
	}
	
	/**
	 * Turns off the chat only room (Need Mod)
	 */
	public final void suscribersOnlyOff() {
		this.bot.sendMessage("/subscribersoff", this);
	}
	
	/**
	 * Clears the chat useful for clearing spam (Need Mod)
	 */
	public final void clearChat() {
		this.bot.sendMessage("/clear", this);
	}
	
	/**
	 * Turn on the r9kbeta feature on Twitch (Need Mod)
	 */
	public final void r9kbeta() {
		this.bot.sendMessage("/r9kbeta", this);
	}
	
	/**
	 * Turns off the r9kbeta feature on Twitch (Need Mod)
	 */
	public final void r9kbetaOff() {
		this.bot.sendMessage("/r9kbetaoff", this);
	}
	
	/**
	 * Put a comercial on air for 30sec (Need Streamer/Editor)
	 */
	public final void commercial() {
		this.bot.sendMessage("/commercial", this);
	}
	
	/**
	 * Host a channel (Need Streamer/Editor)
	 *
	 * @param channel The target of the host
	 */
	public final void host(Channel channel) {
		this.bot.sendMessage("/host " + channel, this);
	}
	
	/**
	 * Unhost the hosted channel (Need Streamer/Editor)
	 */
	public final void unhost() {
		this.bot.sendMessage("/unhost", this);
	}
	
	/**
	 * Get the currently viewers (This method is on beta so it may not be optimized)
	 *
	 * @return A String[] with all the current viewers
	 */
	public final List<User> getViewers() {
		URL url;
		try {
			url = new URL(urln.replace("$channel$", channel.toString().substring(1)));
			URLConnection conn = url.openConnection();
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String inputLine = "";
			String str = "";
			while ((str = br.readLine()) != null) {
				inputLine = inputLine + str;
			}
			br.close();
			JsonObject jsonObj = JsonObject.readFrom(inputLine);
			JsonArray array = jsonObj.get("chatters").asObject().get("viewers").asArray();
			JsonArray array2 = jsonObj.get("chatters").asObject().get("moderators").asArray();
			List<User> viewers = new ArrayList<User>();
			for (JsonValue value : array)
				viewers.add(User.getUser(value.toString().substring(1, value.toString().length() - 1)));
			for (JsonValue value : array2)
				viewers.add(User.getUser(value.toString().substring(1, value.toString().length() - 1)));
			return viewers;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Get the currently viewers (This method is on beta so it may not be optimized)
	 *
	 * @return A String[] with all the current viewers
	 */
	public final List<User> getMods() {
		URL url;
		try {
			url = new URL(urln.replace("$channel$", channel.toString().substring(1)));
			URLConnection conn = url.openConnection();
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String inputLine = "";
			String str = "";
			while ((str = br.readLine()) != null) {
				inputLine = inputLine + str;
			}
			br.close();
			JsonObject jsonObj = JsonObject.readFrom(inputLine);
			JsonArray array2 = jsonObj.get("chatters").asObject().get("moderators").asArray();
			List<User> mods = new ArrayList<User>();
			for (JsonValue value : array2)
				mods.add(User.getUser(value.toString().substring(1, value.toString().length() - 1)));
			return mods;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Check if the user is a mod
	 *
	 * @param user The user
	 * @return true : false
	 */
	public final boolean isMod(User user) {
		return this.getMods().contains(user);
	}
	
	/**
	 * Check if the selected user is following the channel
	 *
	 * @param user The user to check
	 * @return If the user is following
	 */
	@SuppressWarnings("deprecation")
	public final boolean isFollowing(User user) {
		try {
			URL url = new URL("https://api.twitch.tv/kraken/users/" + user.toString().toLowerCase() + "/follows/channels/" + channel.substring(1).toLowerCase());
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			JsonObject jsonObj = JsonObject.readFrom(br.readLine());
			String str = jsonObj.get("channel").asObject().get("status").toString();
			return str.equals("null");
		} catch (IOException ex) {
			return false;
		}
	}
	
	/**
	 * @param user        The user to check
	 * @param oauth_token The token to access the information.
	 *                    This method requires the token to be generated with requested scope "channel_check_subscription"
	 * @return If the user is a sub
	 */
	@SuppressWarnings("deprecation")
	public final boolean isSubscribed(User user, String oauth_token) {
//		try {
//			URL url = new URL("https://api.twitch.tv/kraken/channels/" + channel.substring(1).toLowerCase() + "/subscriptions/" + user.toString().toLowerCase() + "?oauth_token=" + oauth_token);
//			URLConnection conn = url.openConnection();
//			conn.setRequestProperty("Client-ID", bot.getClientID());
//	        BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ));
//	        JsonObject jsonObj = JsonObject.readFrom(br.readLine());
//	        String str = jsonObj.get("_id").asString();
//	        return str.equals("404");
//		} catch (IOException ex) {
//			ex.printStackTrace();
//			return false;
//		}
		return ChannelQueries.isSubscriber(this, user, oauth_token, bot.getClientID());
	}
	
	
	/**
	 * Check if the channel is in Stream
	 *
	 * @return Returns the state
	 */
	public final boolean isLive() {
		return Channel.isLive(this, bot);
	}
	
	/**
	 * Get the game the streamer is streaming
	 *
	 * @return The game name
	 */
	public final String getGame() {
		if (!this.isLive()) return "";
		try {
			URL url = new URL("https://api.twitch.tv/kraken/streams/" + channel.substring(1));
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String strs = br.readLine();
			JsonObject jsonObj = JsonObject.readFrom(strs);
			String str = jsonObj.get("stream").asObject().get("game").asString();
			return str;
		} catch (IOException ex) {
			ex.printStackTrace();
			return null;
		}
	}
	
	/**
	 * Get the title that the Streamer put
	 *
	 * @return the title
	 */
	public final String getTitle() {
		if (!this.isLive()) return "";
		try {
			URL url = new URL("https://api.twitch.tv/kraken/streams/" + channel.substring(1));
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			JsonObject jsonObj = JsonObject.readFrom(br.readLine());
			String str = jsonObj.get("stream").asObject().get("channel").asObject().get("status").asString();
			return str;
		} catch (IOException ex) {
			return null;
		}
	}
	
	/**
	 * Get the viewers on that stream
	 *
	 * @return the number of viewers seeing the stream
	 */
	public final int getViewersNum() {
		if (!this.isLive()) return 0;
		try {
			URL url = new URL("https://api.twitch.tv/kraken/streams/" + channel.substring(1));
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			JsonObject jsonObj = JsonObject.readFrom(br.readLine());
			int i = jsonObj.get("stream").asObject().get("viewers").asInt();
			return i;
		} catch (IOException ex) {
			return 0;
		}
	}
	
	/**
	 * Get the language the streamer is streaming
	 *
	 * @return the language in the streamer is streaming
	 */
	public final String getLanguange() {
		try {
			URL url = new URL("https://api.twitch.tv/kraken/streams/" + channel.substring(1));
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			JsonObject jsonObj = JsonObject.readFrom(br.readLine());
			String str = jsonObj.get("stream").asObject().get("channel").asObject().get("language").asString();
			return str;
		} catch (IOException ex) {
			return null;
		}
	}
	
	/**
	 * Ge the total followers of that streamer
	 *
	 * @return the number of followers
	 */
	public final int getFollowersNum() {
		try {
			URL url = new URL("https://api.twitch.tv/kraken/channels/" + channel.substring(1) + "/follows");
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String inputLine = "";
			String str = "";
			while ((str = br.readLine()) != null) {
				inputLine = inputLine + str;
			}
			br.close();
			JsonObject jsonObj = JsonObject.readFrom(inputLine);
			int stri = jsonObj.get("_total").asInt();
			return stri;
		} catch (IOException ex) {
			System.out.println("Errur:");
			System.out.println(ex.getMessage());
			return 0;
		}
	}
	
	/**
	 * Get the total views of the streamer
	 *
	 * @return the total views of the streamer
	 */
	public final int getTotalViews() {
		try {
			URL url = new URL("https://api.twitch.tv/kraken/streams/" + channel.substring(1));
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			JsonObject jsonObj = JsonObject.readFrom(br.readLine());
			int str = jsonObj.get("stream").asObject().get("channel").asObject().get("views").asInt();
			return str;
		} catch (IOException ex) {
			return 0;
		}
	}
	
	/**
	 * Check if a channel is in Stream
	 *
	 * @param channel the channel to check
	 * @return Returns the state
	 */
	public static final boolean isLive(Channel channel, TwitchBot bot) {
		try {
			URL url = new URL("https://api.twitch.tv/kraken/streams/" + channel.toString().substring(1));
			URLConnection conn = url.openConnection();
			conn.setRequestProperty("Client-ID", bot.getClientID());
			BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			JsonObject jsonObj = JsonObject.readFrom(br.readLine());
			String str = jsonObj.get("stream").toString();
			return !str.equals("null");
		} catch (IOException ex) {
			return false;
		}
	}
}


<|start_filename|>src/com/cavariux/twitchirc/Core/TwitchBot.java<|end_filename|>
package com.cavariux.twitchirc.Core;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.cavariux.twitchirc.Chat.Channel;
import com.cavariux.twitchirc.Chat.User;

/**
 * The main object to start making your bot
 * @author <NAME>
 * @version 1.0-Beta
 */
public class TwitchBot {
	
	@SuppressWarnings("unused")
	private String whispers_ip = "";
	@SuppressWarnings("unused")
	private int whispers_port = 443;
	private boolean wen = true;
	private String user;
	private String oauth_key;
	private BufferedWriter writer;
	private BufferedReader reader;
	private ArrayList<String> channels = new ArrayList<String>();
	private String version = "v1.0-Beta";
	private boolean stopped = true;
	private String commandTrigger = "!";
	private String clientID = "";

	private static final Logger LOGGER = Logger.getLogger(TwitchBot.class.getName());
	
	public final List<Channel> getChannels(){
		return Channel.getChannels();
	}
	
	public TwitchBot(){}
	
	/**
	 * Here you can connect without having to connect to a chat group
	 */
	public void connect() {
		wen = false;
		connect("irc.twitch.tv", 6667);
	}
	
	/**
	 * The connect method alouds you to connect to the IRC servers on twitch
	 * @param ip The ip of the Chat group
	 * @param port The port of the Chat group
	 */
	public void connect(String ip, int port)
	{
		if (isRunning()) return;
		try{
			if (user == null || user == "")
			{
				LOGGER.log(Level.SEVERE, "Please select a valid Username");
				System.exit(1);
				return;
			}
			if (oauth_key == null || oauth_key == "")
			{
				LOGGER.log(Level.SEVERE,"Please select a valid Oauth_Key");
				System.exit(2);
				return;
			}
			
			@SuppressWarnings("resource")
			Socket socket = new Socket(ip, port);
			this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
			this.writer.write("PASS " + oauth_key + "\r\n");
			this.writer.write("NICK " + user + "\r\n");
			this.writer.write("USER " + this.getVersion() + " \r\n");
			this.writer.write("CAP REQ :twitch.tv/commands \r\n");
			this.writer.write("CAP REQ :twitch.tv/membership \r\n");
			this.writer.flush();
			
			String line = "";
			while ((line = this.reader.readLine()) != null)
			{
				 if (line.indexOf("004") >= 0) {
		                LOGGER.log(Level.INFO,"Connected >> " + user + " ~ irc.twitch.tv");
		                break;
		            }else {
		                LOGGER.log(Level.INFO,line);
		            }
			}
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	protected void onSub(User user, Channel channel, String message)
	{
		
	}
	
	/**
	 * Set the username that the connect method will use
	 * @param username Needs your <a href="http://www.twitch.tv">Twitch</a> Username to connect
	 */
	public final void setUsername(String username) {
		this.user = username;
	}
	
	/**
	 * Sets the required ClientID for the use of the api.
	 * @param clientID
	 */
	public final void setClientID(String clientID) {
		this.clientID = clientID;
	}
	
	/**
	 * Method to return the clientid.
	 * @return The clientid
	 */
	public final String getClientID() {
		if (this.clientID != null)
			return this.clientID;
		else {
			LOGGER.log(Level.INFO,"You need to give a clientID to use the TwitchAPI");
			return "";
		}
	}
	
	 /**
	  * Set the "password" that the <a href="connect">connect</a> method will use.
	  * @param oauth_key To get this key go to the <a href="http://twitchapps.com/tmi/">TwitchApps</a> and get it on the TMI section
	  */
	public final void setOauth_Key (String oauth_key)
	{
		this.oauth_key = oauth_key;
	}
	
	/**
	 * This method is called when a message is sent on the Twitch Chat.
	 * @param user The user is sent, if you put it on a String it will give you the user's nick
	 * @param channel The channel where the message was sent
	 * @param message The message
	 */
	protected void onMessage(User user, Channel channel, String message)
	{
		
	}
	
	/**
	 * This method is called when a command is sent on the Twitch Chat.
	 * @param user The user is sent, if you put it on a String it will give you the user's nick
	 * @param channel The channel where the command was sent
	 * @param command The command
	 */
	protected void onCommand(User user, Channel channel, String command)
	{
		
	}
	
	protected void onHost(User hoster, Channel hosted)
	{
	
	}
	
//	/**
//	 * This method is used if you want to send a command to the IRC server, not commontly used
//	 * @param message the command you will sent
//	 */
//	public void sendRawMessage(String message)
//	{
//		try {
//			this.writer.write(message + " \r\n");
//			this.writer.flush();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		LOGGER.log(Level.INFO,message);
//	}
	
	/**
	 * An int variation of the sendRawMessage(String)
     *
     * message had to be appended with .toString()
	 * @param message the command you will sent
	 */
	public void sendRawMessage(Object message)
	{
		try {
			this.writer.write(message + " \r\n");
			this.writer.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		LOGGER.log(Level.INFO, message.toString());
	}
	
	/**
	 * Send a message to a channel on Twitch (Don't need to be on that channel)
	 * @param message The message that will be sent
	 * @param channel The channel where the message will be sent
	 */
	public void sendMessage(Object message, Channel channel)
	{
		try {
			this.writer.write("PRIVMSG " + channel + " :" + message.toString() + "\r\n");
			this.writer.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		LOGGER.log(Level.INFO,"> MSG " + channel + " : " + message.toString());
	}
	
//	/**
//	 * Send a message to a channel on Twitch (Don't need to be on that channel)
//	 * @param message The message that will be sent
//	 * @param channel The channel where the message will be sent
//	 */
//	public void sendMessage(String message, Channel channel)
//	{
//		try {
//			this.writer.write("PRIVMSG " + channel + " :" + message + "\r\n");
//			this.writer.flush();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		LOGGER.log(Level.INFO,"> MSG " + channel + " : " + message);
//	}
//	
//	/**
//	 * A sendMessage variation with an int
//	 * @param message The message that will be sent
//	 * @param channel channel The channel where the message will be sent
//	 */
//	public void sendMessage(int message, Channel channel)
//	{
//		try {
//			this.writer.write("PRIVMSG " + channel + " :" + message + "\r\n");
//			this.writer.flush();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		LOGGER.log(Level.INFO,"> MSG " + channel + " : " + message);
//	}

	//<editor-fold desc="Rhodderz Code">

    /**
     * Returns the logger for this library.
     * @return Logger
     */
    public static Logger getLOGGER() {
        return LOGGER;
    }

    /**
     * Experimetal, see if we can change the nick of the bot.
     * @param newNick
     */
    public void setNick(String newNick){
        try {
            this.writer.write("NICK " + newNick + "\r\n");
        }catch (IOException ioe){

        }
    }

    //</editor-fold>
	
	/**
	 * The method to join an IRC channel on Twitch
	 * @param channel The channel name
	 * @return You can get the channel you just created
	 */
	@SuppressWarnings( "deprecation" )
	public final Channel joinChannel (String channel)
	{
		Channel cnl = Channel.getChannel(channel.toLowerCase(), this);
		sendRawMessage("JOIN " + cnl.toString().toLowerCase() + "\r\n");
		this.channels.add(cnl.toString());
		LOGGER.log(Level.INFO,"> JOIN " + cnl);
		return cnl;
	}
	
	/**
	 * Leaves the channel you want
	 * @param channel The channel you want to leave
	 */
	public final void partChannel (String channel)
	{
		Channel cnl = Channel.getChannel(channel.toLowerCase(), this);
		this.sendRawMessage("PART " + cnl);
		this.channels.remove(cnl);
		LOGGER.log(Level.INFO,"> PART " + channel);
	}
	
	/**
	 * No need to use this dev things
	 * @return a BufferedWrtier
	 */
	public final BufferedWriter getWriter ()
	{
		return this.writer;
	}
	
	/**
	 * Starts the full mechanism of the bot, this is the last method to be called
	 */
	public final void start()
	{
		if (isRunning()) return;
		String line = "";
		stopped = false;
		try {
			while ((line = this.reader.readLine( )) != null && !stopped) {
			    if (line.toLowerCase( ).startsWith("ping")) {
			    	LOGGER.log(Level.INFO,"> PING");
			        LOGGER.log(Level.INFO,"< PONG " + line.substring(5));
			        this.writer.write("PONG " + line.substring(5) + "\r\n");
			        this.writer.flush();
			    } else if (line.contains("PRIVMSG"))
			    {
			        String str[];
			        str = line.split("!");
			        final User msg_user = User.getUser(str[0].substring(1, str[0].length()));
			        str = line.split(" ");
			        Channel msg_channel;
			        msg_channel = Channel.getChannel(str[2], this);
			        String msg_msg = line.substring((str[0].length() + str[1].length() + str[2].length() + 4), line.length());
			        LOGGER.log(Level.INFO,"> " + msg_channel + " | " + msg_user + " >> " +  msg_msg);
			        if (msg_msg.startsWith(commandTrigger))
			        	onCommand(msg_user, msg_channel, msg_msg.substring(1));
			        if (msg_user.toString().equals("jtv") && msg_msg.contains("now hosting")) {
			        	String hoster = msg_msg.split(" ")[0];
			        	onHost(User.getUser(hoster), msg_channel);
			        }
			        onMessage(msg_user, msg_channel, msg_msg);
			    } else if (line.contains(" JOIN ")) {
			    	String[] p = line.split(" ");
			    	String[] pd = line.split("!");
			    	if (p[1].equals("JOIN"))
			    		userJoins(User.getUser(pd[0].substring(1)), Channel.getChannel(p[2], this));
				} else if (line.contains(" PART ")) {
			    	String[] p = line.split(" ");
			    	String[] pd = line.split("!");
			    	if (p[1].equals("PART"))
			    		userParts(User.getUser(pd[0].substring(1)), Channel.getChannel(p[2], this));
				} else if (line.contains(" WHISPER ")) {
					String[] parts = line.split(":");
					final User wsp_user = User.getUser(parts[1].split("!")[0]);
					String message = parts[2];
					onWhisper(wsp_user, message);
				} else if (line.startsWith(":tmi.twitch.tv ROOMSTATE")) {
			 
				} else if (line.startsWith(":tmi.twitch.tv NOTICE"))
			    {
			    	String[] parts = line.split(" ");
			    	if (line.contains("This room is now in slow mode. You may send messages every"))
			    	{
			    		LOGGER.log(Level.INFO,"> Chat is now in slow mode. You can send messages every " + parts[15] + " sec(s)!");
			    	} else if (line.contains("subscribers-only mode")) {
			    		if (line.contains("This room is no longer"))
			    			LOGGER.log(Level.INFO,"> The room is no longer Subscribers Only!");
			    		else
			    			LOGGER.log(Level.INFO,"> The room has been set to Subscribers Only!");
			    	} else {
			    		LOGGER.log(Level.INFO,line);
			    	}
			    } else if (line.startsWith(":jtv MODE "))
			    {
			    	String[] p = line.split(" ");
			    	if (p[3].equals("+o")) {
			    		LOGGER.log(Level.INFO,"> +o " + p[4]);
			    	} else {
			    		LOGGER.log(Level.INFO,"> -o " + p[4]);
			    	}
			    } else if (line.toLowerCase().contains("disconnected"))
			    {
				    LOGGER.log(Level.INFO, line);
				    this.connect();
			    } else
			    {
			        LOGGER.log(Level.INFO,"> " + line);
			    }
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Simply stops the bot.
	 */
	public void stop() {
		this.stopped = true;
		this.sendRawMessage("Stopping"); //so that the bot has one message to process to actually stop
	}
	
	/**
	 * Stops the bot and sends a message to all channels the bot has joined
	 * @param message Message to send to all channels
	 */
	public void stopWithMessage(String message) {
		this.stopped = true;
		for (String cnl : channels) {
			this.sendMessage(message, Channel.getChannel(cnl, this));
		}
	}

	public boolean isRunning() {
		return !stopped;
	}
	
	/**
	 * A user joins the channel
	 * @param user The user that has join
	 * @param channel The channel he joined
	 */
	protected void userJoins(User user, Channel channel)
	{
		
	}
	
	/**
	 * A user leaves/parts the channel
	 * @param user The user that has left
	 * @param channel The channel he left
	 */
	protected void userParts(User user, Channel channel)
	{
		
	}
	
	/**
	 * This will let you whisper to the specified user
	 * @param user The user to send the message
	 * @param message The messsage to send
	 */
	public void whisper(User user, String message)
	{
		if (!channels.isEmpty()) {
			this.sendMessage("/w " + user + " " + message, Channel.getChannel(channels.get(0), this));
			
		} else if (!wen) {
			LOGGER.log(Level.INFO,"You have to be either connected to at least one channel or join another Server to be able to whisper!");
		} else {
			sendRawMessage("PRIVMSG #jtv :/w " + user + " " + message);
		}
	}
	
	/**
	 * When overrided this method lets you check for whispers.
	 * @param user The user that sent it
	 * @param message The message he sent
	 */
	protected void onWhisper(User user, String message)
	{
	}
	
	/**
	 * Sets the whispers ip (000.000.000.000:0000)
	 * @param ip The whole ip
	 */
	protected final void setWhispersIp(String ip)
	{
		if (!ip.contains(":")) {
			LOGGER.log(Level.INFO,"Invaid ip!");
			return;
		}
		String[] args = ip.split(":");
		whispers_ip = args[0];
		whispers_port = Integer.parseInt(args[1]);
	}
	
	/**
	 * Sets the whispers ip
	 * @param ip The ip to connect
	 * @param port The port to connect with
	 */
	protected final void setWhispersIp(String ip, int port)
	{
		whispers_ip = ip;
		whispers_port = port;
	}
	
	/**
	 * Sets the string that will mark a message as command if it begins with it
	 * @param trigger string to mark a message as command
	 */
	public void setCommandTrigger(String trigger) {
		this.commandTrigger = trigger;
	}
	
	/**
	 * Get the version of the TwitchIRC lib
	 * @return the version of the TwitchIRC lib
	 */
	public final String getVersion()
	{
		return "TwitchIRC "+version;
	}
	
}
