#!/usr/bin/env python3

import curses 
import threading

from .globals import CURSES_LOCK

class Pager:
    def set_dim(self, height, width):
        if height < 4 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._regen_actual()
            self._redraw()
        
    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()

    def _redraw(self):
        with self._lock, CURSES_LOCK:
            start = max(0, self._bottom_a - self._height + 2)
            end = self._bottom_a
            todisp = self._actual[start:end]
            if len(todisp) < self._height-2 and len(todisp) < len(self._actual):
                end = self._bottom_a+self._height-2-len(todisp)
                todisp += self._actual[self._bottom_a:end]
            self.win.erase()
            self.win.border()
            if start > 0:
                self.win.addch(0, self._width//2, '⯅')
            for n, l in enumerate(todisp, 1):
                self.win.addstr(n, 1, l)
            if end < len(self._actual):
                self.win.addch(self._height-1, self._width//2, '⯆')
            self.win.refresh()

    def _split_line(self, l):
        with self._lock:
            lines = []
            
            while len(l) >= self._width-2:
                lines.append(l[:self._width-3] + '…')
                l = "⮡ "+l[self._width-3:]
            lines.append(l)

            return lines
                
    def _regen_actual(self):
        with self._lock:
            self._actual = []
            for n, l in enumerate(self._lines):
                self._actual += self._split_line(l)
                if n == self._bottom:
                    self._bottom_a = len(self._actual)
            self._bottom_a = max(self._bottom_a, self._height-2)

    def display_many(self, s, split=False):
        with self._lock:
            if split:
                self._lines.append("")
                self._actual.append("")
            for l in s:
                self._lines.append(l)
                self._actual += self._split_line(l)
            self._bottom = len(self._lines) - 1
            self._bottom_a = len(self._actual)
            self._redraw()

    def display(self, s):
        self.display_many((s, ))

    def user_page(self, refresh=None):
        curses.curs_set(0)
        
        while True:
            l = self.win.getch()

            with self._lock:
                if l == curses.KEY_RESIZE:
                    if refresh is not None:
                        refresh()
                elif l == ord('q'):
                    break
                elif l in (ord('k'), curses.KEY_UP):
                    if self._bottom_a > self._height-2:
                        self._bottom_a -= 1
                        self._redraw()
                elif l in (ord('j'), curses.KEY_DOWN):
                    if self._bottom_a < len(self._actual):
                        self._bottom_a += 1
                        self._redraw()
                elif l == curses.KEY_NPAGE:
                    if self._bottom_a < len(self._actual):
                        self._bottom_a = min(len(self._actual), self._bottom_a + self._height - 2)
                        self._redraw()
                elif l == curses.KEY_PPAGE:
                    if self._bottom_a > 0:
                        self._bottom_a = max(self._height - 2, self._bottom_a - self._height + 2)
                        self._redraw()
                elif l == curses.KEY_HOME:
                    if self._bottom_a > self._height - 2:
                        self._bottom_a = self._height - 2
                        self._redraw()
                elif l == curses.KEY_END:
                    if self._bottom_a < len(self._actual):
                        self._bottom_a = len(self._actual)
                        self._redraw()

        curses.curs_set(1)

    def clear(self):
        with self._lock:
            self._lines = []
            self._actual = []
            self._bottom_a = 0
            self._bottom = -1
            self._redraw()

    def __init__(self, y, x, height, width):
        with CURSES_LOCK:
            self.win = curses.newwin(height, width, y, x)
            self.win.keypad(True)
        self._lock = threading.RLock()
        self._height = height
        self._width = width
        self._y = -1
        self._x = -1
        self._lines = []
        self._actual = []
        self._bottom = -1
        self._bottom_a = 0

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