import curses

from .globals import CURSES_LOCK

_progress = ["    "]
for i in range(8):
    pos = i // 2
    s = _progress[-1]
    _progress.append(s[:pos] + ('\u2588' if i%2 else '\u258c') + s[pos+1:])

def get_progress(v):
    if v == 0:
        return _progress[0]
    elif v <= 36:
        return _progress[1]
    elif v <= 73:
        return _progress[2]
    elif v <= 109:
        return _progress[3]
    elif v <= 145:
        return _progress[4]
    elif v <= 181:
        return _progress[5]
    elif v <= 218:
        return _progress[6]
    elif v <= 254:
        return _progress[7]
    return _progress[8]

class ChannelView:
    width = 9
    height = 3

    def _refresh_channel(self):
        with CURSES_LOCK:
            self.win.addstr(0, 0, "%03d.%03d" % (self.c.f.id, self.c.id), curses.A_UNDERLINE if self._active else 0)
            self.win.refresh()

    def _refresh_value(self):
        with CURSES_LOCK:
            self.win.addstr(1, 0, get_progress(self._value))
            self.win.addstr(1, 4, "%03d" % self._value, (curses.A_ITALIC|curses.A_BOLD if self._held else 0))
            self.win.refresh()

    def refresh(self):
        self._refresh_value()
        self._refresh_channel()

    @property
    def active(self):
        return self._active

    @active.setter
    def active(self, v):
        if v != self._active:
            self._active = v
            self._refresh_channel()

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, v):
        if v != self._value:
            self._value = v
            self._refresh_value()

    @property
    def held(self):
        return self._held

    @held.setter
    def held(self, v):
        if v != self._held:
            self._held = v
            self._refresh_value()

    def set_pos(self, y, x):
        self.y = self.y
        self.x = self.x
        with CURSES_LOCK:
            self.win.refresh()
            self.win.mvwin(y, x)
        self.refresh()

    def __init__(self, root, c, y, x, value=0, held=False, active=False):
        self._active = active
        self._held = held
        self._value = value
        self.c = c
        
        self.y = y
        self.x = x

        self.root = root
        with CURSES_LOCK:
            self.win = root.subpad(self.height, self.width, self.y, self.x)
            self.win.leaveok(True)

        self._refresh_value()
        self._refresh_channel()

class ChannelBank:
    def set_dim(self, height, width):
        if ((height-2)//ChannelView.height) * ((width-4)//ChannelView.width) < len(self.scope):
            raise NotImplementedError("Screen size to small")


        with CURSES_LOCK:
            if (height, width) != (self._height, self._width):
                self.win.erase()
                self.win.refresh()

                self.win.resize(height, width)
                self.win.redrawwin()

            self._height = height
            self._width = width
            self._refresh_scope()
            self._put_title()
            self.win.refresh()

    def _refresh_scope(self):
        with CURSES_LOCK:
            self.win.erase()
            ncv = {}
            cols = (self._width-4)//ChannelView.width
            self._sscope = sorted(self.scope, key=lambda a: (a.f.id, a.id))
            for n, c in enumerate(self._sscope):
                row = (n // cols)*ChannelView.height + 1
                col = (n % cols)*ChannelView.width + 2
                if c in self._cv:
                    active = self._cv[c].active
                    held = self._cv[c].held
                    value = self._cv[c].value
                else:
                    active = False
                    held = False
                    value = 0
                ncv[c] = ChannelView(self.win, c, row, col, value=value, active=active, held=held)
            self._cv = ncv
            self._put_title()
            self.win.refresh()

    def set_pos(self, y, x):
        if (y, x) != (self._y, self._x):
            with CURSES_LOCK:
                self.win.mvwin(y, x)
                self._put_title()
                self.win.refresh()

    def set_active(self, channels, v=True):
        for c in channels:
            self._cv[c].active = v

    def set_held(self, channels, v=True):
        for c in channels:
            self._cv[c].held = v

    def set_values(self, cv):
        if isinstance(cv, dict):
            cv = cv.items()
        for c, v in cv:
            self._cv[c].value = v

    def set_scope(self, scope):
        self.scope = frozenset(scope)
        self._refresh_scope()

    @property
    def title(self):
        return self._title

    def _put_title(self):
        self.win.border()
        pos = min(self._width-2-len(self._title), (3*self._width)//4 - (len(self._title) // 2))
        self.win.addstr(self._height-1, pos, self._title, curses.A_REVERSE if self._highlight else 0)

    @property
    def highlight(self):
        return self._highlight

    @highlight.setter
    def highlight(self, value):
        if value != self._highlight:
            self._highlight = value
            with CURSES_LOCK:
                self._put_title()
                self.win.refresh()

    @title.setter
    def title(self, v):
        if v != self._title:
            with CURSES_LOCK:
                self._title = v
                self.win.border()
                self._put_title()
                self.win.refresh()
            
    def __init__(self, y, x, height, width, scope=frozenset()):
        with CURSES_LOCK:
            self.win = curses.newwin(height, width, y, x)
            self.win.keypad(True)
        self._highlight = False
        self.scope = frozenset(scope)
        self._sscope = []
        self._title = "Channels"
        self._cv = {}
        self._height = height
        self._width = width
        self._y = -1
        self._x = -1
        self.set_pos(y, x)
        self.set_dim(height, width)