"""
Created on Oct 30, 2013

@author: Nicklas Boerjesson
"""
import platform
import sys

from qal.common.strings import empty_if_none


def platform_to_int():
    """Returns an integer depending on platform."""
    if platform.system().lower() == "linux":
        return 0
    elif platform.system().lower() == "windows":
        return 1
    elif platform.system().lower() == "darwin":
        return 2
    else:
        return 3


def import_error_to_help(_module, _err_obj, _pip_package, _apt_package, _win_package, _import_comment=None):
    """Usable to create a helpful error message if a module is missing"""
    if str(_err_obj) == "No module named '" + str(_module) + "'":
        _err_msg = "The python " + get_python_versions(_style="Minor") + " module \"" + str(
            _module) + "\" is not installed.\n"
        _err_msg += ["Run sudo pip3 install " + str(_pip_package) +
                     empty_if_none(" or sudo apt-get install " + str(_apt_package), _apt_package),
                     "Either run pip install " + str(_pip_package) + empty_if_none(
                         ", download and install " + str(_win_package) +
                         " or install from source.", _win_package),
                     "If available on your platform, run pip" + get_python_versions(_style="Minor") + " install " + str(
                         _pip_package) +
                     " otherwise download and install from source."][platform_to_int()]
        return _err_msg + empty_if_none("\n" + str(_import_comment), _import_comment)
    else:
        return str(_err_obj)


def discover_database_servers(_ip):
    """Uses Nmap to scan the subnet of the specified IP-address for the following RDBMS:
    SQL Server, IBM DB2, MYSQL, Oracle and Postgres."""
    return discover_services(_ip, [1433, 523, 1521, 5432, 3306], True)


def discover_services(_ip, _ports, _verbose=False):
    """Uses Nmap to scan the subnet of the specified IP-address for services on the specified ports"""

    try:
        import nmap  # import nmap.py module
    except ImportError as _err:
        raise Exception(
            import_error_to_help(_module="nmap", _err_obj=_err, _pip_package="python-nmap", _apt_package=None,
                                 _win_package=None))

    try:
        _nm = nmap.PortScanner()  # instantiate nmap.PortScanner object
    except nmap.PortScannerError:
        raise Exception('Nmap not found(nmap not installed on the system?)', sys.exc_info()[0])
    except Exception as e:
        print("Unexpected error:" + str(e), sys.exc_info()[0])
        raise Exception(str(e))

    _ips = _ip.split(".")
    _new_ip = ".".join(_ips[0:3])
    _port_str = ",".join(str(x) for x in _ports)
    if _verbose:
        print("Scanning " + _new_ip + ".2-254, ports " + _port_str)

    _nm.scan(hosts=_new_ip + ".2-254", arguments="-p T:" + _port_str + " -T4 -sV")

    _detected_services = []
    for _host in _nm.all_hosts():
        if _nm[_host].state() == 'up':
            if _verbose:
                print('----------------------------------------------------')
                print('Host : %s (%s)' % (_host, _nm[_host].hostname()))
                print('State : %s' % _nm[_host].state())

            for _proto in _nm[_host].all_protocols():
                if _verbose:
                    print('----------')
                    print('Protocol : %s' % _proto)

                for _port in _nm[_host][_proto]:
                    if isinstance(_nm[_host][_proto][_port], dict) and _nm[_host][_proto][_port]['state'] == 'open':
                        if _verbose:
                            print(_nm[_host].hostname() + " - " + _nm[_host][_proto][_port]['product'] + _host)
                        _detected_services.append([_host, _nm[_host].hostname(), _nm[_host][_proto][_port]['product']])

    return _detected_services


def get_python_versions(_style=None):
    """
    Return the current version of python, styled in different ways:
    * major : 3
    * minor : 3.4
    * release : 3.4.4
    * build : 3.4.4 build 1300

    :param _style: Style of the the result.
    """
    _major, _minor, _release, _state, _build = sys.version_info

    if _style is None or _style.lower() == "full":
        return str(_major) + "." + str(_minor) + "." + str(_release) + " " + _state + " build " + str(_build)
    elif _style.lower() == "major":
        return str(_major)
    elif _style.lower() == "minor":
        return str(_major) + "." + str(_minor)
    elif _style.lower() == "release":
        return str(_major) + "." + str(_minor) + "." + str(_release)

    else:
        raise Exception("Error in get_python_versions: Invalid _style-parameter :'" + _style + "'")


