# Copyright 2015 VMware, Inc.  All rights reserved. -- VMware Confidential
#
'''The file contains Operating System utilities.
'''

import platform
import os
import logging

import transport
from transport.local import LocalOperationsManager

logger = logging.getLogger(__name__)

class Platform:
    '''List of supported OS platforms.'''
    WINDOWS = 'Windows'
    LINUX = 'Linux'

def isLinux(osType=None):
    '''Tests if the given osType is *nux based. If the osType is not specified, then
    test if the local Operating system is *nix based one.

    @param osType: OS platform. The expected values are Windows or Linux.
    @type osType: str.
    '''
    osType = osType or getPlatform()
    return osType.lower() == 'linux'

def isWindows(osType=None):
    '''Tests if the given osType is from Windows family. If the osType is not specified,
    then test if the local Operating system is from Windows family.

    @param osType: OS platform. The expected values are Windows or Linux.
    @type osType: str.
    '''
    osType = osType or getPlatform()
    return osType.lower() == 'windows'

def translatePlatform(platformKind):
    '''Translates the platform kind to either Windows or Linux constants. The utility
    is responsible to translate the platform to unified platform constants.

    @param platformKind: Platform kind in insensitive case. Expected Windows or Linux.
    @type platformKind: str

    @return: constant from Platform structure.
    '''
    result = Platform.WINDOWS if platformKind.lower() == 'windows' else Platform.LINUX
    logger.debug("Translate platform kind %s to %s", platformKind, result)
    return result

def getPlatform():
    '''Gets the type of operating system.

    @return: 'Linux' if the local OS is Unix based
      'Windows' if the local OS is Windows based
    @raise exception: If the local OS is unknown.
    '''
    osType = platform.system()
    if osType == '':
        raise ValueError('The local operating system is not supported')

    result = translatePlatform(osType)
    return result

def getOSObject(linuxObject, windowsObject):
    '''Returns either linuxObject or windowsObject according to local OS type.

    @param linuxObject: The object which is going to be returned if we are
      running on Linux OS. This argument is mutually exclusive with windowsObject
      parameter.

    @param windowsObject: The object which is going to be returned if we are
      running on Windows OS. This argument is mutually exclusive with linuxObject
      parameter.

    @return: linuxObject parameter if we're running on Linux OS, otherwise
      windowsObject

    Example:
      magicNumber = os_utils.getOSObject(12, 34)
      statusParser = os_utils.getOSObject(MyStatusParser(), None)
    '''
    resultObject = linuxObject if isLinux() else windowsObject

    return resultObject

def createDirectory(directory):
    '''Creates the path to given directory.

    @return: True if the directory has been created or False if the directory
      has existed before the call.
    '''
    if not os.path.exists(directory):
        os.makedirs(directory)
        return True
    else:
        if not os.path.isdir(directory):
            error = "Cannot create directory '%s' because a regular file with that " \
                    "name already exists" % directory
            logger.error(error)
            raise ValueError(error)

        return False

def executeCommand(commandArgs, cwd=None, localStdinFile=None, env=None):
    '''Executes a command locally and return the result kept in the
    memory. This routine waits for the process to finish.

    @param commandArgs: list command and arguments, e.g. ['ls', '-l']
    @type commandArgs: list of string

    @param cwd: newer process current working directory to set to.
    @type cwd: string

    @param localStdinFile: local file to be used as stdin, None for no stdin
    @type localStdinFile: str

    @param env: extension of local environment. The type is dictionary where
      lookup key points to the env variable name and lookup value to the env value.
      Pay attention that duplicated variables would be replaced rather than
      extending their value, i.e. if you want to extend that PATH variable
      you need to retrieve the local PATH value, extend its value and pass
      the extended environment variable.
    @type env: dict

    @return: Tuple of stdout, stderr and process exit code
    @rtype: Tuple

    @raise ExecutionException: if a command cannot be executed.
    '''
    result = transport.executeCommand(LocalOperationsManager(),
                                      commandArgs, cwd, localStdinFile, env)

    return result.stdout, result.stderr, result.exitCode

def getCommandExitCode(commandArgs, cwd=None, localStdinFile=None,
                localStdoutFile=None, localStderrFile=None, env=None):
    '''Executes a command locally, capture the stdout and stderr in
      files and return the process exit code. This routine waits for the
      process to finish before return the result.

    @param commandArgs: list command and arguments, e.g. ['ls', '-l']
    @type commandArgs: list of string

    @param cwd: newer process current working directory to set to.
    @type cwd: string

    @param localStdinFile: local file to be used as stdin, None for no stdin
    @type localStdinFile: str

    @param localStdoutFile: local file to capture stdout to, None for no stdout capture
    @type localStdoutFile: str

    @param localStdErr: local file to capture stderr to, None for no stderr capture
    @type localStdErrFile: str

    @param env: extension of local environment. The type is dictionary where
      lookup key points to the env variable name and lookup value to the env value.
      Pay attention that duplicated variables would be replaced rather than
      extending their value, i.e. if you want to extend that PATH variable
      you need to retrieve the local PATH value, extend its value and pass
      the extended environment variable.
    @type env: dict

    @return: process exit code
    @raise ExecutionException: If the command cannot be executed.
    '''
    exitCode = transport.getCommandExitCode(LocalOperationsManager(),
                                            commandArgs, cwd, localStdinFile,
                                            localStdoutFile, localStderrFile,
                                            env, supressLogging=True)

    return exitCode

def getCommandOutput(commandArgs):
    '''Executes a command locally and return the stdout as a string.
    This routine waits for the process to finish before return the result.

    Example:
        cmd = ['ls', '-l']
        result = os_utils.getCommandOutput(cmd)
        print result

    @param commandArgs: list command and arguments, e.g. ['ls', '-l']
    @type commandArgs: list of str

    @return: The stdout of executed command.
    @rtype: str

    @raise ExecutionException: if a command cannot be executed.
    '''
    stdout = transport.getCommandOutput(LocalOperationsManager(), commandArgs,
                                        supressLogging=True)
    return stdout
