#!/usr/bin/env python3

"""
This module is called on behalf of the HTC apps to setup
the congiguration files for any services which the HTC apps need

The config is read from the services table in the readonly database:
CREATE TABLE [services] (
 [tag] text NOT NULL,
 [active] integer NOT NULL,
 [type] integer NOT NULL,
 [parameters] text,
 [description] text );
"""

import sys
import os
import sqlite3

CONFIG_PATHNAMES="/etc/htc/pathnames.py"
SERVICE_TAGS=("pageserver", "uploader", "powermanager", "netupdate", "nfs", "modem")

def import_file(path):
    """
    Import a file (probably config) from an absolute path
    """
    import importlib.util
    spec = importlib.util.spec_from_file_location("_tmp_cfg", path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)  # type: ignore[attr-defined]
    return module

def load_config_file(service_tag):
    """
    load a config file onto a list for perusal/modification
    returns filename and content
    """  
    content=[]
    filename = "/etc/default/" + service_tag
    try:
        with open(filename, "r") as f:
            content = f.readlines()
    except Exception: 
        pass            
    return filename,content

def save_config_file(filename,content):
    """
    saves a config file
    """  
    with open(filename, "w") as f:
        f.write("\n".join(content))

def find_read_only_database():
    """
    Look in various places for the read-only database
    """
    result = None
    pathnames = import_file(CONFIG_PATHNAMES)
    if os.path.isfile(pathnames.CONFIG_PATH_DB_READONLY):
        result = pathnames.CONFIG_PATH_DB_READONLY
    else:
        print("Can't find:" + pathnames.CONFIG_PATH_DB_READONLY)
    return result

def get_service_tag_keyword(service_tag):
    """
    return service tag keyword given a service atg
    """
    return "RUN_" + service_tag.upper()

def find_service_tag_in_content(file_content, service_tag):
    """
    find the index of a service tag in the content 
    if it's not found return None
    """
    result = None
    keyword = get_service_tag_keyword(service_tag)
    indices = [i for i,s in enumerate(file_content) if (s.upper().startswith(keyword))]
    if indices:
        result = indices[0]
    return result

def get_service_status_from_db(db_connection, service_tag):
    """
    get the required status of a service from the read-only database
    if the service is not found in the services table assume it's not required
    return active as boolean
    """
    result = False
    query = "SELECT active,description FROM services WHERE tag == '{0}';"
    fmt = "Service:{0} ({1}): Required:{2}" 
    try:
        cx = db_connection.cursor()
        cx.execute(query.format(service_tag))
        qr = cx.fetchone()
        if qr:
            print(fmt.format(service_tag, qr[1], qr[0]))
            result = bool(qr[0])
    except Exception: 
        pass            
    return result

def get_service_status_from_config(file_content, service_tag):
    """
    get the required status of a service from the config file content
    return active as boolean
    """
    result = False
    if file_content:
        try:
            ix = find_service_tag_in_content(file_content, service_tag)
            value = file_content[ix].split("=")[1].strip().upper()
            result = value == "TRUE"
        except Exception: 
            pass            
    return result

def set_service_status_to_config(file_content, service_tag, service_enabled):
    """
    set the required status of a service in the config file content
    """
    keyword = get_service_tag_keyword(service_tag)
    output = keyword + "=" + str(service_enabled).lower()
    ix = find_service_tag_in_content(file_content, service_tag)
    if ix is None:
        file_content.append(output)        
    else:
        file_content[ix] = output

def check_service_enabled(service_tag, db_connection):
    """
    check whether a service is enabled and enable if if necessary
    """
    print("Checking service:" + service_tag)
    config_filename, config_contents = load_config_file(service_tag)
    enabled_now = get_service_status_from_config(config_contents, service_tag)
    enabled_requested = get_service_status_from_db(db_connection, service_tag)
    if (enabled_now != enabled_requested):
        set_service_status_to_config(config_contents, service_tag, enabled_requested)
        save_config_file(config_filename, config_contents)

def main():
    """
    Main entry point.
    """
    read_only_database_filename = find_read_only_database()
    if not read_only_database_filename:
        return
    db_connection = sqlite3.connect(read_only_database_filename)
        
    for service_tag in SERVICE_TAGS:
        check_service_enabled(service_tag, db_connection)

if __name__ == "__main__":
    main()
