#!/usr/bin/env python3

import curses
import math
import threading 

from blc2.constants import INFTY, MANUAL, JOIN, CHASERSTEP

CURSES_LOCK = threading.RLock()

def format_time(n):
    if n == INFTY:
        return "∞s"
    elif n == 0:
        return "0s"
    postfixes = "mcisahkegtp"
    idx = 0
    multiple = 10
    while n >= multiple:
        idx += 1
        multiple *= 10

    return str(n)[0]+postfixes[idx]

class ChaserView:
    def set_dim(self, height, width):
        if height < 5 or width < 10:
            raise ValueError("Size too small")

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

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

            self._height = height
            self._width = width
            self._redraw()

    @staticmethod
    def fit(s, l, pad=False):
        ## TODO: Try shortening by words first?
        if len(s) > l:
            return s[:l-1] + '…'
        elif len(s) < l and pad:
            return s + ' '*(l-len(s))
        return s
        
    def set_pos(self, y, x):
        with self._lock:
            if (y, x) != (self._y, self._x):
                self.win.mvwin(y, x)
                self._y = y
                self._x = x
                self.win.noutrefresh()

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

    @highlight.setter
    def highlight(self, value):
        with self._lock:
            if self._highlight != value:
                self._highlight = value
                self._redraw()

    def _redraw(self):
        self.win.erase()
        self.win.border()
        self.win.hline(2, 1, curses.ACS_HLINE, self._width-2)
        self.win.addch(2, 0, curses.ACS_LTEE)
        self.win.addch(2, self._width-1, curses.ACS_RTEE)

        if self._chaser is None:
            self.win.refresh()
            return

        c = self._chaser
        w = self._width - 2
        self.win.addstr(1, 1, self.fit(("%d: "% c.id) + c.name + " (%s)" % ("Join" if c.type == JOIN else c.advance_mode), w, True), curses.A_REVERSE if self._highlight else 0)

        maxsteps = self._height - 4
        first = 0
        if maxsteps < len(c.steps):
            if self._selected is None:
                first = 0
                last = maxsteps
            else:
                last = min(self._selected + (maxsteps // 2), len(c.steps))
                first = last - maxsteps
                if first < 0:
                    last -= first
                    first = 0
        else:
            first = 0
            last = len(c.steps)
        steps = c.steps[first:last]
        for n, s in enumerate(steps, 1):
            if first+n-1 == self._selected:
                attrs = curses.A_REVERSE
            else: 
                attrs = 0
            if s.type == CHASERSTEP and s.function is not None:
                ft = s.function.type[0].upper()
                fid = str(s.function.id)
            elif s.type != CHASERSTEP:
                ft = s.type[0].upper()
                fid = str(s.id)
            else:
                ft = "-"
                fid = "---"

            t = "%s%3s%s|%s:%s:%s" % (ft, fid, '*' if (s.type == CHASERSTEP and s.duration_mode == MANUAL) else ' ', format_time(s.fade_in), format_time(s.duration if s.type != CHASERSTEP else s.length), format_time(s.fade_out))
            self.win.addstr(n+2, 1, self.fit((self._numformat % (first+n)) + ": " + s.name, w-len(t), pad=True)+t, attrs)

        if first > 0:
            self.win.addch(2, self._width//2, '⯅')
        if last < len(c.steps):
            self.win.addch(self._height-1, self._width//2, '⯆')
        
        self.win.refresh()

    @property
    def selected(self):
        with self._lock:
            return self._selected

    @selected.setter
    def selected(self, value):
        with self._lock:
            if value != self._selected:
                self._selected = value
                ## TODO: Clean this up if possible?
                self._redraw()

    def set_chaser(self, chaser, selected=None):
        with self._lock:
            self._chaser = chaser
            self._selected = selected
            if chaser is not None and chaser.steps:
                self._numformat = "%%%dd" % math.ceil(math.log10(len(chaser.steps)))
            self._redraw()

    @property
    def chaser(self):
        with self._lock:
            return self._chaser

    def __init__(self, y, x, height, width):
        with CURSES_LOCK:
            self.win = curses.newwin(height, width, y, x)
            self.win.leaveok(True)
            self.win.keypad(True)
        self._lock = threading.RLock()
        self._height = height
        self._width = width
        self._y = -1
        self._x = -1

        self._chaser = None
        self._highlight = False
        self._numformat = ""
        self._selected = -1

        self.set_pos(y, x)
        self.set_dim(height, width)