#!/bin/python

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from .mbio import MBIO


from threading import Thread, Lock
from queue import Queue
import ipcalc


class MBIONetworkScanner(object):
    def __init__(self, mbio: MBIO, network=None, maxthreads=32):
        self._mbio=mbio
        self._network=network or mbio._network
        self._maxthreads=maxthreads
        self._queue=Queue()
        self._lock=Lock()
        self._hosts={}

    def reset(self):
        self._hosts={}

    @property
    def mbio(self):
        return self._mbio

    @property
    def logger(self):
        return self.mbio.logger

    def hosts(self):
        hosts=[]
        try:
            n=ipcalc.Network(self._network)
            for host in n:
                hosts.append(str(host))
        except:
            pass
        return hosts

    def probe(self, host):
        # to be overriden
        # should return the hostid (i.e. mac)
        return None

    def declareHost(self, host, hostid):
        if host and hostid:
            with self._lock:
                self.logger.warning('%s: found host %s (%s)...' % (self.__class__.__name__, host, hostid))
                if host not in self._hosts:
                    self._hosts[host]=hostid.lower()

    def probeNetwork(self):
        while True:
            try:
                host=self._queue.get()
            except:
                break

            try:
                # self.logger.debug('%s: scanning host %s...' % (self.__class__.__name__, host))
                hostid=self.probe(host)
                if hostid:
                    self.declareHost(host, hostid)
            except:
                self.logger.exception('probe')
                pass
            self._queue.task_done()

    def scan(self):
        self.reset()
        if self._network:
            hosts=self.hosts()
            if hosts:
                for t in range(self._maxthreads):
                    t = Thread(target=self.probeNetwork)
                    t.daemon = True
                    t.start()

                for host in hosts:
                    self._queue.put(host)

                self._queue.join()
                return self._hosts

    def configureHostFromGateway(self, host, gateway):
        # to be overriden
        pass

    def configureNetwork(self):
        hosts=self.scan()
        if hosts:
            for host in hosts:
                hostid=hosts[host]
                # check if the hostid (i.e MAC) is known on the declared gateways
                gateway=self.mbio.gateway(hostid)
                if gateway:
                    try:
                        self.configureHostFromGateway(host, gateway)
                    except:
                        self.logger.exception('reconfigureHostFromGateway')


if __name__=='__main__':
    pass
