import sys
import time
import uuid

ONEYEAR = 366 * 24 * 3600


def get_abs_time(times):
    """Gets the absolute times for the given potential relative times.

    If a given timestamp is less than one year, then the value is
    relative (to now, rounded up to a full second) and converted
    into an absolute timestamp

    Parameters :
        times([(float)]) : an array of unix timestamps or relative duration (< 1 year) as floats

    Returns :
        [(float)] : an array of absolute unix timestamps as floats
    """
    now = int(time.time() + 0.999)
    return [t + now if t < ONEYEAR else t for t in times]


class Logger(object):
    def __init__(self, logpath):
        self.terminal = sys.stdout
        self.log = open(logpath, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        pass


class HandlerBase:
    def __init__(self):
        self.handlers = {k[2:]: getattr(self, k) for k in dir(type(self)) if k.startswith('w_')}


class Client(HandlerBase):
    def __init__(self, server, streams, instrument_name, device_name):
        super().__init__()
        self.id = uuid.uuid4().hex[0:15]
        self.nodes = {}
        self.node_map = {}
        if streams:
            for uri in streams:
                urisplit = uri.rsplit('://')
                kind = urisplit[0] if len(urisplit) == 2 else 'secop'
                node = server.interactor_classes[kind](uri, self.node_map)
                self.nodes[uri] = node
        self.server = server
        self.instrument_name = instrument_name
        self.device_name = device_name  # do not know if this is needed
        self.updates = {}

    def poll(self):
        updates = sum((n.get_updates() for n in self.nodes.values()), start=[])
        result = [dict(type='update', updates=updates)] if updates else []
        graph_updates = self.handlers.get('graphpoll', object)()
        if graph_updates:
            result.append(graph_updates)
        return result

    def w_getblock(self, path):
        path = path.split(',')[-1]  # TODO: why this?
        if path == "main":  # TODO: change to "-main-"?
            components = []
            for node in self.nodes.values():
                node.add_main_components(components)
            return dict(type='draw', path='main', title='modules', components=components)
        node = self.node_map[path]
        return dict(type='draw', path=path, title=path, components=node.get_components(path))

    def w_updateblock(self, path):
        if path == 'main':  # TODO: change to "-main-"?
            for node in self.nodes.values():
                node.update_main()
        else:
            node = self.node_map[path]
            node.update_params(path)
        return dict(type='accept-block')

    def w_console(self):  # TODO: check if still used
        return dict(type='accept-console')

    def w_sendcommand(self, command):
        result = None
        for node in self.nodes.values():
            result = node.handle_command(command)
            if result is not None:
                break
        if isinstance(result, str):
            return dict(type='accept-command', result=result)
        return dict(type='accept-command')  # TODO: how to handle result is None?

    def info(self):
        return ["na"]
