import inspect
import logging
from subprocess import Popen, PIPE, STDOUT

from sjrpc.utils import pure

from ccnode.node import DefaultHandler
from ccnode.tags import Tag, DynamicTags
from ccnode.host import tags


logger = logging.getLogger(__name__)


class Handler(DefaultHandler):
    """Handler for host role."""
    def __init__(self, *args, **kwargs):
        DefaultHandler.__init__(self, *args, **kwargs)

        # add host tags to self.tags dict
        [
            'cpu',
            'cpuuse',
            'arch',
            'chaserial',
            'cpufreq',
            'disk',
            'hmodel',
            'hserial',
            'hvendor',
            'hbios',
            'load',
            'mem',
            'memfree',
            'memused',
            'os',
            'platform',
            'sto',
            'uname',
            'uptime',
        ]
        logger.debug(u'Begin introspection')
        for n, m in inspect.getmembers(tags):  # (name, member)
            # only keep strings or functions as tags
            if getattr(m, '__module__', None) != 'ccnode.host.tags' or (
                n.startswith('_')):
                continue
            elif isinstance(m, (str, unicode)):
                # if string, it means it is constant, then ttl = -1
                ttl = -1
            elif inspect.isfunction(m):
                # if function take function ttl argument or set -1 by default
                ttl = getattr(m, 'ttl', -1)
            elif isinstance(m, DynamicTags):
                logger.debug('plop')
                for t in m.iter_tags():
                    self.tags[t.name] = t
                    logger.debug('Introspected %s with ttl %s.' % (t.name,
                                                                   t.ttl))
                continue
            else:
                continue

            logger.debug('Introspected %s with ttl %s.' % (n, ttl))

            # finally add the tag
            self.tags[n] = Tag(n, m, ttl)
        logger.debug(u'End introspection')

    @pure
    def execute_command(self, command):
        """Execute an arbitrary shell command on the host.
        
        :param string command: shell command to run
        """
        # return stdout and stderr mixed in
        return Popen(command, shell=True, bufsize=-1, stdin=PIPE, stdout=PIPE,
                     stderr=STDOUT).communicate()[0] or None

    @pure
    def node_shutdown(self, reboot=True, gracefull=True):
        """Halt/Reboot the node."""
        args = ['/sbin/shutdown']
        if reboot:
            args.append('-r')
            if gracefull:
                logger.info(u'Going to reboot the host...')
                args.append('-f')
            else:
                logger.info(u'Going to force the reboot of the host...')
                args.append('-n')
        else:
            # halt
            args.append('-h -P')
            if not gracefull:
                logger.info(u'Going to halt the host...')
                args.append('-n')
            else:
                logger.info(u'Going to force the halt of the host...')

        args.append('0')

        return self.execute_command(' '.join(args))