#coding:utf-8

import os
import sys
import xml.sax
import importlib
import subprocess 
from xml.sax import handler
import sunhpc.modules as sunhpc_modules

MODULES_DIR = sunhpc_modules.__path__[0]

# Sunhpc exception hierarchy
class SunhpcException(Exception):
    """Base class for Sunhpc exceptions."""
    pass

class HostnotfoundException(SunhpcException):
    """This exception is used when the given host does not exist"""
    pass

class ParameterNotValid(SunhpcException):
    """This exception is used when the user input parameters are 
    not valid"""
    pass

class CommandError(SunhpcException):
    """This exception is thrown by the sunhpc command line when 
    something goes awry"""
    pass

class KickstartError(SunhpcException):
    pass

class KickstartGraphError(KickstartError):
    pass

class KickstartNodeError(KickstartError):
    pass

class SafeError(KickstartError):
    pass

class InsertError(Exception):
    pass

class InsertDone(Exception):
    pass

class DumpError(Exception):
    pass

class Struct:
    pass


def escapeAttr(value):
    """escape attribute values with XML escaping"""
    if value is None:
        return value
    return xml.sax.saxutils.escape(value, { "\"": "&quot;",
                        "%": "&#x0025;",
                        "'": "\\'"})

def unescapeAttr(value):
    """unescape attribute values with XML escaping """
    if value is None:
        return value
    return xml.sax.saxutils.unescape(value, {"&quot;": "\"",
                        "&#x0025;": "%"})

def escapeStringForShell(string):
    """escape the given string so that it can be used in a shell script
    inside a double quote string"""
    return string.replace("\"", "\\\"") 

def str2bool(s):
    """Converts an on/off, yes/no, true/false string to 1/0."""
    if s and s.upper() in [ 'ON', 'YES', 'Y', 'TRUE', '1', 'ENABLED', 'ENABLE']:
        return True
    else:
        return False

def bool2str(b):
    """Converts an 1/0 to a yes/no"""
    if b:
        return 'yes'
    else:
        return 'no'

def list2str(list):
    s = ''
    for e in list:
        s = s + e
    return s


def listcmp(l1, l2):
    return map(lambda a,b: a==b, l1, l2)

def listdup(e, n):
    l = []
    for i in range(0, n):
        l.append(e)
    return l


def list_isprefix(l1, l2):
    l = listcmp(l1, l2)
    for i in range(0, len(l1)):
        if not l[i]:
            return 0
    return 1

def getNativeArch():
    """Returns the canotical arch as reported by the operating system"""
    
    arch = os.uname()[4]
    if arch in [ 'i386', 'i486', 'i586', 'i686']:
        arch = 'i386'
    return arch

def mkdir(newdir):
    """Works the way a good mkdir should :)
        - already exists, silently complete
        - regular file in the way, raise an exception
        - parent directory(ies) does not exist, make them as well
        From Trent Mick's post to ASPN."""
    if os.path.isdir(newdir):
        pass
    elif os.path.isfile(newdir):
        raise OSError("a file with the same name as the desired " \
                    "dir, '%s', already exists." % newdir)
    else:
        head, tail = os.path.split(newdir)
        if head and not os.path.isdir(head):
            mkdir(head)
        if tail:
            os.mkdir(newdir)

class ParseXML(handler.ContentHandler,
          handler.DTDHandler,
          handler.EntityResolver,
          handler.ErrorHandler):
    """A helper class to for XML parsers. Uses our
    startElement_name style."""

    def __init__(self, app=None):
        handler.ContentHandler.__init__(self)
        self.app = app
        self.text = ''
        
    def startElement(self, name, attrs):
        """The Mason Katz school of parsers. Make small functions
        instead of monolithic case statements. Easier to override and
        to add new tag handlers."""
        try:
            f = getattr(self, "startElement_%s" % name)
            f(name, attrs)
        except AttributeError:
            return

    def endElement(self, name):
        try:
            f = getattr(self, "endElement_%s" % name)
            f(name)
        except AttributeError:
            return

    def characters(self, s):
        self.text += s

def system(cmd, type='standard'):
    if type == 'spinner':
        return startSpinner(cmd)
    else:
        return subprocess.call(cmd, shell=True)

def startSpinner(cmd):
    """This used to just be a system() but now we
    control the child output to keep the status
    on one line using stupid CR terminal tricks.
    We even add a way cool spinny thing in
    column zero just to be l33t!
    
    Does not show standard error output."""

    p = subprocess.Popen(cmd, shell=True, 
            stdin=subprocess.PIPE, stdout=subprocess.PIPE, 
        stderr=subprocess.PIPE, close_fds=True)
    w, r ,e = (p.stdin, p.stdout, p.stderr)
    currLength  = 0
    prevLength  = 0
    spinChars   = '-\|/'
    spinIndex   = 0
    while 1:
        line = e.readline()
        if not line:
            break
        if len(line) > 79:
            data = line[0:78]
        else:
            data = line[:-1]
        currLength = len(data)
        pad = ''
        for i in range(0, prevLength - currLength):
            pad = pad + ' '
        spin  = spinChars[spinIndex % len(spinChars)]
        spinIndex = spinIndex + 1
        print (spin + data + pad + '\r', end='')
        prevLength = currLength
        sys.stdout.flush()
    r.close()
    w.close()
    e.close()
        
    # Cleanup screen when done
    pad = ''
    for i in range(0,78):
        pad = pad + ' '
    print ('\r%s\r' % pad, end='')

def index_modules(modules_directory: str = MODULES_DIR) -> list:
    """ Returns list of all exploits modules

    :param str modules_directory: path to modules directory
    :return list: list of found modules
    """
    modules = []
    for root, dirs, files in os.walk(modules_directory):
        files.sort()
        _, package, root = root.rpartition("sunhpc/modules/".replace("/", os.sep))
        root = root.replace(os.sep, ".")
        files = filter(lambda x: not x.startswith("__") and x.endswith(".py"), files)
        modules.extend(map(lambda x: ".".join((root, os.path.splitext(x)[0])), files))

    return modules

def import_centrals(module: str):
    """ Imports centrals module

    :param str path: absolute path to centrals e.g. routersploit.modules.exploits.asus_auth_bypass
    :return: centrals module or error
    """
    try:
        # 判断模块中的类名称.
        module = importlib.import_module(module)
        if hasattr(module, "Modules"):
            return getattr(module, "Modules")
        elif hasattr(module, "Plugins"):
            return getattr(module, "Plugins")
        else:
            raise ImportError("No module named '{}'".format(module))

    except (ImportError, AttributeError, KeyError) as err:
        pass






















