# Path: plugins/pasteImporter.py
# class PasteImporter:
#     """Class that can read a select number of pastes from different sites
#     and return the content of the paste.
# 
#     This class is not meant to be instanced, but should instead be used as a
#     fully static class.
#     """
#     @staticmethod
#     def getPasteContent(url):
#         if not url: raise PasteImporterException('Not an URL')
# 
#         page = requests.get(url)
#         if 'hastebin.com/raw' in page.url:
#             return page.content.decode('utf-8')
#         elif 'pastebin.com/raw' in page.url:
#             return page.content.decode('utf-8')
#         elif 'gist.githubusercontent.com/' in page.url:
#             return page.content.decode('utf-8')
#         elif 'pokepast.es' in page.url:
#             # Pokepast.es doesn't have a "raw" that easily give us the content
#             # so we have to manually parse it.
#             htmlTree = html.fromstring(page.content)
#             # Relies on pokepast.es to not change their layout at all!
#             return ''.join([node.text_content() for node in htmlTree.xpath('/html/body/main/div/pre')])
#         else:
#             # This is not a supported type of pastebin service
#             raise PasteImporterException('Unsupported URL')
# 
# Path: invoker.py
# class ReplyObject:
#     """ Class for returning information from a command to the core program.
# 
#     Parameters used for creating this class defines the behaviour of the main
#     program when it comes across the reply object.
# 
#     Attributes:
#         text: str, the content of the reply.
#         samePlace: bool, if the response will always be in pm or where the command
#         was said.
#         ignoreEscaping: bool, default every reply is escaped to not allow
#         arbitrary commands to be executed through replies. Some commands require
#         to be able to use PS commands, which is when this should be overwritten.
#         ignoreBroadcastPermission: bool, ignore the global broadcast permission
#         for the reply if this is true.
#         gameCommand: bool, unused, pending removal.
#         canPmReply: bool, override the default request for users without broadcast
#         permission to pm the command and instead return the result of the action.
#         isException: bool, if a command throws an exception this will be true.
#     """
#     def __init__(self, res = '', reply = False, escape = False, broadcast = False, game = False, pmreply = False, ignoreml = False):
#         self.text = str(res)
#         self.samePlace = reply
#         self.ignoreEscaping = escape
#         self.ignoreBroadcastPermission = broadcast
#         self.ignoreMultiline = ignoreml
#         self.gameCommand = game
#         self.canPmReply = pmreply
#         self.isException = isinstance(res, Exception)
# 
#     def __eq__(self, other):
#         try:
#             return (self.text == other.text
#                 and self.samePlace == other.samePlace
#                 and self.ignoreEscaping == other.ignoreEscaping
#                 and self.ignoreBroadcastPermission == other.ignoreBroadcastPermission
#                 and self.ignoreMultiline == other.ignoreMultiline
#                 and self.gameCommand == other.gameCommand
#                 and self.canPmReply == other.canPmReply
#                 and self.isException == other.isException
#             )
#         except:
#             # This only happens if the other object isn't a matching object
#             return False
# 
#     def response(self, text):
#         self.text = text
#         return self
#     def extra(self, text):
#         self.text += text
#         return self
# 
# class Command:
#     """ Wrapper class that every command should use when being created.
# 
#     The default run method should never be called, and any instance of the
#     class should override this method on creation of the instance.
# 
#     Commands should also implement any private methods they may need for completion
# 
#     Attributes:
#         cmdTriggers: List, list of every trigger that should be used to invoke
#         this method.
#         altHtml: Bool, true if the command has alternate output if HTML is supported.
#     """
#     def __init__(self, triggers, nonAbsRun = None, html = False):
#         self.cmdTriggers = triggers
#         self.altHtml = html
#         self.hasBroadcastAlt = False
#         # This will hide the default run method if it is given on object creation
#         self.run = nonAbsRun if nonAbsRun else self.run
#     def run(self, robot, cmd, room, params, user):
#         """Abstract method for executing a command after it has been found. Each command
#         has to reimplement this function to work.
# 
#         Args:
#             robot: PokemonShowdownBot, the instance of PokemonShowdownBot that called this function.
#             cmd: string, the command that was send.
#             room: Room, the room object that the command was sent from.
#             params: string, additional paramters that the command may need.
#             user: User, the user object of the user who sent the command.
#         Returns:
#             ReplyObject.
#         Raises:
#             NotImplementedError if not implemented, otherwise unknown. """
#         raise NotImplementedError('Command#run method not implemented')


from datetime import datetime, timedelta
from plugins.pasteImporter import PasteImporter
from invoker import ReplyObject, Command
import os
import sched
import calendar
import time
import threading
    if not room.scheduler.thread:
        room.scheduler.configureEventScheduler(robot)

    with open('added-jobs-{}.csv'.format(room.title), 'a+') as jobs:
        jobs.write('{user},{job}\n'.format(user=user.id, job=params))

    date, frequency, joblist = params.replace('| ', '|').split('|')
    # Validate date string format first
    if not EventScheduler.validateDateString(date):
        return reply.response('Invald date format. Expected format is YYYY/MM/DD HH:MM.')

    room.scheduler.addJob(date, frequency, joblist)
    return reply.response('New event scheduled for {date}, repeating every {freq} days.'.format(date=date, freq=frequency))

def clearEvents(robot, cmd, params, user, room):
    reply = ReplyObject('', reply=True, pmreply=True)
    if not user.hasRank('#'): return reply.response("Permission denied, only Room Owners (#) and up can use this command.")

    try:
        os.remove('added-jobs-{}.csv'.format(room.title))
    except FileNotFoundError:
        # This is fine
        pass
    room.scheduler.clearEvents()

    return reply.response('All events cleared')

# Exports
commands = [
    Command(['addevent'], addEvent),

# Path: plugins/pasteImporter.py
# class PasteImporter:
#     """Class that can read a select number of pastes from different sites
#     and return the content of the paste.
# 
#     This class is not meant to be instanced, but should instead be used as a
#     fully static class.
#     """
#     @staticmethod
#     def getPasteContent(url):
#         if not url: raise PasteImporterException('Not an URL')
# 
#         page = requests.get(url)
#         if 'hastebin.com/raw' in page.url:
#             return page.content.decode('utf-8')
#         elif 'pastebin.com/raw' in page.url:
#             return page.content.decode('utf-8')
#         elif 'gist.githubusercontent.com/' in page.url:
#             return page.content.decode('utf-8')
#         elif 'pokepast.es' in page.url:
#             # Pokepast.es doesn't have a "raw" that easily give us the content
#             # so we have to manually parse it.
#             htmlTree = html.fromstring(page.content)
#             # Relies on pokepast.es to not change their layout at all!
#             return ''.join([node.text_content() for node in htmlTree.xpath('/html/body/main/div/pre')])
#         else:
#             # This is not a supported type of pastebin service
#             raise PasteImporterException('Unsupported URL')
# 
# Path: invoker.py
# class ReplyObject:
#     """ Class for returning information from a command to the core program.
# 
#     Parameters used for creating this class defines the behaviour of the main
#     program when it comes across the reply object.
# 
#     Attributes:
#         text: str, the content of the reply.
#         samePlace: bool, if the response will always be in pm or where the command
#         was said.
#         ignoreEscaping: bool, default every reply is escaped to not allow
#         arbitrary commands to be executed through replies. Some commands require
#         to be able to use PS commands, which is when this should be overwritten.
#         ignoreBroadcastPermission: bool, ignore the global broadcast permission
#         for the reply if this is true.
#         gameCommand: bool, unused, pending removal.
#         canPmReply: bool, override the default request for users without broadcast
#         permission to pm the command and instead return the result of the action.
#         isException: bool, if a command throws an exception this will be true.
#     """
#     def __init__(self, res = '', reply = False, escape = False, broadcast = False, game = False, pmreply = False, ignoreml = False):
#         self.text = str(res)
#         self.samePlace = reply
#         self.ignoreEscaping = escape
#         self.ignoreBroadcastPermission = broadcast
#         self.ignoreMultiline = ignoreml
#         self.gameCommand = game
#         self.canPmReply = pmreply
#         self.isException = isinstance(res, Exception)
# 
#     def __eq__(self, other):
#         try:
#             return (self.text == other.text
#                 and self.samePlace == other.samePlace
#                 and self.ignoreEscaping == other.ignoreEscaping
#                 and self.ignoreBroadcastPermission == other.ignoreBroadcastPermission
#                 and self.ignoreMultiline == other.ignoreMultiline
#                 and self.gameCommand == other.gameCommand
#                 and self.canPmReply == other.canPmReply
#                 and self.isException == other.isException
#             )
#         except:
#             # This only happens if the other object isn't a matching object
#             return False
# 
#     def response(self, text):
#         self.text = text
#         return self
#     def extra(self, text):
#         self.text += text
#         return self
# 
# class Command:
#     """ Wrapper class that every command should use when being created.
# 
#     The default run method should never be called, and any instance of the
#     class should override this method on creation of the instance.
# 
#     Commands should also implement any private methods they may need for completion
# 
#     Attributes:
#         cmdTriggers: List, list of every trigger that should be used to invoke
#         this method.
#         altHtml: Bool, true if the command has alternate output if HTML is supported.
#     """
#     def __init__(self, triggers, nonAbsRun = None, html = False):
#         self.cmdTriggers = triggers
#         self.altHtml = html
#         self.hasBroadcastAlt = False
#         # This will hide the default run method if it is given on object creation
#         self.run = nonAbsRun if nonAbsRun else self.run
#     def run(self, robot, cmd, room, params, user):
#         """Abstract method for executing a command after it has been found. Each command
#         has to reimplement this function to work.
# 
#         Args:
#             robot: PokemonShowdownBot, the instance of PokemonShowdownBot that called this function.
#             cmd: string, the command that was send.
#             room: Room, the room object that the command was sent from.
#             params: string, additional paramters that the command may need.
#             user: User, the user object of the user who sent the command.
#         Returns:
#             ReplyObject.
#         Raises:
#             NotImplementedError if not implemented, otherwise unknown. """
#         raise NotImplementedError('Command#run method not implemented')


# Path: plugins/eventscheduler.py
from datetime import datetime, timedelta
from plugins.pasteImporter import PasteImporter
from invoker import ReplyObject, Command
import os
import sched
import calendar
import time
import threading

    if not room.scheduler.thread:
        room.scheduler.configureEventScheduler(robot)

    with open('added-jobs-{}.csv'.format(room.title), 'a+') as jobs:
        jobs.write('{user},{job}\n'.format(user=user.id, job=params))

    date, frequency, joblist = params.replace('| ', '|').split('|')
    # Validate date string format first
    if not EventScheduler.validateDateString(date):
        return reply.response('Invald date format. Expected format is YYYY/MM/DD HH:MM.')

    room.scheduler.addJob(date, frequency, joblist)
    return reply.response('New event scheduled for {date}, repeating every {freq} days.'.format(date=date, freq=frequency))

def clearEvents(robot, cmd, params, user, room):
    reply = ReplyObject('', reply=True, pmreply=True)
    if not user.hasRank('#'): return reply.response("Permission denied, only Room Owners (#) and up can use this command.")

    try:
        os.remove('added-jobs-{}.csv'.format(room.title))
    except FileNotFoundError:
        # This is fine
        pass
    room.scheduler.clearEvents()

    return reply.response('All events cleared')

# Exports
commands = [
    Command(['addevent'], addEvent),

    Command(['clearevents'], clearEvents)