"""

Siehe auch: Steamrock Digital Barometer

Meßwert alls 15 Minuten: 
  Es wird in hPa gemessen mit einer Nachkommastelle
  84 Stunden * 4 Werte je Stunde = 336 Meßwerte
Tendenzwert über 3 Stunden

Je Zoomstufe wird ein eigener Buffer vorgehalten um ein sauberes
Diagramm zu erhalten. Überall gilt: Je Pixel ein Meßwert.

Drucktendenz:
  - 1 hour tendency
  - 3 hour tendency

Verschiedene Datenquellen auswählbar:
- intern (BME280, BMP280)
- N2K generisch
- Historie von 
    - Yacht devices
    - Capteurs?

Das Diagramm wird mit Ursprung rechts unten (x0, y0) gezeichnet,
da die Werte in der Vergangenhait liegen, also links vom Ursprung.

Damit eine saubere Skala auf der Y-Achse erreicht wird, gibt einige
feste Skalierungen.
Standard: 20hPa von unten nach oben, z.B. 1015, 1020, 1025, 1030, 1035

TODO 
  - wenn keine Luftdruckdaten vorliegen, dann eine entsprechende
    Meldung anzeigen

"""

import time
import cairo
from .page import Page

class Barograph(Page):

    def __init__(self, pageno, cfg, appdata, boatdata):
        super().__init__(pageno, cfg, appdata, boatdata)
        # Meßwert alle 15 Minuten: 
        # 84 Stunden * 4 Werte je Stunde = 336 Meßwerte
        self.bd = boatdata
        if not cfg['bme280']:
            self.source = None # keine Datenquelle!
        else:
            self.source = 'I' # (I)ntern, e(X)tern, None=Disabled
        self.zoom = (1, 2, 3, 6, 12)
        self.zoomindex = 4
        self.series = (75, 150, 300, 600, 900)

        # Y-Axis
        self.vmin = 0
        self.vmax = 0
        self.scalemin = 1000
        self.scalemax = 1020
        self.scalestep = 5

        # Tendenzwert über 3 Stunden
        self.hist3 = None
        self.hist1 = None

        self.buttonlabel[1] = '+'
        self.buttonlabel[2] = '-'
        self.buttonlabel[5] = 'SRC'

        self.data = None
        self.refresh = time.time() - 30

    def handle_key(self, buttonid):
        # TODO Serie auswählen aufgrund Zoomlevel
        if buttonid == 1:
            # Zoom in
            if self.zoomindex > 0:
                self.zoomindex -= 1
            self.refresh = time.time() - 30
        elif buttonid == 2:
            # Zoom out
            if self.zoomindex <  len(self.zoom) - 1:
                self.zoomindex += 1
            self.refresh = time.time() - 30
        if buttonid == 5:
            # Source
            if self.source == 'I':
                self.source = 'X'
            else:
                self.source = 'I'

            # Testausgabe der Datenerfassung
            data = []
            vmin = 9999
            vmax = 0
            i = self.series[self.zoomindex]
            for value in self.bd.history['press'].series[i].get():
                v = value / 10
                data.append(v)
                if v < vmin and v != 0:
                    vmin = v
                elif v > vmax and v != 0:
                    vmax = v
            print(f"Werte: vmin={vmin}, vmax={vmax}")
            ymin, ymax, step = self.getYScale(vmin, vmax)
            print(f"Skala: ymin={ymin}, ymax={ymax}, step={step}")
            print(f"zoomindex={self.zoomindex}, series={self.series[self.zoomindex]}")

            hist1a = self.bd.history['press'].series[i].getvalue(3600)
            hist1b = self.bd.history['press'].series[i].getvalue3(3600)
            trend1 = data[0] - hist1b
            print(f"{hist1a} / {hist1b} -> Trend1: {trend1:.1f}")

    def loadData(self):
        """
        Transfer data from history to page buffer
        set y-axis according to data
        """
        if self.source == None:
            # TODO hier muß noch Arbeit reingesteckt werden!
            return False
        self.data = []
        self.vmin = 9999
        self.vmax = 0
        i = self.series[self.zoomindex]
        for value in self.bd.history['press'].series[i].get():
            v = value / 10
            self.data.append(v)
            if v < self.vmin and v != 0:
                self.vmin = v
            elif v > self.vmax and v != 0:
                self.vmax = v
        self.scalemin, self.scalemax, self.scalestep = self.getYScale(self.vmin, self.vmax)
        return True

    def drawTrend(self, ctx, code, x, y, w):
        """
        One hour Trend
        0: Stationary            <= 1 hPa
        1: Rising                >1 and <= 2 hPa
        2: Rising fast           >2 and <= 3 hPa
        3: Rising very fast      >3 hPa
        -1: Falling
        -2: Falling fast
        -3: Falling very fast       
        """
        trend1map = {
            -3: "Falling_Very_Fast.png",    # > 3 hPa
            -2: "Falling_Fast.png",         # > 2 and <= 3 hPa
            -1: "Falling.png",              # > 1 and <= 2 hPa
             0: "Stationary.png",           # <= +/- 1 hPa
             1: "Rising.png",               # < -1 and >= -2 hPa
             2: "Rising_Fast.png",          # < -2 and >= -3 hPa
             3: "Rising_Very_Fast.png"      # < -3 hPa
        }

        if code == 0:
            # Pfeil horizontal rechts
            ctx.move_to(x, y - w / 2)
            ctx.line_to(x + w, y - w / 2)
            ctx.draw()
            # Position merken
            ctx.line_to(x - w / 4, y - w)
            ctx.line_to(x - w / 4, y)
            ctx.line_to(x + w, y - w / 2)
            ctx.fill()
        elif code == 1:
            # Pfeil schräg nach oben
            pass
        elif code == 2:
            # Pfeil gerade nach oben
            pass
        elif code == 3:
            # Doppelpfeil nach oben
            pass
        elif code == -1:
            # Pfeil schräg nach unten
            pass
        elif code == -2:
            # Pfeil gerade nach unten
            pass
        elif code == -3:
            # Doppelpfeil nach unten
            pass

    def drawWMOCode(self, ctx, code, x, y, w):
       """
       Three hour code
       Code 0 to 8:
           0: Increasing, then decreasing; athmospheric pressure the same 
              as or higher than three hours ago
           1: Increasing then steady; or increasing, then increasing more 
              slowly; athmospheric pressure now higher than three hours ago
           2: Increasing (steadily or unsteadily); athmospheric pressure
              now higher than three hours ago
           3: Decreasing or steady, then increasing; or increasing then 
              increasing more rapidly; athmospheric pressure now higher
              than three hours ago
           4: Steady; athmospheric pressure is the same as three hours ago
           5: Decreasing, then increasing; athmospheric pressure now is the 
              same as or lower than three hours ago
           6: 
           7:
           8:
       """
       pass

    def getYScale(self, vmin, vmax):
        # Y-Achse aufgrund Meßwerten einstellen
        diff = vmax - vmin
        if diff < 20:
            step = 5
        elif diff <= 40:
            step = 10
        else:
            step = 15
        vmin = int(vmin - (vmin % step))        # Nächstes Vielfaches nach oben
        vmax = int(vmax + step - (vmax % step)) # Nächstes Vielfaches nach unten 
        return (vmin, vmax, step)

    def draw(self, ctx):
        """
        Darstellung angelehnt an klassisches Gerät
        Daten werden im nichtflüchtigen Speicher gehalten
        Da sich die Daten langsam verändern, reicht es, diese z.B. nur alle
        30 Sekunden oder langsamer zu laden.
        Der aktuelle Wert oben ist natürlich nicht alt.

        Datenreihen 
        - 1 Woche, stündlich: 7 * 24 = 168 Meßwerte
        - 1 Tag, alle 10 min: 24 * 6 = 144 Meßwerte
        Der Druck wird in zwei Bytes abgespeichert. Es wird eine Nachkommastelle
        verwendet. Um ohne Fließkommazahlen auszukommen wird der Maßwert einfach
        mit 10 multipliziert.

        Darstellung wie Steamrock:
        1 Pixel entspricht einem Meßwert alle 15min.
        1 Tag hat dementsprechend eine Breite von 48px
        """

        timestamp = time.time()
        if timestamp - self.refresh >= 30:
            self.refresh = timestamp
            self.loadData()

        ctx.set_source_rgb(0, 0, 0)
        ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)

        # Datenquelle rechts oben
        ctx.set_font_size(16)
        ctx.move_to(330, 50)
        if self.source == 'I':
            ctx.show_text("BMP280")
        else:
            ctx.show_text("N2K Bus")
        ctx.stroke()
        # Zoomstufe
        datastep = self.series[self.zoomindex]
        if datastep > 120:
            if datastep % 60 == 0:
                fmt = "{:.0f} min"
            else:
                fmt = "{:.1f} min"
            datastep /= 60
        else:
            fmt = '{} s'
        self.draw_text_center(ctx, 360, 62, fmt.format(datastep))

        # Aktueller Luftdruck hPa
        ctx.set_font_size(32)
        self.draw_text_center(ctx, 200, 40, self.bd.pressure.format())
        #self.draw_text_center(ctx, 200, 40, "1019.2")
        ctx.set_font_size(16) 
        self.draw_text_center(ctx, 200, 62, "hPa")

        # Trend
        ctx.set_font_size(16)
        # TODO Trend linie
        #trend = 
        self.draw_text_center(ctx, 295, 62, "0.0")

        # min/max
        ctx.move_to(10, 38)
        ctx.show_text(f"min: {self.vmin}")
        ctx.move_to(10, 50)
        ctx.show_text(f"max: {self.vmax}")

        # Alarm
        self.draw_text_center(ctx, 70, 62, "Alarm Off")

        # Hintergrundrahmen
        ctx.set_line_width(2)

        ctx.move_to(0, 75)
        ctx.line_to(400, 75)

        ctx.move_to(130, 20)
        ctx.line_to(130, 75)

        ctx.move_to(270, 20)
        ctx.line_to(270, 75)

        ctx.move_to(325, 20)
        ctx.line_to(325, 75)

        ctx.stroke()


        # Diagramm
        # --------
        ymin = self.scalemin
        ymax = self.scalemax
        yn = self.scalestep
        ystep = (ymax - ymin) / yn

        xstep = 48

        # Ursprung ist rechts unten
        x0 = 350
        y0 = 270
        w = 7 * 48
        h = 180

        ctx.set_line_width(1)
        ctx.rectangle(x0 - w + 0.5, y0 - h + 0.5, w, h)
        ctx.stroke()

        # X-Achse sind Stunden
        xn = 0
        for xt in [x * -1 * self.zoom[self.zoomindex] for x in range(1,7)]:
            xn += 1
            ctx.move_to(x0 - xn * xstep + 0.5, y0)
            ctx.line_to(x0 - xn * xstep + 0.5, y0 - h)
            ctx.stroke()
            self.draw_text_center(ctx, x0 - xn * xstep + 0.5, y0 - 8, str(xt), fill=True)
        ctx.stroke()
        #for x in (1, 2, 3, 4, 5, 6):
        #    ctx.move_to(x0 - x * 48 + 0.5, y0 + 0.5)
        #    ctx.line_to(x0 - x * 48 + 0.5, y0 - h + 0.5)
        #ctx.stroke()

        # Y-Achse
        ctx.move_to(x0 + 5.5, y0 + 0.5)
        ctx.line_to(x0 + 5.5, y0 - h)
        ctx.move_to(x0 - w - 5.5, y0 + 0.5)
        ctx.line_to(x0 - w - 5.5, y0 -h )
        ctx.stroke()

        dy = 9 # Pixel je hPa
        ysmin = self.scalemin
        ysmax = self.scalemax

        y = y0 + 0.5
        ystep = self.scalestep
        ys = ysmin
        while y >= y0 - h:
            if ys % ystep == 0:
                ctx.move_to(x0 + 10, y + 5.5)
                ctx.show_text(str(ys))
                ctx.move_to(x0 - w - 5, y)
                ctx.line_to(x0 + 5, y)
            else:
                ctx.move_to(x0, y)
                ctx.line_to(x0 + 5, y)
                ctx.move_to(x0 - w - 5, y)
                ctx.line_to(x0 - w, y)
            y -= dy
            ys += 1
        ctx.stroke()

        # Meßdaten
        if self.data:
            for v in self.data:
                x0 -= 1
                if v > 0:
                    ctx.rectangle(x0, y0 - (v - ysmin) * dy, 1.5, 1.5)
            ctx.fill()
        else:
            # Keine Daten vorhanden!
            # TODO iregndwas nettes anzeigen
            pass
