from JumpScale import j


def mbToKB(value):
    if not value:
        return value
    return value * 1024


def getInt(val):
    if val is not None:
        return int(val)
    return val


class system_gridmanager(j.tools.code.classGetBase()):
    """
    gateway to grid
    """

    def __init__(self):
        self._te = {}
        self.actorname = "gridmanager"
        self.appname = "system"
        self.clients = {}
        self._nodeMap = dict()
        self.clientsIp = dict()

    def getQuery(self, params):
        query = {}
        for key, value in params.items():
            if 'None' not in str(value):
                query[key] = value
        return query

    def getClient(self, nid, category):
        nid = int(nid)
        if nid not in self.clients:
            if nid not in self._nodeMap:
                self.getNodes()
            if nid not in self._nodeMap:
                raise RuntimeError('Could not get client for node %s!' % nid)
            for ip in self._nodeMap[nid]['ipaddr']:
                if j.sal.nettools.tcpPortConnectionTest(ip, 4446):
                    user = "root"  # j.application.config.get('system.superadmin.login')
                    self.clients[nid] = j.servers.geventws.getClient(
                        ip, 4446, org="myorg", user=user, passwd='fake', category=category)
                    self.clientsIp[nid] = ip
                    return self.clients[nid]
            raise RuntimeError('Could not get client for node %s!' % nid)

        return self.clients[nid]

    def getNodeSystemStats(self, nid, **kwargs):
        """
        ask the right processmanager on right node to get the information about node system
        param:nid id of node
        result json
        """
        nid = int(nid)
        client = self.getClient(nid, 'stats')

        try:
            stats = client.listStatKeys('n%s.system.' % nid)
        except Exception as e:
            # from IPython import embed
            # print "DEBUG NOW getNodeSystemStats"
            # embed()
            pass

        cpupercent = [stats['n%s.system.cpu.percent' % nid][-1]]
        mempercent = [stats['n%s.system.memory.percent' % nid][-1]]
        netstat = [stats['n%s.system.network.kbytes.recv' % nid][-1], stats['n%s.system.network.kbytes.send' % nid][-1]]

        result = {'cpupercent': [cpupercent, {'series': [{'label': 'CPU PERCENTAGE'}]}],
                  'mempercent': [mempercent, {'series': [{'label': 'MEMORY PERCENTAGE'}]}],
                  'netstat': [netstat, {'series': [{'label': 'KBytes Recieved'}, {'label': 'KBytes Sent'}]}]}
        return result

    def getNodes(self, id=None, gid=None, nid=None, name=None, roles=None, ipaddr=None, macaddr=None,
                 active=None, peer_stats=None, peer_log=None, peer_backup=None, lastcheckFrom=None, lastcheckTo=None, **kwargs):
        """
        param:id str,,find based on id
        param:gid int,,find nodes for specified grid
        param:name str,,match on text in name
        param:roles str,,match on comma separated list of roles (subsets also ok e.g. kvm.  would match all roles starting with kvm.)
        param:ipaddr str,,comma separated list of ip addr to match against
        param:macaddr str,,comma separated list of mac addr to match against
        param:active bool,,True,is the node still active
        param:peer_stats int,,id of node which has stats for this node
        param:peer_log int,,id of node which has logs (e.g. transactionlogs) for this node
        param:peer_backup int,,id of node which has backups for this node
        param:lastcheckFrom str,-1h,-4d;-4w;-4m;-1h;-1s  d=day w=week m=month s=sec  find nodes with lastcheckFrom  (-4d means 4 days ago)
        param:lastcheckTo str,-1h,-4d;-4w;-4m;-1h;-1s  d=day w=week m=month s=sec  find nodes with lastcheckTo  (-4d means 4 days ago)
        result:list(list)
        """
        if id:
            results = j.data.models.system.Node.get(id)
        else:
            lastcheckFrom = self._getEpoch(lastcheckFrom)
            lastcheckTo = self._getEpoch(lastcheckTo)
            params = {'gid': getInt(gid),
                      'nid': getInt(nid),
                      'name': name,
                      'active': active,
                      'lastcheck': {'$gte': lastcheckFrom},
                      'lastcheck': {'$lte': lastcheckTo},
                      'peer_stats': peer_stats,
                      'peer_log': peer_log,
                      'peer_backup': peer_backup,
                      }
            params = self.getQuery(params)
            results = j.data.models.system.Node.find(params)

        def myfilter(node):
            self._nodeMap[node['id']] = node
            if roles and not set(roles).issubset(set(node['roles'])):
                return False
            if ipaddr and ipaddr not in node['ipaddr']:
                return False
            if macaddr and macaddr not in node['netaddr']:
                return False
            return True

        return list(filter(myfilter, results))

    def getProcessStats(self, nid, domain="", name="", **kwargs):
        """
        ask the right processmanager on right node to get the information
        param:nid id of node
        param:domain optional domain name for process
        param:name optional name for process
        result json
        """
        if domain == "*":
            domain = ""
        if name == "*":
            name = ""
        client = self.getClient(nid)
        return client.monitorProcess(domain=domain, name=name)

    def _showUnavailable(self, width, height, message="STATS UNAVAILABLE"):
        import PIL.Image as Image
        import PIL.ImageDraw as ImageDraw
        import io

        size = (int(width), int(height))
        im = Image.new('RGB', size, 'white')
        draw = ImageDraw.Draw(im)
        red = (255, 0, 0)
        text_pos = (size[0] / 2, size[1] / 2)
        text = message
        draw.text(text_pos, text, fill=red)

        del draw
        output = io.StringIO()
        im.save(output, 'PNG')
        del im
        response = output.getvalue()
        output.close()
        return response

    def getStatImage(self, statKey, title=None, aliases={}, width=500, height=250, **kwargs):
        """
        @param statkey e.g. n1.disk.mbytes.read.sda1.last
        """
        import urllib.request
        import urllib.parse
        import urllib.error
        query = list()
        ctx = kwargs['ctx']
        ctx.start_response('200', (('content-type', 'image/png'),))
        statKey = statKey.strip()

        for target in statKey.split(','):

            if target in aliases:
                target = "alias(%s, '%s')" % (target, aliases[target])
            query.append(('target', target))
        if title:
            query.append(('title', title))

        query.append(('height', height))
        query.append(('width', width))
        query.append(('lineWidth', '2'))
        query.append(('graphOnly', 'false'))
        query.append(('hidexAxes', 'false'))
        query.append(('hidexGrid', 'false'))
        query.append(('areaMode', 'none'))
        query.append(('tz', 'CET'))

        params = kwargs.copy()
        params.pop('ctx')
        for key, value in params.items():
            query.append((key, value))

        querystr = urllib.parse.urlencode(query)
        url = "http://127.0.0.1:8081/render?%s" % (querystr)
        r = requests.get(url)
        try:
            result = 
r.send()
        except Exception:
            return self._showUnavailable(width, height, "GRAPHITE UNAVAILABLE")
        return result.content

    def getProcessesActive(self, nid, name, domain, **kwargs):
        """
        ask the right processmanager on right node to get the info
        output all relevant info (no stat info for that we have getProcessStats)
        param:nid id of node (if not spe
cified goes to all nodes and aggregates)
        param:name optional name for process name (part of process name)
        param:domain optional name for process domain (part of process domain)
        result json
        """
        client = self.getClient(nid)
   