# Copyright 3D Control Systems, Inc. All Rights Reserved 2017-2019.

# Built in San Francisco.

# This software is distributed under a commercial license for personal,
# educational, corporate or any other use.
# The software as a whole or any parts of it is prohibited for distribution or
# use without obtaining a license from 3D Control Systems, Inc.

# All software licenses are subject to the 3DPrinterOS terms of use
# (available at https://www.3dprinteros.com/terms-and-conditions/),
# and privacy policy (available at https://www.3dprinteros.com/privacy-policy/)

import findssh
import logging
import time
import zeroconf

import http_detect

class ZeroconfDetector(http_detect.HTTPDetector):

    PORT = 80 # port is not real port on which zeronconf responded, but port belong to printer's API
    TIMEOUT = 6
    DEFAULT_MDNS_SERVICE_NAME = "_http._tcp.local."
    #DEFAULT_MDNS_SERVICE_NAME = "_mpd._tcp.local."
    #DEFAULT_MDNS_SERVICE_NAME = "_nvstream_dbd._tcp.local."

    def __init__(self, parent, profile):
        self.logger = logging.getLogger(__name__)
        self.parent = parent
        self.profile = profile
        self.discovered_printers = []
        self.ip = findssh.getLANip()
        self.service_name = self.DEFAULT_MDNS_SERVICE_NAME
        self.port = self.PORT
        if profile and profile.get("network_detect"):
            service_name = profile.get("network_detect").get('filter')
            if not service_name.endswith('.local.'):
                service_name += '.local.'
            self.service_name = service_name
            self.port = int(profile.get("network_detect").get('port', self.PORT))

    def set_service_name(self, service_name):
        self.service_name = service_name

    def detect(self, already_know_ip=None, non_default_port=None):
        if non_default_port:
            self.port = non_default_port
        self.zeroconf = zeroconf.Zeroconf()
        self.browser = zeroconf.ServiceBrowser(self.zeroconf, self.service_name, self)
        count = 100
        sleep_per_loop = self.TIMEOUT / count
        while count:
            time.sleep(sleep_per_loop)
            count -= 1
        self.zeroconf.close()

    def remove_service(self, zeroconf, service_type, name):
        self.logger.debug("Service %s removed" % (name,))

    def check_ip(self, host):
        self.logger.warning(f"A real check_ip is not implemented for {__class__.__name__}!")
        return True

    def add_service(self, zeroconf, service_type, name):
        info = zeroconf.get_service_info(service_type, name)
        try:
            ip = info.parsed_addresses()[0]
        except:
            self.logger.error('Failed to determine IP address of detected service')
            ip = None
        else:
            # port is not real port on which zeronconf responded, but port belong to printer's API
            self.logger.info(f"Zeroconf service found on {ip}")
            self.logger.debug(f"Service {name} added:\nIP:{ip}\nInfo:{info}")
            if self.check_ip(ip):
                discovered_host = {"IP": ip, "PORT": self.port, "SNR": ip}
                self.logger.info(f"Adding printer: {discovered_host}")
                self.discovered_printers.append(discovered_host)
            else:
                self.logger.debug(f"Skipping host(printer check failed): {discovered_host}")
