#!/usr/bin/python
# Python library sharing features not specific to modems but more global to the controller and system
import subprocess
import os
import logging
import lib_logger
import datetime
import time
import signal
import sys

sys.path.append('/tmp/update')  # needed for update type detection

logger = logging.getLogger()

def sync():
    """ saves files on flash
    """
    try:
        output = subprocess.check_output(["sync"])
        return True
    except subprocess.CalledProcessError as e:
        return False

def reboot():
    os.system("reboot")

def startService(service_name):
    try:
        output = subprocess.check_output(["systemctl", "start", service_name])
        return True, service_name + " started"
    except subprocess.CalledProcessError as e:
        return False, "Exception while starting " + service_name

def restartService(service_name):
    try:
        output = subprocess.check_output(["systemctl", "restart", service_name])
        return True, service_name + " restarted"
    except subprocess.CalledProcessError as e:
        return False, "Exception while restarting " + service_name

def stopService(service_name):
    try:
        output = subprocess.check_output(["systemctl", "stop", service_name])
        return True, service_name + " stopped"
    except subprocess.CalledProcessError as e:
        return False, "Exception while stopping " + service_name

def isServiceActive(service_name):
    try:
        output = subprocess.check_output(["systemctl", "is-active", service_name])
        if "active" in output:
            return True, service_name + " is active"
        return False, service_name + " is inactive"
    except subprocess.CalledProcessError as e:
        return False, "Exception while reading status of " + service_name

def isServiceInstalled(service_name):
    try:
        output = subprocess.check_output(["systemctl", "list-unit-files", service_name])
        if "1 unit files listed" in output:
            return True, service_name + " is installed"
        return False, service_name + " is not installed"
    except subprocess.CaledProcessError as e:
        return False, "Execption while looking for " + service_name

def disableService(service_name):
    try:
        output = subprocess.check_output(["systemctl", "disable", service_name])
        return True, service_name + " disabled"
    except subprocess.CalledProcessError as e:
        return False, "Exception while disabling " + service_name

def enableService(service_name):
    try:
        output = subprocess.check_output(["systemctl", "enable", service_name])
        return True, service_name + " enabled"
    except subprocess.CalledProcessError as e:
        return False, "Exception while enabling " + service_name

def isServiceEnabled(service_name):
    try:
        output = subprocess.check_output(["systemctl", "is-enabled", service_name])
        if "enabled" in output:
            return True, service_name + " is enabled"
        return False, service_name + " is disabled"
    except subprocess.CalledProcessError as e:
        return False, "Exception while reading status of " + service_name

def isProcessRunning(process_name,  verbose=False):
    """check if a process is running, return tuple (status, message)
    process_name is case sensitive
    """
    if len(process_name) == 0:
        return False, "No process name given"

    if verbose:
        print ""
        print "-Check if %s process is running" % (process_name)

    status = False
    try:
        output = subprocess.check_output(["ps", "-C", process_name, "-o", "comm="])
        output = output.decode('utf-8')
        if output.find(process_name) != -1:
            status = True
            message = "Process %s is running" % process_name
    except subprocess.CalledProcessError as e:
        message =  "Process %s is not running" % process_name
    except Exception as e:
        message = "Generic exception while checking if %s process was running:%s" % (process_name, e)

    if verbose:
        print message
    return status, message

def call_shell(command, check_error_code=True):
    '''
    Call a shell application and return a tuple (return error code, command output)
    @command: command to execute as a list of command followed by parameters
    @check_error_code: if True, an exception is raised if return code is not 0
    '''
    try:
        logger.debug("Execute: \"{}\"".format(" ".join(command)))
        output = subprocess.check_output(command,stderr=subprocess.STDOUT)
        output = output.rstrip('\n')
        logger.debug("Execute output is \"{}\"".format(output))
        return (0, output)
    except subprocess.CalledProcessError as e:
        if check_error_code:
            logger.exception("Command: {} has failed with error code {}. Output is: {}".format(command, e.returncode, e.output))
            raise
        return (e.returncode, e.output)

def call_shell_with_timeout(command, timeout=0, check_error_code=True):
    '''
    Call a shell application and return a tuple (return error code, command output)
    In case of timeout, error code is set to 1, and command ouput is set to None
    @command: command to execute as a list of command followed by parameters
    @timeout: max time to wait for command execution, in seconds
    @check_error_code: if True, an exception is raised if return code is not 0
    '''
    try:
        start = datetime.datetime.now()
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        while process.poll() is None:
            time.sleep(0.1)
            now = datetime.datetime.now()
            if (now - start).seconds > timeout:
                os.kill(process.pid, signal.SIGKILL)
                os.waitpid(-1, os.WNOHANG)
                return (1, None)
        return (0,process.stdout.read())
    except subprocess.CalledProcessError as e:
        if check_error_code:
            logger.exception("Command: {} has failed with error code {}. Output is: {}".format(command, e.returncode, e.output))
            raise
        return (e.returncode, e.output)


def get_controller_type():
    '''
    Returns the controller type as given by script /usr/local/bin/whichcontrollerami.sh.
    Includes exception handling for script execution.
    Possible return values: "mcb", "seacloud", "".
    '''
    try:
        # check on which system were are running and set rl78 file name accordingly
        (result, controller) = call_shell(["/bin/sh","-c", "/usr/local/bin/whichcontrollerami.sh"])
        if result != 0:
            logger.error("Unable to get controller type via /usr/local/bin/whichcontrollerami.sh")
            return ""
    except subprocess.CalledProcessError as e:
        logger.error("exception while ececuting /usr/local/bin/whichcontrollerami.sh")
        return ""

    return controller


def get_update_type():
    '''
    Returns the update type as given by script whichupdateami.sh.
    Includes exception handling for script execution.
    Possible return values: "mcb", "seacloud", "".
    '''
    # update type script is expected in current directory (update base folder))
    update_base_folder_name = os.getcwd()
    update_type_file="{0}/whichupdateami.sh".format(update_base_folder_name)
    if os.path.exists(update_type_file):
        try:
            # check on which system were are running and set rl78 file name accordingly
            (result, upd_type) = call_shell(["/bin/sh","-c", update_type_file])
            if result != 0:
                logger.error("Unable to get update type via {0}".format(update_type_file))
                return ""
        except subprocess.CalledProcessError as e:
            logger.error("exception while ececuting {0}".format(update_type_file))
            return ""
    else:
        logger.error("{0} does not exist.".format(update_type_file))
        return ""

    logger.info("Update type = {}".format(upd_type))
    return upd_type
