#!/usr/bin/env python3

# ----------------------------------------------------------------------------
# MIRbot CLI - Simple commandline wrapper for MIRbot Object
# (Modular Information Retrieval bot)
# ----------------------------------------------------------------------------
# Written by Xan Manning
# ----------------------------------------------------------------------------
#
# Copyright (c) 2017 PyratLabs (http://pyrat.io)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ----------------------------------------------------------------------------

# Import standard modules required to run bot.
import getopt
import os
import sys
import time
import daemon
import lockfile
import signal

# Import our core module
from mirbot import MIRCore

# Check we are running a good version of Python 3
if sys.version_info < (3,4):
    print("Your Python version may be too old.")
    print("Please upgrade to Python 3.4.x or above.")
    exit(1)


# Print usage instructions.
def usage():
    print("")
    print("Command:    %s" % sys.argv[0])
    print("")
    print("Arguments:  -c --config /path/to/config")
    print("            -d --daemon")
    print("            -h --help")
    print("")


# Parse command line arguments.
def getArguments():
    # Set the default arguments.
    arguments = {
        'daemon': False,
        'home': os.path.expanduser("~/.mirbot")
    }

    # Try parsing the command line arguments, set the allowed options
    #
    #       -h | --help
    #       -d | --daemon
    #       -c | --config /configdir
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hc:d",
            ["help", "config=", "daemon"])
    except getopt.GetoptError as err:
        print(err)
        usage()
        sys.exit(2)

    # Cycle the options and apply arguments
    for o, a in opts:
        if o in ("-h", "--help"):
            usage()
            sys.exit(0)
        elif o in ("-c", "--config"):
            arguments['home'] = a
        elif o in ("-d", "--daemon"):
            arguments['daemon'] = True
        else:
            assert False, "Unhandled Option"

    # Return the arguments dictionary
    return arguments


# Our main function for this program:
def main(arguments):
    # Initialize our core object, no config passed in CLI, just arguments.
    core = MIRCore({}, arguments)

    # While we are allowed to connect/reconnect
    while core.reconnect:
        # Connect to the server
        core.connect()

        # Leave some time for the connection to catch up
        time.sleep(2)

        # Execute commands required upon establishing a connection
        for connectCommand in core.config['commands']:
            core.send(connectCommand)

        # Rejoin the channels that we have designated in config and in bot
        # assignment database.
        core.rejoin()

        # Listen to the connection, execute based on input/output
        core.listen()

        # We've stopped listening, are we terminating the connection?
        if core.reconnect == False:
            print("Terminating the connection...")
            break

        # If not, tell console what we are doing...
        print("Reconnection request...")
        print("Delaying 10 seconds before reconnect...")

        # Sleep 10 seconds
        time.sleep(10)

        # Clean up variables.
        core.clean(True)


# Launch our bot:
if __name__ == "__main__":
    # Collect our arguments into a dictionary
    arguments = getArguments()

    # Are we daemonizing the process?
    if arguments['daemon'] == True:
        # Check the homedir exists
        if not os.path.isdir(arguments['home']):
            print("Error: %s doesn't exists." % arguments['home'])
            print("Try running without --daemon to create directory.")
            sys.exit(1)

        # Build our daemon's context
        context = daemon.DaemonContext(
            working_directory=arguments['home'],
            umask=0o002,
            pidfile=lockfile.FileLock("%s/mirbot.pid" % arguments['home']),
        )

        # Map the signals to methods in the class
        context.signal_map = {
            signal.SIGTERM: MIRCore.disconnect,
            signal.SIGHUP: 'terminate',
            signal.SIGUSR1: MIRCore.restart
        }

        # Run the bot in the daemonized context.
        with context:
            main(arguments)
    else:
        # Run the bot in the foreground
        main(arguments)
