#!/usr/bin/env python

"""
This is a helper program for the MoltenIron server.
"""

# Copyright (c) 2016 IBM Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable-msg=C0103
# pylint: disable=redefined-outer-name

import argparse
import os
import signal
import sys

from daemonize import Daemonize
from pkg_resources import resource_filename
import yaml

from molteniron import moltenirond


PID = "/var/run/moltenirond.pid"
YAML_CONF = None
ERROR_LOGFILE = "/tmp/MoltenIron-error-logfile"


class MoltenIronPIDNotFound(RuntimeError):
    """os.path.isfile() error: The PID file does not exist"""


class MoltenIronKillError(RuntimeError):
    """os.kill() error"""


class MoltenIronReadLinesError(RuntimeError):
    """fobj.readlines() error"""


def get_moltenirond_pid():
    """Return the PID of the MoltenIron server process."""

    if not os.path.isfile(PID):
        raise MoltenIronPIDNotFound("isfile error %s" % (PID, ))

    with open(PID) as fobj:
        lines = fobj.readlines()
        try:
            pid = int(lines[0])

            try:
                # Send harmless kill signal in order to test existance
                os.kill(pid, 0)
            except Exception as e:
                raise MoltenIronKillError("os.kill error: %s" % (e, ))

            return pid
        except Exception as e:
            raise MoltenIronReadLinesError("readlines error: %s" % (e, ))


def moltenirond_main():
    """This is the main routine for the MoltenIron server."""

    with open(YAML_CONF, "r") as fobj:
        conf = yaml.load(fobj, Loader=yaml.SafeLoader)

        moltenirond.listener(conf)


def log_error(s):
    """Log an error to stderr and to a file."""

    with open(ERROR_LOGFILE, "a+") as fobj:
        fobj.writelines(s + "\n")
        print(s, file=sys.stderr)


if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="Molteniron daemon helper")
    parser.add_argument("-c",
                        "--conf-dir",
                        action="store",
                        type=str,
                        dest="conf_dir",
                        help="The directory where configuration is stored")
    parser.add_argument("-p",
                        "--pid-dir",
                        action="store",
                        type=str,
                        dest="pid_dir",
                        help="The directory where PID information is stored")
    parser.add_argument("-v",
                        "--verbose",
                        action="store",
                        type=bool,
                        dest="verbose",
                        help="Set a verbose information mode")
    parser.add_argument("command", type=str, nargs=1, help="the command")

    args = parser.parse_args()

    if args.conf_dir:
        if not os.path.isdir(args.conf_dir):
            msg = "Error: %s is not a valid directory" % (args.conf_dir, )
            print(msg, file=sys.stderr)
            sys.exit(1)

        YAML_CONF = os.path.realpath("%s/conf.yaml" % (args.conf_dir, ))
    else:
        YAML_CONF = resource_filename("molteniron", "conf.yaml")

    # Test for read ability
    fobj = open(YAML_CONF, "r")
    fobj.close()

    if args.pid_dir:
        if not os.path.isdir(args.pid_dir):
            msg = "Error: %s is not a valid directory" % (args.pid_dir, )
            print(msg, file=sys.stderr)
            sys.exit(1)

        PID = os.path.realpath("%s/moltenirond.pid" % (args.pid_dir, ))

    if args.verbose:
        print("YAML_CONF = %s" % (YAML_CONF, ))
        print("PID = %s" % (PID, ))

    if len(args.command) != 1:
        msg = "Error: Expecting one command? Received: %s" % (args.command, )
        log_error(msg)
        sys.exit(1)

    if args.command[0].upper().lower() == "start":
        try:
            pid = get_moltenirond_pid()
        except MoltenIronPIDNotFound:
            pid = -1

        if pid > 0:
            log_error("Error: The daemon is already running")
            sys.exit(1)

        daemon = Daemonize(app="moltenirond",
                           pid=PID,
                           action=moltenirond_main)
        daemon.start()

    elif args.command[0].upper().lower() == "stop":
        try:
            pid = get_moltenirond_pid()
        except MoltenIronPIDNotFound:
            pid = -1

        if pid > 0:
            os.remove(PID)
            os.kill(pid, signal.SIGTERM)
        else:
            log_error("Error: The daemon doesn't exist?")
            log_error("Error: pid = %d" % (pid, ))
            sys.exit(1)
    else:
        msg = "Error: Unknown command: %s" % (args.command[0], )
        log_error(msg)
        sys.exit(1)
