# -*- coding: utf-8 -*-
import asyncio
import calendar
import json as m_json
import logging
import os
import random
import re
import urllib
from collections import namedtuple
from datetime import datetime
from urllib import parse, request

import discord
import giphypop
import pyjokes
import requests
import wikipedia
from bs4 import BeautifulSoup
from googleapiclient.discovery import build
from pytz import timezone
from tabulate import tabulate
from wordnik import WordApi

# TODO LIST
""" make a reminder,  voice channel join and play music (Works but not needed right now.),
channel specific updates (Example: Danny's bot), adjust !box, add restart."""

# set up logging module to output diagnostic to the console.
logging.basicConfig()

# Create an instance of Giphy.
g = giphypop.Giphy()

# Open opus DLL which is in the same path as bot. For music bot applications.
if not discord.opus.is_loaded():
    discord.opus.load_opus('libopus-0.dll')

# Open file with login info.
Proto_info = open("C:\Python Discord bot\Prototype\login.txt", "r")
info = Proto_info.read().split(":")
Proto_info.close()

# Open file with status changes.
status_info = open("C:\Python Discord bot\Prototype\status.txt", "r")
status = status_info.read().splitlines()
status_info.close()

# Open file with command list part 1.
cmd_info = open("C:\Python Discord bot\Prototype\command_first.txt", "r")
command_one = cmd_info.read().splitlines()
cmd_info.close()

# Open file with command list part 2.
cmd_info2 = open("C:\Python Discord bot\Prototype\command_second.txt", "r")
command_two = cmd_info2.read().splitlines()
cmd_info2.close()

# Twitch Emote list.
inputF = open('C:\DiscordPics\TwitchEmotes.txt')
twitchEmotes = inputF.read().splitlines()
inputF.close()

# Pokemon model GIF list.
inputF = open('C:\DiscordPics\PokemonNames.txt')
pokemonNames = inputF.read().splitlines()
inputF.close()

# Create instance of Discord
client = discord.Client()
# ---------------------------------------------------------------------------------------------------------------------
# Parameters of making trivia questions. Currently broken as of async branch.
Trivia = namedtuple('Trivia', ['question', 'choices', 'answer'])

# List of Trivia questions that will be picked at random via !trivia command
trivia_q = [
    Trivia('Morrighan is a goddess from which game?', ['Dragon Nest', 'Mabinogi', 'Vindictus', 'Atlantis'], 1),
    Trivia('Morrighan is the goddess of?', ['Peace', 'War and Light', 'War and Destruction', 'War and Vengeance'], 3),
    Trivia('A pregnant goldfish is called a?', ['Twat', 'Twit', 'Twix', 'None'], 1),
    Trivia('What\'s the name for the excessive bodily hair growth in women?',
           ['Hirsutism', 'Adrogyny', 'Masculinism', 'Feminization'], 0),
    Trivia('What was Elvis Presley\'s last name?', ['Arthur', 'Leroy', 'Aaron', 'Lewis'], 2),
    Trivia('Which season and episode was South Park\'s "Safe Space"?', ['S9E1', 'S8E10', 'S9E5', 'S8E5'], 2),
    Trivia('Which programming language am I built on?', ['C++', 'Brainfuck', 'Lua', 'Python'], 3),
    Trivia('What group of people make up 65% of Elvis impersonators?',
           ['African Americans', 'Caucasians', 'Asians', 'Indians'], 2),
    Trivia('All bats turn what direction when leaving a cave?', ['Left', 'Right', 'Up', 'Down'], 0),
    Trivia('Audi is just a higher end _______ car.', ['Volvo', 'Volkswagen', 'Mazda', 'Hyundai'], 1),
    Trivia('Who is known to shoot eggs and fire out of their snout?', ['Yoshi', 'Birdo', 'Q*bert', 'Freddy'], 1),
    Trivia('Germany is bordered to the east by how many countries?', ['None', 'One', 'Two', 'Three'], 3),
    Trivia('In *The Lion King*, who played the voice of Simba?',
           ['Ernie Sabella', 'Jeremy Irons', 'Matthew Broderick', 'Robert Guillaume'], 2),
    Trivia('In the sentence, "The moon rose on the horizon." What is the preposition?',
           ['"Moon"', '"The"', '"Rose"', '"On"'], 3),
    Trivia('Kimchi originated from?', ['Korea', 'Japan', 'China', 'Taiwan'], 0),
    Trivia('King Henry the VIII had how many wives?', ['None', 'One', 'Six', 'Eight'], 2),
    Trivia('Nintendo 64 was almost called _______ 64.', ['Ultra', 'Mega', 'Giga', 'Dreamcast'], 0),
    Trivia('Strawberries have more Vitamin ___ than oranges.', ['D', 'C', 'B12', 'E'], 1),
    Trivia('Team Fortress 2: Engineers are able to build what guns?', ['Laser', 'Rifle', 'Explosive', 'Sentry'], 3),
    Trivia('The American Civil War took place from 1861 to _____.', ['1863', '1864', '1865', '1866'], 2),
    Trivia('Which was the first color handheld video game console?',
           ['Nintendo Game Boy Color', 'Sega Game Gear', 'Neo Geo Pocket Color', 'Atari LYNX'], 3),
    Trivia('The average ant can lift how many times its own weight?',
           ['Double', 'Triple', 'Fifty', 'It doesn\'t lift bro.'], 2),
    Trivia('The first Toy Story movie was released in?', ['1991', '1993', '1995', '1997'], 2),
    Trivia('Which automobiles are front-wheel drive?',
           ['Honda Civic DX', 'Nissan Sentra', 'Audi A4', 'All of the above'], 3),
    Trivia('The original Coca-Cola was?', ['Green', 'Blue', 'White', 'Orange'], 0),
    Trivia('Destroyers are exlusive to which race?', ['Lyn', 'Jin', 'Lycandi', 'Gon'], 3),
    Trivia('Which race only has 1 gender?', ['Jin', 'Gon', 'Yun', 'Lyn'], 2),
    Trivia('What is the role of Force Master in PVE party?',
           ['Support', 'Useless Class', 'Tank/Support', 'DPS/Support'], 3),
    Trivia('Which anime is the best?', ['Corey in the House', 'Avatar', 'King of the Hill', 'Tentale sluts 4'], 0),
    Trivia('Which faction goes against the Blackram Pirates?',
           ['Cerulean', 'Bamboo Guard', 'Skyhaven Resistance', 'Talus Dominion'], 1),
]

# !fight command words to use.
verblist = [' shanked ', ' shot ', ' punched ', ' kicked ', ' kneed ', ' bludgeoned ', ' smashed ',
            ' pummeled ', ' broke ', ' assaulted ', ' killed ', ' uppercut ', ' tackled ', ' jabbed ',
            ' choked ', ' headbutted ', ' tripped ']
attacklist = [', threw them in a ditch and told them to git gud.',
              ', chained them to a tree and left them there to rot.',
              ', and pushed them off a cliff.',
              ', kicked their shins and spat in their face.',
              ', chained them to a bed and had a good time with them.',
              ', broke their glasses and took their lunch money.',
              ', and sacrificed them for our lord and savior Cthulu.',
              ', went to their castle and took the Princess back.',
              ', and pushed them down into whirlpool of quicksand.',
              ', and shot an arrow into their knee.',
              ', tied them to a chair and played the "Friday" song on repeat.',
              ', tied them to a chair and played the "Baby" song by Beiberz',
              ', depleted their HP and took their loot.',
              ', then {0.author.mention} got offended and ragequit.',
              ', and threw them into a tank full of starved piranhas.',
              ', and put electric clamps onto their nipples.',
              ', and burned them alive.',
              ', and made them eat moldy pizza.',
              ', and pierced them with a unicorn strap on.',
              ', and crushed them to death with boulders.',
              ', and put them in an elevator with elevator music for eternity.']

# List of words that trigger a corresponding response when mentioning @FRACTAL AKA 8ball questions.
bot_question = ['should ', 'Should ', 'SHOULD ', 'can ', 'Can ', 'CAN ', 'will ', 'Will ', 'WILL ', 'may ', 'May ',
                'MAY ',
                'are ', 'Are ', 'ARE ', 'might ', 'Might ', 'MIGHT ', 'is ', 'Is ', 'IS ', 'do ', 'Do ', 'DO ',
                'would ',
                'Would ', 'WOULD ', 'was ', 'Was ', 'WAS ', 'am ', 'Am ', 'AM ', 'did ', 'Did ', 'Did ', 'DID ', 'how ',
                'How ', 'HOW ', 'does ', 'Does ', 'DOES ', 'could ', 'Could ', 'COULD ', 'would ', 'Would ', 'WOULD'
                                                                                                             'will',
                'Will', 'WILL', 'did', 'Did', 'DID']

# Response to @FRACTAL questions
magicEight = ['Yes.', 'I decided to say yes, just cause.', 'Absolutely.', 'Definitely.', 'Lol no.',
              'I think so, {0.author.mention}.', 'Most likely, {0.author.mention}',
              'I\'m afraid not, {0.author.mention}', 'No.', 'Of course!',
              'I\'m busy. Ask me later, {0.author.mention}.', 'Unfortunately, no.', 'Hell yes!', 'Yep.',
              'Sure why not?',
              'Absolutely not!', 'Don\'t count on it.', 'My reply is no.', 'My sources say no, {0.author.mention}',
              'Probably, {0.author.mention}',
              'Probably not, {0.author.mention}.', 'Yes... :smirk:', 'I\'ll let Fractalus decide for me.', 'Nah.',
              'Mhm.', 'Ya.',
              'A little bird told me yes, {0.author.mention}.' 'Possibly. ', 'Definitely. ',
              'Absolutely not. :anguished:  ', 'I think not, {0.author.mention}', 'Yes. ', 'No. ',
              'Let me think about it :pensive: ', 'I think so. {0.author.mention}', 'Sure why not. ',
              'No... {0.author.mention}',
              'Probably. ', ' I say yes. :+1:', 'I do not think so, {0.author.mention} ',
              'Let me get back to you on that. {0.author.mention}', 'Nope. ', 'Yup. ˙͜>˙', 'Yep. ',
              'My sources say yes, {0.author.mention}',
              'I don`t know, {0.author.mention}', 'Hell yes! {0.author.mention}', 'Absolutely.', 'I`m feeling a no...',
              'I believe so!',
              'I am uncertain.', 'Ask me later.', 'Of course.', 'Of course not. :kissing:',
              'No, not really...', 'Sure.', 'A friend of yours said yes, {0.author.mention}', 'Mhm. {0.author.mention}',
              'A little bird told me no, {0.author.mention}']
# ---------------------------------------------------------------------------------------------------------------------
# '111889796946759680', '90588624512356352', '90939385553383424', '73651876540723200', '79258673020411904'
# My ID.
ADMIN = ['90829628691709952']

command_count = 0
bot_game = 'Digital Ocean'

voice = None
player = None
music_que = []

timeout_store = 0
pwr_timeout = {}


# Defining Youtube Search API function
def youtube_search(search_string, max_results=5):
    youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
                    developerKey=DEVELOPER_KEY)

    # Call the search.list method to retrieve results matching the specified
    # query term.
    search_response = youtube.search().list(q=search_string, part="id,snippet", maxResults=max_results).execute()

    videos = []
    # Add each result to the appropriate list, and then display the lists of
    # matching videos, channels, and playlists.
    for search_result in search_response.get("items", []):
        videos.append(
            '**' + search_result['snippet']['title'] + '**\n<http://youtu.be/' + search_result['id']['videoId'] + '>\n')
    return videos



# Class to make !trivia and run !trivia
class GuessingState(object):
    STARTED = 1,  # started a !trivia session
    GUESSED = 2,  # did a single guess via !guess
    ENDED = 3,  # the game has ended

    def __init__(self, message):
        self.current_state = GuessingState.STARTED
        self.author = message.author
        self.channel = message.channel
        self.trivia = random.choice(trivia_q)
        self.show_trivia()

    def show_trivia(self):
        message = [self.trivia.question, '']
        for index, choice in enumerate(self.trivia.choices):
            message.append('{}.  {}'.format(index, choice))

        message.append('')
        message.append('Select an answer by typing `!guess <number>`, IE. `!guess 0`.')
        message.append('You may give up by typing `!giveup`.')
        message.append('You have **two** guess attempts.')
        yield from client.send_message(self.channel, '\n'.join(message))

    def do_guess(self, answer):
        if self.current_state == GuessingState.ENDED:
            return

        try:
            answer = int(answer)
        except ValueError:
            return client.send_message(self.channel, 'You must input a numeric answer.')

        if answer == self.trivia.answer:
            yield from client.send_message(self.channel, 'You are correct! The trivia has now ended.')
            self.current_state = GuessingState.ENDED
        else:
            if self.current_state == GuessingState.STARTED:
                yield from client.send_message(self.channel, 'Incorrect. You have one more guess.')
                self.current_state = GuessingState.GUESSED
            else:
                msg = 'You are incorrect and out of answers. The correct answer was **"{0.author.mention}"**.'
                yield from client.send_message(self.channel, msg.format(self.trivia.choices[self.trivia.answer]))
                self.current_state = GuessingState.ENDED

    def quit(self):
        msg = 'Giving up so easily? The correct answer was "**{}**".'.format(self.trivia.choices[self.trivia.answer])
        yield from client.send_message(self.channel, msg)
        self.current_state = GuessingState.ENDED

    @property
    def is_over(self):
        return self.current_state == GuessingState.ENDED


# a dict of userIDs to GuessingState objects
current_games = {}


# Get bot uptime.
def get_bot_uptime(client):
    now = datetime.utcnow()
    delta = now - client.uptime
    hours, remainder = divmod(int(delta.total_seconds()), 3600)
    minutes, seconds = divmod(remainder, 60)
    days, hours = divmod(hours, 24)
    if days:
        fmt = 'I have been running for **{d} days, {h} hours, {m} minutes, and {s} seconds**'
    else:
        fmt = 'I have been running for **{h} hours, {m} minutes, and {s} seconds**'

    return fmt.format(d=days, h=hours, m=minutes, s=seconds)


# Removes unwanted HTML crap via regex. Used with remove_tags function.
TAG_RE = re.compile(r'<[^>]+>')


def remove_tags(text):
    # re.sub('<[^>]*>', '', text)
    return TAG_RE.sub('', text)


# JOIN and LEAVE server notifications
@client.async_event
def on_member_join(member):
    if str(member.server.id) != '91335971232043008 90833638555406336 90939613044039680 ' \
                                '112406723771281408 90904264594964480 91335971232043008 73656163517857792':
        server = member.server
        yield from client.send_message(member.server.channels[0],
                                       ':tada::confetti_ball: Greetings **{0.mention}**, welcome to the **{1.name}** server! :confetti_ball::tada:'.format(
                                               member, server))
        print('Member joined: ')
        print(member)


@client.async_event
def on_member_remove(member):
    if str(member.server.id) != '91335971232043008 90833638555406336 90939613044039680 ' \
                                '112406723771281408 90904264594964480 91335971232043008 73656163517857792':
        yield from client.send_message(member.server.channels[0],
                                       ":warning: **{0.mention}** has left the server.".format(member))
        print('Member left: ')
        print(member)


# TODO Move commands to separate modules/plugins
@client.async_event
def on_message(message):
    global magicEight
    global bot_question
    global MODS
    global command_count
    global pwr_timeout
    global timeout_store
    global option
    global ownerID
    global firstTime
    global skipCount
    global skipperlist
    global voice
    global player
    global music_que

    current_time = datetime.now()
    if message.author == client.user:
        return
    # create a permanent invite for users to give to others using XKCD format.
    if message.content.casefold() == "/invite".casefold():
        command_count += 1
        invite = client.create_invite(destination=message.channel, xkcd=True, max_age=0)
        if invite is not None:
            yield from client.send_message(message.channel,
                                           "Here's your invite!\n{}\n\nInvite expires in 30 minutes.".format(
                                                   invite.url))
        else:
            yield from client.send_message(message.channel, "Unable to create invite. Try again later.")

    # twitch keyword listener. Allow use of Twitch Emotes in daily chat.
    if message.content.startswith('/') == False:
        try:
            # Check the folder if the word is in file; Reverse order to allow use of multi contained emotes
            # IE Kappa, KappaRoss, KappaClaus, KappaHD, ETC.
            for t in reversed(twitchEmotes):
                if t.lower() in message.content.lower():
                    os.chdir('C:\DiscordPics\Twitch emotes')
                    yield from client.send_file(message.channel, t + '.jpg')
                break
        except Exception:
            pass

    # pokemon keyword listener. Allow viewing of live pokemon sprites directly from the games.
    if message.content.startswith('pkmn') and len(message.content.split()) == 2 \
            or message.content.startswith('Pkmn') and len(message.content.split()) == 2:
        try:
            for p in pokemonNames:
                if p.lower() in message.content.lower():
                    os.chdir('C:/DiscordPics/Pokemon')
                    yield from client.send_file(message.channel, p + '.jpg')
                    break
        # Return message if file name is not found in computer. TODO check why this exception is not reached.
        except FileNotFoundError:
            yield from client.send_message(message.channel,
                                           'Incorrect input or spelling. Format `pkmn <name>-<form or gender>`')
    elif message.content.startswith('pkmn') and len(message.content.split()) == 1:
        yield from client.send_message(message.channel, "You\'ve got to give me a Pokemon name...")

    # Twitch.tv command checks twitch channels to see their status, game played and viewer count.
    if message.content.startswith('/twitch') and len(message.content.split()) == 2:
        command_count += 1
        twitch_channel = message.content.split()[-1].lower()
        if twitch_channel == 'jaesung':
            twitch_channel = 'lsjjws3'
        if twitch_channel == 'suk':
            twitch_channel = 'suk12355'
        r = requests.get('https://api.twitch.tv/kraken/streams/' + twitch_channel)
        if r.status_code == 200:
            twitch_data = r.json()
            if twitch_data['stream'] == None:
                yield from client.send_message(message.channel,
                                               twitch_channel + '\'s channel is currently **OFFLINE**.')
            else:
                yield from client.send_message(message.channel, twitch_channel + '\'s channel is currently **ONLINE**!')
                yield from client.send_message(message.channel,
                                               twitch_channel + ' is currently playing **{}** with **{}** viewers!\n{}'.format(
                                                       twitch_data['stream']['game'],
                                                       str(twitch_data['stream']['viewers']),
                                                       'http://www.twitch.tv/' + twitch_channel))
        elif r.status_code == 404:
            yield from client.send_message(message.channel,
                                           'Invalid channel. It does not exist or you typed it incorrectly.')
        elif r.status_code == 422:
            yield from client.send_message(message.channel,
                                           'The channel you specified: **{}** is a justin.tv channel and doesnt work on Twitch or it is a banned account.'.format(
                                                   twitch_channel))
    elif message.content.startswith('/twitch') and len(message.content.split()) == 1:
        yield from client.send_message(message.channel, 'Please format your `!twitch` input as `!twitch <channelname>`')
    elif message.content.startswith('/twitch') and len(message.content.split()) > 2:
        yield from client.send_message(message.channel, 'The `/twitch` function only takes **1** argument.')
    # --------------------------------------------------------------------------------------------------------------------
    # Check if bot is alive.
    if message.content.startswith('Frac?'):
        yield from client.send_message(message.channel, "Yes, human? I am operating as intended.")

    # Completely turn off bot script. Needs manual start up for now.
    if message.content.startswith('/stop') and str(message.author.id) in MODS:
        yield from client.send_message(message.channel, '`F.R.A.C.T.A.L. has shut down.`')
        yield from client.logout()

    # Check channel ID in a server or checks user IDs. Start of counting command use.
    if message.content.startswith('/chid'):
        command_count += 1
        yield from client.send_message(message.channel, "This **channel ID** is: `{}`".format(message.channel.id))
    elif message.content.startswith('/sid'):
        command_count += 1
        yield from client.send_message(message.channel, 'The **server ID** is: {}'.format(message.channel.server.id))
    elif message.content.startswith('/id') and len(message.content.split()) == 2:
        command_count += 1
        try:
            thenames = message.mentions[0].id
            yield from client.send_message(message.channel, "This **member's ID** is: `{}`".format(thenames))
        except IndexError:
            thenames = message.content.replace('/id', '').strip()
            IDs = discord.utils.find(lambda m: m.name == thenames, message.channel.server.members)
            if IDs is not None:
                gottem = IDs.id
                yield from client.send_message(message.channel, "This member's ID is: `{}`".format(gottem))
            else:
                yield from client.send_message(message.channel, "This member doesn\'t exist bro.")
    elif message.content.startswith('/id') and len(message.content.split()) == 1:
        command_count += 1
        yield from client.send_message(message.channel, "**Your** Discord ID is: `{}`".format(message.author.id))

    # Checks info of the server this command is used in. /data checks commands used, members in all servers connected.
    # /where displays list servers of where bot is located.
    if message.content.startswith('/server'):
        command_count += 1
        try:
            '''
            online_number = len([member.id for member in message.channel.server.members if member.status /= 'offline'])
            '''
            serverinfo = "Server name: {0}\nOwner: {1}\nRegion: {2}\nID: {3}\nChannels: {4}\nMember Count:" \
                         " {5}\nServer Icon: ".format(
                    message.channel.server.name, message.channel.server.owner, message.channel.server.region,
                    message.channel.server.id, len(message.channel.server.channels),
                    len(message.channel.server.members))
            yield from client.send_message(message.channel,
                                           '```' + serverinfo + '```' + "{}".format(message.channel.server.icon_url))
        except AttributeError:
            yield from client.send_message(message.channel, 'You cannot use this command in private messages.')
    elif message.content.startswith('/data'):
        command_count += 1
        totalserver = len(client.servers)
        totalmember = len(set(list([member.id for s in client.servers for member in s.members])))
        members = [member for server in client.servers for member in server.members]
        yield from client.send_message(message.channel,
                                       '`<Since the last reset>`\n\n'
                                       '`I am connected to:` **{0}** servers.'
                                       '\n`I have seen:` **{1}** unique members.'
                                       '\n`I have executed:` **{2}** commands.'
                                       '\n\n{3}'.format(str(totalserver), str(totalmember), str(command_count),
                                                        get_bot_uptime(client)))

    if message.content.startswith('!uptime') or message.content.startswith('/uptime'):
        yield from client.send_message(message.channel, get_bot_uptime(client))

    if message.content.startswith('/join') and len(message.content.split()) == 2 \
            or message.content.startswith('!join') and len(message.content.split()) == 2:
        yield from client.send_message(message.channel, 'Are you absolutely sure you want me to join that server?'
                                                        ' Type `yes` or `no`')
        user_reply = yield from client.wait_for_message(timeout=10.0, author=message.author)
        answer = ['yes', 'no']
        try:
            if user_reply is None:
                fmt = 'Since you didn\'t respond, I won\'t join the server.'
                yield from client.send_message(message.channel, fmt)
            if user_reply.content.lower() == answer[1]:
                yield from client.send_message(message.channel, 'Okay, I won\'t join.')
            elif user_reply.content.lower() == answer[0]:
                yield from client.accept_invite(message.content.split()[1])
                mess = 'Successfully joined your server! ' \
                       'If you want me to be fully functional, give me `Manage Roles` permissions.'
                yield from client.send_message(message.channel, mess)
            else:
                yield from client.send_message(message.content, 'That\s not a `yes` or `no`. ˙͜>˙')
        except discord.errors.InvalidArgument:
            yield from client.send_message(message.channel, 'Something went awry. Please try again. *Or I\'m banned '
                                                            'from that server.*')
        except AttributeError:
            pass

    # Hush servers or channels so bot doesn't answer them.
    # Do not continue if user does not have kick permissions.
    '''
    if message.content.startswith('/ignore') and message.channel.permissions_for(message.author).can_kick_members:

        # Load hush list. This is created automatically on the first message
        # received.
        with open('configs/hush.json') as data:
            hushed = json.load(data)

        # Server hush
        if message.content == '/ignore server':
            hushed[message.server.id] = 'server'
            yield from client.send_message(message.channel,
                                           '**Ignoring Server!**\nI will no longer respond to commands in this server.'
                                           'Use `/listen` if you want to use bot commands here again.')

        # Channel hush
        elif message.content == '/ignore channel':
            hushed[message.channel.id] = 'channel'
            yield from client.send_message(message.channel,
                                           '**Ignoring Channel!**\nI will no longer respond to commands in this channel.'
                                           'Use `/listen` if you want to use bot commands here again.')

        # Save hush list.
        with open('configs/hush.json', 'w') as data:
            json.dump(hushed, data, indent=4)
    elif message.content.startswith('/ignore') and message.author.id not in ADMIN:
        yield from client.send_message(message.channel,
                                       ':no_entry_sign: You do not have permission to use this command.')


    # Block a user from using bot commands entirely.
    if message.content.startswith('/blacklist') and message.author.id in ADMIN or \
                    message.content.startswith('/blacklist') and message.channel.permissions_for(
                    message.author).can_kick_members:
        if message.author.id in ADMIN and message.content.split(' ')[1] == 'GLOBAL':
            srv = 'GLOBAL'
        else:
            srv = message.server.id
        with open('configs/plugs.json') as data:
            plugs = json.load(data)
        for mention in message.mentions:
            plugs[mention.id] = srv
            yield from client.send_message(message.channel,
                                           ':heavy_check_mark: {} has been blacklisted.'.format(mention.name))
        with open('configs/plugs.json', 'w') as data:
            json.dump(plugs, data, indent=4)
    '''

    # Call every person in a specific role.
    if message.content.startswith('/call') and message.author.id in ADMIN:
        role_to_mention = message.content.split(' ', 1)[1].lower()

        if role_to_mention != '@everyone':
            mentions = []  # holds mention strings
            for x in message.server.roles:
                if x.name.lower() == role_to_mention:
                    for y in message.server.members:
                        if discord.utils.find(lambda m: m == x, y.roles) != None:
                            mentions.append(y.mention)
        # Yeah, that *is* a shitty way of doing it.
        if mentions:
            yield from client.send_message(message.channel,
                                           '{}\n\n {} has summoned you all.'.format(' | '.join(mentions),
                                                                                    message.author.mention))
        else:
            yield from client.send_message(message.channel,
                                           'That role doesn\'t exist in this server, {}'.format(message.author.mention))

    # Location of bot in whatever servers.
    if message.content.startswith("/where"):
        server_list = []
        for s in client.servers:
            server_list.append(s.name)
        server_string = '\n'.join(server_list)
        yield from client.send_message(message.author, '**I am in these severs**\n\n' + server_string)
    # --------------------------------------------------------------------------------------------------------------------
    if message.content.startswith('hello') and len(message.content.split()) == 1 \
            or message.content.startswith('hi') and len(message.content.split()) == 1 \
            or message.content.startswith('hi bot') and len(message.content.split()) == 2 \
            or message.content.startswith('hiya') and len(message.content.split()) == 1 \
            or message.content.startswith('hola') and len(message.content.split()) == 1:
        hilist = ['Hello there, {0.author.mention}!', 'Why, hello {0.author.mention}.',
                  'Nice to see you, {0.author.mention}',
                  'Hello {0.author.mention}, hope you are doing well. :blush:',
                  'Hey {0.author.mention}. It`s nice to see you.',
                  'Sup {0.author.mention}, having fun today?', '今日は {0.author.mention}. いい　天気ですね?',
                  '안녕 {0.author.mention}! 만마서 반갑습니다~', 'Hey {0.author.mention}. What`s up?',
                  'What`s up {0.author.mention}! Hope your day has been going well.',
                  "Hullo {0.author.mention}. :relaxed:", "Heyo! {0.author.mention}", 'Hi {0.author.mention}. ˙͜>˙']
        yield from client.send_message(message.channel, random.choice(hilist).format(message))

    if message.content.startswith('thanks bot') and len(message.content.split()) == 2 \
            or message.content.startswith('Thanks bot') and len(message.content.split()) == 2 \
            or message.content.startswith('Thanks Bot') and len(message.content.split()) == 2 \
            or message.content.startswith('THANKS BOT') and len(message.content.split()) == 2 \
            or message.content.startswith('TY BOT') and len(message.content.split()) == 2 \
            or message.content.startswith('THX BOT') and len(message.content.split()) == 2:
        tylist = ['You`re very welcome, {0.author.mention}!', 'But of course. :wink:',
                  'No problem, {0.author.mention}.', 'Any time, {0.author.mention}.',
                  'You`re welcome! {0.author.mention}', 'NP. {0.author.mention}']
        yield from client.send_message(message.channel, random.choice(tylist).format(message))

    if message.content.startswith('DN') or message.content.startswith('KDN') or message.content.startswith('dn'):
        dnlist = ["Dragon Nest? Disconnect Nest. :electric_plug:", "Dragon Nest? CC :credit_card: Nest.",
                  "Dragon Nest? Dead game.", "Dragon Nest? Fashion Nest. :dress:", 'Dragon Nest? Lost cause.',
                  'Dragon Nest? Why are you still playing it? :confused:',
                  'Dragon Nest? Cancer nest :mask:',
                  'Dragon Nest? 99% Cash shop updates and events.']
        yield from client.send_message(message.channel, random.choice(dnlist))

    if message.content.startswith('bdo') or message.content.startswith('BDO') or message.content.startswith('Bdo'):
        bdolist = ['Black Desert Online? Man what a pretty shitty game.',
                   'Black Desert Online? Why are you talking about that casual game?',
                   'Black Desert Online? 100% Pay2win.',
                   'Black Desert Online? Economic Simulator 2015',
                   'Black Desert Online? Where\'s the content?', 'Black Desert Online? Incredibly pay2win.',
                   'Black Desert Online? Massive failure of the year.', 'Black Desert Online? Empty Desert Online.']
        yield from client.send_message(message.channel, random.choice(bdolist))

    if message.content.startswith('rekt') or message.content.startswith('REKT') or message.content.startswith('Rekt'):
        rektlist = ['☐ Not REKT ☑ REKT ☑ Left4Rekt', '☐ Not REKT ☑ REKT ☑ REKTangle', '☐ Not REKT ☑ REKT ☑ SHREKT',
                    '☐ Not REKT ☑ REKT ☑ REKT-it Ralph', '☐ Not REKT ☑ REKT ☑ Total REKTall',
                    '☐ Not REKT ☑ REKT ☑ The Lord of the REKT', '☐ Not REKT ☑ REKT ☑ The Usual SusREKTs',
                    '☐ Not REKT ☑ REKT ☑ North by NorthREKT', '☐ Not REKT ☑ REKT ☑ REKT to the Future',
                    '☐ Not REKT ☑ REKT ☑ Once Upon a Time in the REKT',
                    '☐ Not REKT ☑ REKT ☑ The Good, the Bad, and the REKT',
                    '☐ Not REKT ☑ REKT ☑ LawREKT of Arabia', '☐ Not REKT ☑ REKT☑ Tyrannosaurus REKT',
                    '☐ Not REKT ☑ REKT ☑ eREKTile dysfunction', '☑ REKT' '☐ Not REKT ☑ REKT',
                    '☐ Not REKT ☑ REKT ☑ www.rekkit.com', '☐ Not REKT ☑ REKT ☑ Rektflix',
                    '☐ Not REKT ☑ REKT ☑ RektBox 360', '☐ Not REKT ☑ REKT ☑RectCraft',
                    '☐ Not REKT ☑ REKT ☑ Left 4 Rekt']
        yield from client.send_message(message.channel, random.choice(rektlist))

    # response to hostile
    if message.content.startswith('fuck u bot') and len(message.content.split()) == 3 \
            or message.content.startswith('FUCK YOU BOT') and len(message.content.split()) == 3 \
            or message.content.startswith('fk u bot') and len(message.content.split()) == 3 \
            or message.content.startswith('FK YOU BOT') and len(message.content.split()) == 3 \
            or message.content.startswith('SCREW YOU BOT') and len(message.content.split()) == 3 \
            or message.content.startswith('screw you bot') and len(message.content.split()) == 3:
        fuckbotlist = ['Well fuck you too, {0.author.mention}.╭∩╮_(︶︿︶ )',
                       'Yes, yes {0.author.mention}. I know you want to fuck me.',
                       'Initializing `!ban`...', 'Whatever, scrub.', 'Take a chill pill {0.author.mention}.',
                       'Talk about hella salty.',
                       'What\'d you say ya cheeky cunt? I\'ma fuck ya up so hard mate. :anger:']
        yield from client.send_message(message.channel, random.choice(fuckbotlist).format(message))

    if message.content.startswith('fucking bot') or message.content.startswith(
            'dumb bot'):
        deflist = ['Wow, what did I do {0.author.mention}? :disappointed:', 'Fine. Be that way. :unamused:',
                   'It`s not my fault I was programmed this way. :neutral_face:',
                   '{0.author.mention} u mad?~', '{0.author.mention} Please refrain from hostile behaviour.',
                   'Tch, whatever.', ':broken_heart:',
                   ':unamused:', 'Can`t we just get along, {0.author.mention}?',
                   'Can`t we be friends? {0.author.mention}',
                   'I`m just doing my job. :confused:']
        yield from client.send_message(message.channel, random.choice(deflist).format(message))

    if ':^)' in message.content:
        command_count += 1
        yield from client.send_message(message.channel, '˙͜>˙')
    elif '(╯°□°）╯︵ ┻━┻' in message.content:
        command_count += 1
        yield from client.send_message(message.channel, '┬─┬ノ( º _ ºノ) no.')
    elif '┬─┬﻿ ノ( ゜-゜ノ)' in message.content:
        command_count += 1
        yield from client.send_message(message.channel, '(╯°□°）╯︵ ┻━┻')
    elif '┻━┻ ︵ヽ(`Д´)ﾉ︵﻿ ┻━┻' in message.content:
        yield from client.send_message(message.channel, '(ヘ･_･)ヘ┳━┳            ┬──┬ ノ( ゜-゜ノ)')

    if message.content.startswith('/francis') or message.content.startswith('/Francis'):
        yield from client.send_message(message.channel, "Fuck this game. - Francis 2015")
    elif message.content.startswith('/santran') or message.content.startswith('/Santran'):
        yield from client.send_message(message.channel, 'brb runescape - santran 2015')
    elif message.content.startswith('/cas') or message.content.startswith('/Cas'):
        yield from client.send_message(message.channel, '>.> - Casalina 2015')
    elif message.content.startswith('/sachi') or message.content.startswith('/Sachi'):
        yield from client.send_message(message.channel, "MY CHARACTER IS SO CUTE - Sachi 2015")
    elif message.content.startswith('/mythpv') or message.content.startswith('/MythPV'):
        command_count += 1
        yield from client.send_message(message.channel,
                                       '***Myth Guild PV***\n https://www.youtube.com/watch?v=tl7dhm0iOD0')

    elif message.content.startswith('riot') or message.content.endswith('RIOT'):
        command_count += 1
        yield from client.send_message(message.channel, 'ヽ༼ຈل͜ຈ༽ﾉ  RIOT ヽ༼ຈل͜ຈ༽ﾉ')
    elif message.content.startswith('RAISE YOUR DONGERS') \
            or message.content.startswith('raise ur dongers') or message.content.startswith('raise your dongers') \
            or message.content.startswith('ヽ༼ຈل͜ຈ༽ﾉ  RAISE YOUR DONGERS ヽ༼ຈل͜ຈ༽)') \
            or message.content.startswith('ヽ༼ຈل͜ຈ༽ﾉ RAISE YOUR DONGERS ヽ༼ຈل͜ຈ༽)'):
        command_count += 1
        yield from client.send_message(message.channel, 'ヽ༼ຈل͜ຈ༽ﾉ  RAISE YOUR DONGERS ヽ༼ຈل͜ຈ༽)')

    elif message.content.startswith('notice me senpai') or message.content.startswith('NOTICE ME SENPAI') \
            or message.content.startswith('Notice me senpai'):
        command_count += 1
        yield from client.send_message(message.channel,
                                       'Senpai has noticed you, {0.author.mention}. :wink:'.format(message))

    # Send jpg of food or gif when triggered. Local database.
    if message.content.startswith('feed me') and len(message.content.split()) == 2:
        command_count += 1
        food = random.choice(os.listdir('C:/DiscordPics/Food Porn'))
        yield from client.send_message(message.channel,
                                       message.author.mention + ' Someone\'s Hungry~ :meat_on_bone: :fried_shrimp: :hamburger:')
        yield from client.send_file(message.channel, 'C:/DiscordPics/Food Porn/' + food)

    if 'git gud' in message.content or 'get good' in message.content or 'gitgud' in message.content \
            or 'getgood' in message.content:
        if message.author == client.user:
            return
        else:
            os.chdir('C:/DiscordPics/General/')
            yield from client.send_file(message.channel, 'gitgud0.jpg')
    # --------------------------------------------------------------------------------------------------------------------
    # Sends out link resources to games.
    if message.content.startswith("/bns"):
        command_count += 1
        yield from client.send_message(message.channel,
                                       '__Blade and Soul Resources__\n\n'
                                       '+ **Skill Simulator** https://bnstree.com\n'
                                       '+ **NA website** http://www.bladeandsoul.com/en\n'
                                       '+ **Costume simulator** http://bns.inven.co.kr/dataninfo/gallery\n'
                                       '+ **BnS Dojo Fansite** http://www.bladeandsouldojo.com\n'
                                       '+ **Blade and Soul subreddit** https://www.reddit.com/r/bladeandsoul\n'
                                       '+ **NA + EU BnS Discord** https://discord.gg/0Xhfj5MKHvs5n1N4\n'
                                       '+ **Reddit BnS Discord** https://discord.gg/0TaItTx9qrQce4iU\n'
                                       '\n**Release Schedule**\n'
                                       'Name Reservation: January 11th (Founder Packs Only)\n'
                                       'Headstart: January 15th (Founder Packs Only)\n'
                                       'Release: January 19th\n')

    if message.content.startswith("/dn"):
        command_count += 1
        yield from client.send_message(message.channel, '__Dragon Nest Resources__\n\n'
                                                        '+ **Mods  ** <http://dnmods.boards.net/>\n'
                                                        '+ **Skill Simulator  ** <https://dnss.herokuapp.com/>\n'
                                                        '+ **2nd Skill Simulator  ** <http://dnmaze.com/?nxid=62>\n'
                                                        '+ **KR Skill Simulator  ** <https://dnss-kr.herokuapp.com/>\n'
                                                        '+ **Freedom Plays (KDN Updates)** <http://www.freedomplays.com/category/dragon-nest>\n'
                                                        '+ **KDN  ** <http://dn.pupugame.com/index_contents.html>\n'
                                                        '+ **CDN  ** <http://dn.sdo.com/web10/home/index.asp>\n'
                                                        '+ **JDN  ** <http://dragonnest.hangame.co.jp/>\n'
                                                        '+ **NA  ** <http://dragonnest.nexon.net>\n'
                                                        '+ **SEA  ** <http://dn.cherrycredits.com/>\n'
                                                        '+ **NA Forums  ** <http://dragonnest.nexon.net/community/forum>\n'
                                                        '+ **Dragon Nest Reddit  ** <https://www.reddit.com/r/DragonNest>\n'
                                                        '+ **DN Community Discord  ** https://discord.gg/0aoJVkoXoNwFEUea')

    if message.content.startswith("/bdo"):
        command_count += 1
        yield from client.send_message(message.channel, '__Black Desert Online Resources__\n\n'
                                                        '+ **NA website** <http://www.blackdesertonline.com>\n'
                                                        '+ **Black Desert subreddit** <https://www.reddit.com/r/blackdesertonline>\n'
                                                        '+ **BDO Discord**  https://discord.gg/0Zttqnp75M0n0mZE')

    # Links to Emotes for Discord and List for Games to play on Discord.
    if message.content.startswith('/emotes'):
        if message.author == client.user:
            return
        else:
            command_count += 1
            yield from client.send_message(message.channel,
                                           '**List of Discord Emotes** http://www.emoji-cheat-sheet.com')

    if message.content.startswith('/gamelist'):
        command_count += 1
        game_list = '**Master list of Discord games**:\nhttp://hastebin.com/cedukicexa.json'
        '\nhttps://gist.github.com/Rapptz/a82b82381b70a60c281b\nhttps://abal.moe/Discord/JSON/games.json'
        yield from client.send_message(message.channel, game_list)

    # Echos what the user inputs.
    if message.content.casefold().startswith("/say"):
        if message.author == client.user:
            return
        else:
            yield from client.send_message(message.channel, "{}".format(message.content.replace("/say ", '')))
            command_count += 1

    # Generates random number. Maybe helps in some social settings.
    if message.content.startswith("/roll"):
        if message.author == client.user:
            return
        else:
            command_count += 1
            x = random.random() * 100
            yield from client.send_message(message.channel, int(x))
            command_count += 1

    # Generate random number to generate a heads or tails. Also helps with some decisions?
    if message.content.startswith("/coin") or message.content.startswith("/flip") or message.content.startswith(
            "/toss"):
        if message.author == client.user:
            return
        else:
            command_count += 1
            coinlist = [' **Heads!**', ' **Tails!**']
            yield from client.send_message(message.channel, '`The resulting flip is:`' + random.choice(coinlist))
            command_count += 1

    # Randomly picks a choice for user if they have hard time with decisions.
    if message.content.startswith('/choose'):
        user_input = message.content.split()
        choice = user_input[1:]
        all_choice = "` | `".join(choice)
        yield from client.send_message(message.channel,
                                       'You want me to decide? Okay. Between `' + all_choice + '`, I pick **{}**.'.format(
                                               random.choice(choice)))

    # Returns random programmer jokes.
    if message.content.startswith('/pjoke'):
        yield from client.send_message(message.channel, pyjokes.get_joke(language='en', category='all'))

    # Returns random normal jokes.
    if message.content.startswith("/joke"):
        content = requests.get("http://tambal.azurewebsites.net/joke/random")
        if content.status_code == 200:
            yield from client.send_message(message.channel, str(content.json()["joke"]))

    # How long the bot has been around since its creation.
    if message.content.startswith("/age"):
        command_count += 1
        DOB = datetime.strptime('Nov 5 2015 1:33PM', '%b %d %Y %I:%M%p')
        Age = datetime.today() - DOB
        yield from client.send_message(message.channel, 'I am ' + str(Age) + " hours old")

    # Makes bot enter Text-to-Speech and says whatever user inputs.
    if (message.content.startswith('/tts')):
        command_count += 1
        stripped_content = message.content[5:].strip()
        result = stripped_content
        if len(result) <= 0:
            yield from client.send_message(message.channel,
                                           'Invalid use of `/tts`. Please input something after `/tts`.')
        else:
            yield from client.send_message(message.channel, result, tts=True)
            command_count += 1

    # Start of Calculator
    if message.content.startswith('math'):
        command_count += 1
        mathMessage = message.content.replace('math', '')
        try:
            yield from client.send_message(message.channel, eval(mathMessage))
        except SyntaxError:
            msg = 'Invalid input. Please use `+` `-` `/` `*` `%` and/or `&` in your function. ** = Exponent.'
            yield from client.send_message(message.channel, msg)
        except ZeroDivisionError:
            msg = '`Division by `0` is not allowed. This evaluates as ∞ or the indeterminate form 0/0.'
            yield from client.send_message(message.channel, msg)
        except NameError:
            msg = "Whatever you just put in, I don't like it. :unamused:"
            yield from client.send_message(message.channel, msg)

    # list a table of time zones
    if message.content.startswith('/times') or message.content.startswith('the time') or message.content.startswith(
            'The time') or message.content.startswith('/Times'):
        if message.author == client.user:
            return
        command_count += 1
        eastern = timezone('US/Eastern')
        est_time = datetime.now(eastern)
        pacific = timezone('US/Pacific')
        pst_time = datetime.now(pacific)
        central = timezone('US/Central')
        ct_time = datetime.now(central)
        mountain = timezone('MST')
        mst_time = datetime.now(mountain)
        hawaii = timezone('US/Hawaii')
        hw_time = datetime.now(hawaii)
        japan = timezone('Japan')
        jpn_time = datetime.now(japan)
        korea = timezone('Japan')
        kst_time = datetime.now(korea)
        china = timezone('Asia/Hong_Kong')
        cn_time = datetime.now(china)
        sydney = timezone('Australia/Sydney')
        aus_time = datetime.now(sydney)
        taiwan = timezone('Asia/Taipei')
        tw_time = datetime.now(taiwan)
        queensland = timezone('Australia/Queensland')
        queen_time = datetime.now(queensland)
        nz = timezone('NZ')
        nz_time = datetime.now(nz)
        yield from client.send_message(message.channel, "```" +
                                       tabulate([['EST', est_time.strftime("%H:%M:%S"), est_time.strftime("%b %d, %Y"),
                                                  est_time.strftime("%A")],
                                                 ['PST', pst_time.strftime("%H:%M:%S"), pst_time.strftime("%b %d, %Y"),
                                                  pst_time.strftime("%A")],
                                                 ['CST', ct_time.strftime("%H:%M:%S"), ct_time.strftime("%b %d, %Y"),
                                                  ct_time.strftime("%A")],
                                                 ['MST', mst_time.strftime("%H:%M:%S"), mst_time.strftime("%b %d, %Y"),
                                                  mst_time.strftime("%A")],
                                                 ['Hawaii', hw_time.strftime("%H:%M:%S"), hw_time.strftime("%b %d, %Y"),
                                                  hw_time.strftime("%A")],
                                                 ['Korea (KST)', kst_time.strftime("%H:%M:%S"),
                                                  kst_time.strftime("%b %d, %Y"),
                                                  kst_time.strftime("%A")],
                                                 ['Japan', jpn_time.strftime("%H:%M:%S"),
                                                  jpn_time.strftime("%b %d, %Y"),
                                                  jpn_time.strftime("%A")],
                                                 ['Hong Kong', cn_time.strftime("%H:%M:%S"),
                                                  cn_time.strftime("%b %d, %Y"),
                                                  cn_time.strftime("%A")],
                                                 ['Taiwan', tw_time.strftime("%H:%M:%S"), tw_time.strftime("%b %d, %Y"),
                                                  tw_time.strftime("%A")],
                                                 ['Sydney, Aus', aus_time.strftime("%H:%M:%S"),
                                                  aus_time.strftime("%b %d, %Y"),
                                                  aus_time.strftime("%A")],
                                                 ['Queensland, Aus', queen_time.strftime("%H:%M:%S"),
                                                  queen_time.strftime("%b %d, %Y"),
                                                  queen_time.strftime("%A")],
                                                 ['New Zealand', nz_time.strftime("%H:%M:%S"),
                                                  nz_time.strftime("%b %d, %Y"),
                                                  nz_time.strftime("%A")]],
                                                headers=['Zone', 'Time', 'Date', 'Day'], tablefmt='fancy_grid') + "```")

    if message.content.startswith('/calendar'):
        command_count += 1
        cal = calendar.TextCalendar(calendar.SUNDAY).formatyear(2016, 2, 1, 1, 2)
        yield from client.send_message(message.channel, "```Python\n" + cal + "\n```")

    # Returns first 5 videos found related to user input. TODO reformat.
    if message.content.startswith('/yt'):
        command_count += 1
        try:
            user_input = message.content.split()
            query = " ".join(user_input[1:])
            results = youtube_search(query, 5)
            yield from client.send_message(message.channel,
                                           '{0}\n{1}\n{2}\n{3}\n{4}'.format(results[0], results[1],
                                                                                  results[2], results[3], results[4]))
        except KeyError:
            yield from client.send_message(message.channel, 'Please try again with a different query.')

    # Duckduckgo search engine.
    if message.content.startswith('/search'):
        command_count += 1
        page = message.content.split()
        output = "https://duckduckgo.com/?q=" + "+".join(page[1:])
        yield from client.send_message(message.channel, output)
        command_count += 1

    # Search anything and return the first four links to user.
    if message.content.startswith('/google'):
        command_count += 1
        if message.author == client.user:
            return
        else:
            user_input = message.content.split()
            query = " ".join(user_input[1:])
            query = urllib.parse.urlencode({'q': query})
            response = urllib.request.urlopen(
                    'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&' + query).read().decode()
            json = m_json.loads(response)
            results = json['responseData']['results']
            all_results = []
            for result in results:
                title = result['title']
                url = result['url']
                all_results.append('+ **{0}**\n<{1}>'.format(remove_tags(title), url))
            yield from client.send_message(message.channel,
                                           '{0}\n{1}\n{2}\n{3}'.format(all_results[0], all_results[1], all_results[2],
                                                                       all_results[3]))
            all_results = []

    # Return specified amount of sentences from the article searched for.
    if message.content.startswith('/wiki'):
        command_count += 1
        if message.author == client.user:
            return
        else:
            try:
                user_input = message.content.split()
                query = "/".join(user_input[1:])
                yield from client.send_message(message.channel,
                                               wikipedia.summary(query, sentences=5, auto_suggest=True, redirect=True))
            except wikipedia.exceptions.DisambiguationError:
                msg = 'There\'s plenty of matches but I\'m unable to find what you\'re looking for *exactly*.' \
                      ' Be more specific.'
                yield from client.send_message(message.channel, msg)
            except wikipedia.exceptions.PageError:
                msg = 'I have no idea what you even want me to search. Was that a human language?'
                yield from client.send_message(message.channel, msg)

    # Return random XKCD comic. TODO try to be able to search via user input (integer) and RSS feed site.
    if message.content.startswith('/xkcd'):
        command_count += 1
        r = requests.get('http://c.xkcd.com/random/comic/')
        img = r.text.split('http://imgs.xkcd.com/comics/')[1].split('.png')[0]
        response = 'http://imgs.xkcd.com/comics/{}.png'.format(img)
        yield from client.send_message(message.channel, response)

    # Return random cat facts from various sources via API.
    if message.content.startswith('/catfacts'):
        command_count += 1
        response = requests.get('http://catfacts-api.appspot.com/api/facts?number=1')
        if response.status_code == requests.codes.ok:
            json = response.json()
            if json['success'] == "true":
                yield from client.send_message(message.channel, json['facts'][0])

    # Return a random gif from giphy based on the query of user.
    if message.content.startswith('/gif'):
        user_input = message.content.split()
        query = "+".join(user_input[1:])
        '''
        try:
            r = requests.get("http://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag={}".format(query))
            soup = BeautifulSoup(r.content, "html.parser")
             yield from client.send_message(message.channel, soup)
        except:
            pass
        '''
        image = g.random_gif(query)
        yield from client.send_message(message.channel, image)

    # Return first entry of definitions from applicable site.
    if message.content.startswith('/def'):
        # Take user input and only consider what was written after !def
        user_input = message.content.split()
        query = " ".join(user_input[1:])
        try:
            # Urban Dictionary
            r = requests.get("http://www.urbandictionary.com/define.php?term={}".format(query))
            soup = BeautifulSoup(r.content, "html.parser")
            urban_result = soup.find("div", attrs={"class": "meaning"}).text

            # Cambridge Dictionary
            r = requests.get("http://dictionary.cambridge.org/dictionary/british/{}".format(query))
            soup2 = BeautifulSoup(r.content, "html.parser")
            cambridge_result = soup2.find("span", {"class": "def"}).text

            wordApi = WordApi.WordApi(words)
            wiktion = wordApi.getDefinitions(query, sourceDictionaries='wiktionary', limit=1)
            webster = wordApi.getDefinitions(query, sourceDictionaries='webster', limit=1)
            wordnet = wordApi.getDefinitions(query, sourceDictionaries='wordnet', limit=1)

            yield from client.send_message(message.channel,
                                           'Query: `{0}`\n\n**Urban Dictionary**{1}'.format(query, urban_result) +
                                           '\n**Cambridge Dictionary**\n{}'.format(cambridge_result) +
                                           '\n\n**Wiktionary**\n{}'.format(wiktion[0].text) +
                                           '\n\n**Webster**\n{}'.format(webster[0].text) +
                                           '\n\n**Wordnet**\n{}'.format(wordnet[0].text))
        except AttributeError:
            try:
                wordApi = WordApi.WordApi(words)
                definitions = wordApi.getDefinitions(query,
                                                     sourceDictionaries='wiktionary',
                                                     limit=1)
                yield from client.send_message(message.channel,
                                               'Query: `{0}`\n\n**Urban Dictionary**{1}'.format(query, urban_result) +
                                               '\n**Wiktionary**\n{}'.format(definitions[0].text))
            except TypeError:
                yield from client.send_message(message.channel,
                                               'Query: `{0}`\n\n**Urban Dictionary**{1}'.format(query, urban_result))
            except:
                yield from client.send_message(message.channel, '1')
        except TypeError:
            try:
                yield from client.send_message(message.channel,
                                               'Query: `{0}`\n\n**Urban Dictionary**{1}'.format(query, urban_result))
            except:
                yield from client.send_message(message.channel, 'Nope. No results.')
    # ---------------------------------------------------------------------------------------------------------------------
    # Avatar viewer. Accepts @mentions and normal text input.
    if message.content.startswith('/avatar') and len(message.content.split()):
        command_count += 1
        try:
            # stores the avatar of the @mentioned person into variable 'thenames' and sends via yield from client.send_message
            nameMention = message.mentions[0].avatar_url
            yield from client.send_message(message.channel, nameMention)
        except UnboundLocalError:
            pass
        except IndexError:
            nameTyped = message.content.replace('/avatar', '').strip()
            names = discord.utils.find(lambda m: m.name == nameTyped, message.server.members)
            try:
                if names is not None:
                    foundMember = names.avatar_url
                    yield from client.send_message(message.channel, foundMember)
                else:
                    yield from client.send_message(message.channel, "That user does not exist in this server.")
            except discord.errors.HTTPException:
                yield from client.send_message(message.channel, 'This user uses default avatar.\n')
                open('DiscordPics/General', "r")
                yield from client.send_file(message.channel, 'Discord.jpg')
    elif message.content.startswith('/avatar') and len(message.content.split()) == 1:
        yield from client.send_message(message.channel, message.author.avatar_url)

    # COLOR CHANGING CODE
    if message.content.startswith('/color') and len(message.content.split()) >= 3 and str(
            message.author.id) in '90829628691709952 111889796946759680 90588624512356352' \
                                  ' 90939385553383424 73651876540723200 79258673020411904 91750781253865472':
        try:
            # light pink 0xFF69B4
            colorVal = message.content.split()[-1]
            roleName = message.content.replace('/color ', '')
            roleName = roleName.replace(' ' + colorVal, '')
            yield from client.edit_role(message.channel.server,
                                        discord.utils.find(lambda r: r.name == str(roleName),
                                                           message.channel.server.roles),
                                        colour=discord.Colour(int(colorVal, 16)))
            yield from client.send_message(message.channel, '```The color for the specified role has been assigned.```')
            command_count += 1
        except AttributeError:
            error_msg = "The role you specified does not exist. `(Case-sensitive)`"
            yield from client.send_message(message.channel, error_msg)
        except ValueError:
            error_msg = "Please format your hex value similar to `0xFF1234`. Remove the `#` symbol if applicable."
            yield from client.send_message(message.channel, error_msg)
    elif message.content.startswith('/color') and len(message.content.split()) >= 3 and str(
            message.author.id) not in '90829628691709952 111889796946759680':
        msg = ':no_entry: You do not have access to this command. Contact someone with this function\'s permission.'
        yield from client.send_message(message.channel, msg)
        command_count += 1
    elif message.content.startswith('/color') and len(message.content.split()) == 1:
        msg = "This command takes **two** arguments: `/color <role name> <0x(HexNumber)>`"
        yield from client.send_message(message.channel, msg)
        command_count += 1
    elif message.content.startswith('/color') and len(message.content.split()) > 3:
        msg = "This command takes **two** arguments: `/color <role name> <0x(HexNumber)>`"
        yield from client.send_message(message.channel, msg)
        command_count += 1

    '''
    # TRIVIA function
    if message.author == client.user:
        return

    trivia = current_games.get(message.author.id)

    if message.content.startswith('/trivia'):

        msg = 'Your trivia has now begun, {0.author.mention}.\n'.format(message)
         yield from client.send_message(message.channel, msg)

        if trivia is not None:
            yield from client.send_message(message.channel, 'Your trivia is already in progress.')
            current_games[message.author.id] = GuessingState(message)
    elif message.content.startswith('/tguess'):
        if trivia is None:
            yield from client.send_message(message.channel,
                                           'There\'s no trivia or you tried guessing for someone else. :unamused: Start your own trivia with `!trivia`')
        # remove /guess from the string
        content = message.content[6:].strip()
        trivia.do_guess(content)
    elif message.content.startswith('/giveup'):
        if trivia is None:
            yield from client.send_message(message.channel,
                                           'A trivia is not up or you tried giving up for someone else... :unamused:')
        trivia.quit()
    if trivia is not None and trivia.is_over:
        # check if the trivia session ended and remove it
        # from the dictionary of currently running trivia
        del current_games[message.author.id]

    # Guessing Game with numbers.
    if message.author == client.user:
        return
    if message.content.startswith('/guess'):
        yield from client.send_message(message.channel, 'I\'m thinking of a number between 1 and 10. What is it?')

        def guess_check(m):
            return m.content.isdigit()

        guess = yield from client.wait_for_message(timeout=7.0, author=message.author, check=guess_check)
        answer = random.randint(1, 10)
        if guess is None:
            fmt = 'Sorry, you took too long to answer. I was thinking of **{}**.'
            yield from client.send_message(message.channel, fmt.format(answer))
            return
        if int(guess.content) == answer:
             yield from client.send_message(message.channel, 'Correct. Good guess!')
        else:
             yield from client.send_message(message.channel, 'Nope, I was thinking of **{}**.'.format(answer))


    # Longer version of fight that accepts two mentions. Basically fight v2.
    if message.content.startswith('!duel') and str(message.channel.id):
        if message.author == client.user:
            return
        else:
            if len(message.mentions) != 2:
                 yield from client.send_message(message.channel, 'You must tell me which two people will duel.')
            elif message.mentions[0].mention() == message.mentions[1].mention():
                 yield from client.send_message(message.channel, 'That person cannot fight themselves...')
            else:
                results = Duel([message.mentions[0].mention, message.mentions[1].mention])
                for i in range(len(results)):
                     yield from client.send_message(message.channel, results[i])
    '''

    # Short quick command for picking a fight with someone.
    if message.content.startswith('/fight'):
        if message.author == client.user:
            return
        else:
            for disuser in message.mentions:
                user = discord.utils.find(lambda member: member.name == disuser.name, message.channel.server.members)
            yield from client.send_message(message.channel, message.author.mention + random.choice(verblist)
                                           + user.mention + random.choice(attacklist))
            command_count += 1

    # FRACTAL Mention; Magic Eight questions
    if message.author == client.user:
        return
    if message.content.startswith(client.user.mention):
        try:
            command_count += 1
            word_trigger = message.content.split()[1]
            if any(word_trigger in s for s in bot_question) and len(message.content.split()) >= 2:
                yield from client.send_message(message.channel, random.choice(magicEight).format(message))
        except IndexError:
            yield from client.send_message(message.channel, 'Yes? What do you need?')

    # Timeout method by adding 'Box' role to someone which has no text permissions. Requires channel permissions too.
    if message.content.startswith('/box') and str(message.author.id) in ADMIN and len(message.content.split()) == 3:
        try:
            new_m = message.content.split()
            t1 = datetime.now()
            pwr_timeout[new_m[1]] = [int(new_m[2]), t1, message.mentions[0]]
            timeout_store += 1
            yield from client.add_roles(message.mentions[0],
                                        discord.utils.find(lambda r: r.name == 'Box', message.channel.server.roles))
            yield from client.send_message(message.channel,
                                           'You\'ve been bad, ' + new_m[1] + '. You\'ll be put in a box for ' + new_m[
                                               2] + ' seconds.')
            while timeout_store > 0:
                for i in pwr_timeout:
                    timeDiff = current_time - pwr_timeout[i][1]
                    if timeDiff.seconds >= pwr_timeout[i][2]:
                        yield from client.remove_roles(pwr_timeout[i][2],
                                                       discord.utils.find(lambda r: r.name == 'Box',
                                                                          message.channel.server.roles))
                        pwr_timeout.pop(i)
                        timeout_store -= 1
                        break
        except ValueError:
            yield from client.send_message(message.channel,
                                           'I saw you put in those non-integers. Put in some integers instead.')
        except AttributeError:
            yield from client.send_message(message.channel,
                                           'You must create a **Box** role with absolutely no permissions in every channel'
                                           ' and give me **Manage Roles** permission'
                                           ' in this server for this command to work. You must also have permission to use this command.')
    elif message.content.startswith('/box') and len(message.content.split()) != 3 and str(
            message.author.id) in ADMIN:
        yield from client.send_message(message.channel,
                                       '`/box` takes **two** arguments: `/box @mention <time in seconds>`')
    elif message.content.startswith('/box') and str(message.author.id) not in ADMIN:
        yield from client.send_message(message.channel, ':hand: `You have no permission to use this command.`')
    if message.content.startswith('/free') and str(message.author.id) in ADMIN and len(message.content.split()) == 2:
        new_m = message.content.split()
        try:
            if new_m[1] in pwr_timeout:
                client.remove_roles(pwr_timeout[new_m[1]][2], discord.utils.find(lambda r: r.name == 'Box',
                                                                                 message.channel.server.roles))
                pwr_timeout.pop(new_m[1])
                yield from client.send_message(message.channel, new_m[1] + ' is now free from tyranny.')
            elif 'Box' in discord.utils.find(lambda m: m.name == 'Box', message.channel.server.members).roles:
                client.remove_roles(pwr_timeout[new_m[1]][2], discord.utils.find(lambda r: r.name == 'Box',
                                                                                 message.channel.server.roles))
                yield from client.send_message(message.channel, new_m[1] + ' is now free from tyranny.')
            else:
                yield from client.send_message(message.channel, 'That person has not been put into the box.')
        except AttributeError:
            yield from client.send_message(message.channel,
                                           'My records don\'t indicate that person is in the box. :kissing:')
    elif message.content.startswith('/free') and str(message.author.id) not in ADMIN:
        yield from client.send_message(message.channel, ':hand: `You have no permission to use this command.`')
    # ---------------------------------------------------------------------------------------------------------------------
    # PMs the user and gives them the list of commands.
    if message.content.startswith("/commands") or message.content.startswith('!commands'):
        one_string = '\n'.join(command_one)
        two_string = '\n'.join(command_two)
        yield from client.send_message(message.author, '▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬\n'
                                                       '**\nI can join your servers via `/join <discord_url>`!**\n\n'
                                       + one_string)
        yield from client.send_message(message.author, two_string +
                                       '\n▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ஜ۩۞۩ஜ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬')
        yield from client.send_message(message.channel,
                                       "I have PM'ed you the commands, {0.author.mention}.".format(message))
        command_count += 1

    if message.content.startswith("/status"):
        command_count += 1
        status_string = '\n'.join(status)
        yield from client.send_message(message.channel, status_string)

    elif message.content.startswith("/info") or message.content.startswith('!info'):
        command_count += 1
        yield from client.send_message(message.channel,
                                       'I am a bot named `FRACTAL`.\n\n**Owner** <@90829628691709952>\n'
                                       '**Lib:** discord.py|async\n'
                                       '\nFor a list of my commands, type `!commands` or `/commands`')

    elif message.content.startswith("!help") or message.content.startswith('/help'):
        command_count += 1
        yield from client.send_message(message.channel, 'Listing commands that may be of use to you.\n\n'
                                                        '`/info` | `!info` info on bot.\n'
                                                        '`/status` changes and upgrades to bot.\n'
                                                        '`/commands` | `!commands` will be PM\'ed to you.\n'
                                                        '`/server` server info.\n'
                                                        '`/data` how many servers connected to and member count across servers.\n')

    # Opt in and opt out for events. /joinevent to sign up for mentions
    # whenever /event <topic> is used in specific channels.
    if message.content.startswith('/event') and str(message.channel.id) == '129842188879134720' and len(
            message.content.split()) > 1 \
            and str(message.channel.server.id) == '90939613044039680' and message.mention_everyone == False and str(
            message.author.id) in '90939385553383424':
        os.chdir('C:\Python Discord bot\FRAC')
        event_message = '**Event Info**\n\n'
        event_message += message.content[6:]
        if len(message.mentions) != 0:
            for i in message.mentions:
                event_message = event_message.replace(i.mention, '-No mentions-')
        if 'http' in event_message.lower():
            event_message = event_message.replace('http', '')
        with open('eventlist.txt', 'r') as s:
            overC = 0
            event_mentions = []
            tempL = ''
            for line in s:
                tempL += line.replace('\n', ' ')
                if len(tempL) > 1900:
                    event_mentions.append(tempL)
                    tempL = ''
            event_mentions.append(tempL)
            for i in event_mentions:
                yield from client.send_message(message.channel, event_message + '\n\n' + i)
    elif message.content.startswith('/event') and str(message.channel.id) != '129842188879134720' and str(
            message.channel.server.id) == '90939613044039680':
        yield from client.send_message(message.channel,
                                       'You can only set up an event in the <#129842188879134720> channel.')
    elif message.content.startswith('/event') and len(message.content.split()) < 2 and str(
            message.channel.server.id) == '106293726271246336':
        yield from client.send_message(message.channel,
                                       'You must have info about the event.')
    elif message.content.lower().startswith('/joinevent') and str(message.channel.server.id) == '90939613044039680':
        os.chdir('C:\Python Discord bot\FRAC')
        pugL = ''
        with open('eventlist.txt', 'r') as s:
            pugL = s.read()
        if message.author.mention not in pugL:
            with open('eventlist.txt', 'a') as s:
                s.write(message.author.mention)
                s.write('\n')
                yield from client.send_message(message.channel,
                                               'You have successfully signed up for the Christmas event!')
        if message.author.mention in pugL:
            newL = []
            with open('eventlist.txt', 'r') as s:
                for line in s:
                    if message.author.mention not in line:
                        newL.append(line)
            with open('eventlist.txt', 'w') as s:
                for line in newL:
                    s.write(line)
            yield from client.send_message(message.channel,
                                           'You have successfully removed yourself from the Christmas event!')

    # Manually change game bot is playing.
    if message.content.startswith('/game') and message.author.id in ADMIN:
        user_input = message.content.split()
        gameChoice = " ".join(user_input[1:])
        bot_game = gameChoice
        yield from client.change_status(game=discord.Game(name=bot_game))
        yield from client.send_message(message.channel, 'I guess I\'ll play `{}`'.format(bot_game))


# Print basic info to console when successfully logged in.
@client.async_event
def on_ready():
    print('Logged in as')
    print('Username: ' + client.user.name)
    print('ID: ' + client.user.id)
    print('Current working directory: ' + os.getcwd())
    print('------')
    yield from client.change_status(game=discord.Game(name=bot_game))
    client.uptime = datetime.utcnow()


def main_task():
    yield from client.login(info[0], info[1])
    yield from client.connect()


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main_task())
    loop.run_until_complete(client.connect())
except Exception:
    loop.run_until_complete(client.close())
finally:
    loop.close()
