"""
DWD NAVTEX 

Funkmodul (radio) noch nicht implementiert mangels Hardware

B1: Transmitter identity

B2: Subject indicator character

    A 	Navigational warnings
    B 	Meteorological warnings
    C 	Ice reports
    D 	Search & rescue information, and pirate warnings
    E 	Meteorological forecasts
    F 	Pilot service messages
    G 	AIS messages (formerly Decca messages[6])
    H 	LORAN messages
    I 	Not used (formerly OMEGA messages[6])
    J 	SATNAV messages (i.e. GPS or GLONASS)
    K 	Other electronic navaid messages
    L 	Navigational warnings — additional to letter A (Should not be rejected by the receiver)
    T 	Test transmissions (UK only — not official)
    V 	Notice to fishermen (U.S. only — currently not used)
    W 	Environmental (U.S. only — currently not used)
    X 	Special services — allocation by IMO NAVTEX Panel
    Y 	Special services — allocation by IMO NAVTEX Panel
    Z 	No message on hand 

B3, B4: Serial number 01-99, 00: immediate printout

Timecode: DDHHmm UTC MMM YY

Sqlite database schema
  .schema message
  msgid TEXT PRIMARY KEY
  timestamp TEXT
  station TEXT
  content TEXT
  received TEXT

"""
import os
import http.client
import ssl
import re
import sqlite3
import datetime
from gi.repository import GLib

class NAVTEX():

    def __init__(self, logger, cfg):
        self.log = logger
        self.source = cfg['ntx_source'].lower() # net | radio
        self.maxage = cfg['ntx_housekeeping'] # message hold time in hours
        self.running = False
        dbpath = os.path.join(cfg['histpath'], "navtex.db")
        try:
            self.conn = sqlite3.connect(dbpath)
            self.cur = self.conn.cursor()
        except:
            self.log.error(f"Failed to open local database: {dbpath}")
            return
        # Datenbank erstellen wenn nicht vorhanden
        sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='message'"
        self.cur.execute(sql)
        if self.cur.fetchone() == None:
            sql = ("CREATE TABLE IF NOT EXISTS message ("
                   "msgid TEXT PRIMARY KEY NOT NULL,"
                   "station TEXT,"
                   "timestamp TEXT,"
                   "content TEXT NOT NULL,"
                   "received TEXT NOT NULL DEFAULT current_timestamp)"
                  )
            self.cur.execute(sql)
            self.log.info(f"Created NAVTEX database: {dbpath}")
        # Aktualisieren bei Programmstart
        # TODO Ausgeschaltet für Programmentwicklung
        if self.source == 'net':
            self.refresh()
        # In der Konfiguration werden Minuten angegeben
        GLib.timeout_add_seconds(cfg['ntx_refresh'] * 60, self.on_timer)
        self.running = True

    def __del__(self):
        self.conn.close()

    def on_timer(self):
        """
        NAVTEX data handling
        """
        self.refresh()
        self.housekeeping()
        return True

    def parse_message(self, plainmsg):
        """
        Zeile 1: ZCZC<space><BBBB>
        Zeile 2: Stationskennung
        Zeile 3: Zeitstempel (meistens)
        Zeile 4 bis n-1: Nachrichteninhalt
        Zeile n: NNNN

        Je nach Code B1, B2 kann das folgende Format unterschiedlich sein
        """
        msg = {}
        data = plainmsg.splitlines()
        msg['id'] = data[0][5:9]
        msg['station'] = data[1].strip()
        timestamp = data[2]
        if len(timestamp) == 17:
            day = int(timestamp[0:2])
            hour = int(timestamp[2:4])
            minute = int(timestamp[4:6])
            monmap = ('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC')
            month = monmap.index(timestamp[11:14]) + 1
            year = 2000 + int(timestamp[15:17])
            try:
                msg['timestamp'] = datetime.datetime(year, month, day, hour, minute, 0)
            except:
                msg['timestamp'] = None
        else:
            msg['timestamp'] = None
        return msg

    def dwd_get_data(self, local=False):
        """
        net: Webseite auslesen
        https://www.dwd.de/DE/fachnutzer/schifffahrt/funkausstrahlung/navtex
        """
        if local:
            # Für Tests um nicht permanent die Webseite abzufragen
            with open("490_emd.html", "r") as fh:
                content = fh.read()
        else:
            ssl_context = ssl.create_default_context()
            conn = http.client.HTTPSConnection("www.dwd.de", 443, context=ssl_context)
            url = "https://www.dwd.de/DE/fachnutzer/schifffahrt/funkausstrahlung/navtex/490_emd.html"

            try:
                conn.request("GET", url)
                response = conn.getresponse()
                if response.status == 200:
                    content = response.read().decode()
                else:
                    print(f"Error: {response.status}")
                    return []
            except http.client.HTTPException as e:
                self.log.warning(f"HTTP error occurred: {e}")
                return []
            except ssl.SSLError as ssl_error:
                self.log.warning(f"SSL error occurred: {ssl_error}")
                return []

        expr = re.compile("(ZCZC.*?NNNN)", re.DOTALL)
        matches = re.findall(expr, content)

        return matches

    def refresh(self):
        self.log.info("NAVTEX refresh")
        messages = self.dwd_get_data(False)
        sql = "INSERT INTO message (msgid, station, content) VALUES (?, ?, ?)"
        for m in messages:
            msg = self.parse_message(m)
            self.cur.execute("SELECT COUNT(*) FROM message WHERE msgid=?", (msg['id'],))
            result = self.cur.fetchone()
            if result[0] == 0:
                self.log.debug(f"NAVTEX: insert new message '{msg['id']}'")
                self.cur.execute(sql, (msg['id'], msg['station'], m))
                self.conn.commit()

    def housekeeping(self):
        self.log.info("NAVTEX housekeeping")
        sql = "DELETE FROM message WHERE (julianday('now') - julianday(received)) * 24 > ?"
        self.cur.execute(sql, (self.maxage, ))

    def get_count(self):
        sql = "SELECT COUNT(*) FROM message"
        self.cur.execute(sql)
        result = self.cur.fetchone()
        return result[0]

    def get_ids(self):
        sql = "SELECT msgid FROM message"
        result = self.cur.execute(sql)
        msgids = []
        for row in result.fetchall():
            msgids.append(row[0])
        return msgids

    def get_message(self, msgid):
        sql = "SELECT content FROM message WHERE msgid=?"
        self.cur.execute(sql, (msgid, ))
        result = self.cur.fetchone()
        return result[0]

