#!/usr/bin/python3
import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib

import os, shutil, re
import sqlite3

def __recursive_search__(dictionary, key):
    if key in dictionary:
        return dictionary[key]
    else:
        for value in dictionary.values():
            if isinstance(value, dict):
                result = __recursive_search__(value, key)
                if result is not None:
                    return result
    return None

def __write_element_in_table__(version_data:dict ,data: dict, cursor: sqlite3.Cursor, version_id, parent_id):
        #key写入到数据库
        if 'keys' in data:
            keys = data['keys']
            for key in keys:
                property = key

                user_value = keys[key].get('value')
                # if attr is None:
                #     attr = keys[key].get('default')

                type = keys[key].get('_type')

                default_value = keys[key].get('default')
                if isinstance(default_value, str) is False:
                    default_value = str(default_value)

                description = keys[key].get('description')

                summary = keys[key].get('summary')

                permission = keys[key].get('permission')
                if permission is None:
                    permission = 'public'

                #TODO: 计算range取值范围
                range = keys[key].get('range')
                # reload时，没有更新的枚举数据的range应该是枚举参数的字符串列表
                # 更新后或初始化时的枚举数据的range是@[枚举名]
                if type == 'enum' and isinstance(range, str) and range.startswith('@'):
                    enum_range = {}
                    print(keys[key]['range'])
                    element_list = __recursive_search__(version_data, keys[key]['range'][1:])
                    for element in element_list:
                        enum_range[element['nick']] = int(element['value'])
                    range = str(enum_range)
                    
                cursor.execute('''INSERT INTO configures (version_id, property, user_value, data_type, default_value, permission, range, parent, description, summary) 
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',(version_id, property, user_value, type, default_value, permission, range, parent_id, description, summary))
        if 'children' in data:
            children = data['children']
            for child in children:
                if child.startswith('enum_'):
                    continue
                cursor.execute("INSERT INTO configures (version_id,group_name,parent) VALUES (?, ?, ?)",(version_id, child, parent_id))
                group_id = cursor.lastrowid
                __write_element_in_table__(version_data,children[child],cursor,version_id,group_id)

def __covert_app_table__(data: dict, cursor: sqlite3.Cursor):
    # 创建app表
    cursor.execute('''CREATE TABLE IF NOT EXISTS app
                    (id INTEGER PRIMARY KEY AUTOINCREMENT,
                    app_name TEXT,
                    defualt_version TEXT)''')
    #将app信息写入app表
    for app in data.keys():
        default_version = data[app].get('default_version')
        # 如果没有设置默认版本，将默认版本设置为最大版本
        if default_version is None:
            for version in data[app]:
                if default_version is None:
                    default_version = version
                #比较版本 版本目前认为是2.0.0-0k0格式
                default_list = re.findall(r'\d+', default_version)
                list = re.findall(r'\d+', version)
                for i in range(0,6):
                    if len(default_list) == i:
                        default_version = version
                        break
                    if len(list) == i:
                        break
                    if int(default_list[i]) < int(list[i]):
                        default_version = version
                        break
                    if int(default_list[i]) > int(list[i]):
                        break
        cursor.execute("INSERT INTO app (app_name, defualt_version) VALUES (?,?)",(app, default_version))

def __covert_version_table__(data: dict, cursor: sqlite3.Cursor):
    # 创建version表
    cursor.execute('''CREATE TABLE IF NOT EXISTS version
                    (id INTEGER PRIMARY KEY AUTOINCREMENT,
                    app_id INTEGER,
                    version TEXT,
                    compatible TEXT,
                    FOREIGN KEY (app_id) REFERENCES app(id))''')
    for app in data.keys():
        cursor.execute("SELECT id FROM app WHERE app_name = ?", (app,))
        appId = cursor.fetchone()
        for version in data[app].keys():
            if(version == 'default_version'):
                continue
            cursor.execute("INSERT INTO version (app_id,version, compatible) VALUES (?, ?, ?)",(appId[0],version, data[app][version].get('compatible')))

def __covert_configure_table__(data: dict, cursor: sqlite3.Cursor):
    # 创建version表
    cursor.execute('''CREATE TABLE IF NOT EXISTS configures
                    (id INTEGER PRIMARY KEY AUTOINCREMENT,
                    version_id INTEGER,
                    property TEXT,
                    group_name TEXT,
                    user_value TEXT,
                    data_type TEXT,
                    default_value TEXT,
                    permission TEXT,
                    range TEXT,
                    parent INTEGER,
                    description TEXT,
                    summary TEXT,
                    FOREIGN KEY (version_id) REFERENCES version(id),
                    FOREIGN KEY (parent) REFERENCES configures(id))''')
    cursor.execute("SELECT * FROM app")
    apps = cursor.fetchall()
    for app in apps:
        cursor.execute("SELECT * FROM version WHERE app_id = ?", (app[0],))
        versions = cursor.fetchall()
        for version in versions:
            version_data = data[app[1]][version[2]]
            #keys写入数据库
            __write_element_in_table__(version_data,version_data,cursor,version[0],0)

def __dict2db__(dict, path):
        try:
            # 连接到数据库（如果不存在则创建）
            db_file_path =  path.rsplit('/',maxsplit=1)[0]
            if not os.path.exists(db_file_path):
                os.makedirs(db_file_path)
            conn = sqlite3.connect(path)

            # 创建游标对象
            cursor = conn.cursor()
            conn.execute('BEGIN TRANSACTION')

            # 获取数据库中的所有表名
            cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
            tables = cursor.fetchall()

            # 遍历所有表名，对每个表执行DELETE语句以删除所有行
            for table in tables:
                cursor.execute(f"DELETE FROM {table[0]}")

            __covert_app_table__(dict,cursor)
            __covert_version_table__(dict,cursor)
            __covert_configure_table__(dict,cursor)

            # 提交更改
            conn.commit()
            conn.close()
            return 0
        
        except Exception as e:
            conn.rollback()
            conn.close()
            return -1

#读取一个元素
def __format_element(parent: dict, cursor: sqlite3.Cursor, version_id, parent_id):
    keys = {}
    children = {}
    cursor.execute('SELECT * FROM configures WHERE version_id = ? AND parent = ?', (version_id,parent_id))
    configure_data = cursor.fetchall()
    for configure in configure_data:
        #读取子分组
        if configure[3] is not None:
            children[configure[3]] = {}
            __format_element(children[configure[3]],cursor,version_id,configure[0])
        #读取key
        else:
            keys[configure[2]] = {}
            if configure[4] is not None:
                keys[configure[2]]['value'] = configure[4]
            if configure[5] is not None:
                keys[configure[2]]['_type'] = configure[5]
            if configure[6] is not None:
                keys[configure[2]]['default'] = configure[6]
            if configure[7] is not None:
                keys[configure[2]]['permission'] = configure[7]
            if configure[8] is not None:
                keys[configure[2]]['range'] = configure[8]
            if configure[10] is not None:
                keys[configure[2]]['description'] = configure[10]
            if configure[11] is not None:
                keys[configure[2]]['summary'] = configure[11]
    if keys:
        parent['keys'] = keys
    if children:
        parent['children'] = children            

#将数据库中的内容读取到数据结构中 
#由于存储数组到数据库不会存储 枚举 所以反序列化出来的数据结构中不存在 枚举
def __format_db_file(db_file: str):
    try:
        data = {}
        conn = sqlite3.connect(db_file)
        if conn is None:
            return data
        # 创建游标对象
        cursor = conn.cursor()
        #遍历app表
        conn.execute('BEGIN TRANSACTION')
        cursor.execute('SELECT * FROM app')
        app_data = cursor.fetchall()
        for app in app_data:
            data[app[1]] = {}
            cursor.execute('SELECT * FROM version WHERE app_id = ?', (app[0],))
            version_data = cursor.fetchall()
            for version in version_data:
                data[app[1]][version[2]] = {}
                __format_element(data[app[1]][version[2]],cursor,version[0],0)
        conn.close()
        return data
    except Exception as e:
        conn.rollback()
        conn.close()
        return {}

def __merge_dict(dest:dict , src:dict):
    if src is None:
        return dest
    for key, value in src.items():
        if key in dest and isinstance(dest[key], dict) and isinstance(src[key], dict):
            __merge_dict(dest[key], src[key])
        else:
            if key != 'user_value':
                dest[key] = value
    return dest

def __del_discarded_key(dest:dict, src:dict):
    keys_to_delete = []
    for key in dest:
        if not isinstance(dest[key], dict):
            return
        if key not in src:
            keys_to_delete.append(key)
        else:
            __del_discarded_key(dest[key], src[key])

    for key in keys_to_delete:
        dest.pop(key)

__user_view = {}
__destination_file = '~/.config/kylin-config/user.db'

class KYSettingsDBusSessionService(dbus.service.Object):
    def __init__(self, bus_name, object_path):
        dbus.service.Object.__init__(self, bus_name, object_path)
        self.Init()

    @dbus.service.method("com.kylin.kysdk.conf2")
    def Init(self):
        try:
            source_file = '/etc/kylin-config/user.db'
            destination_file = '~/.config/kylin-config/user.db'
            destination_file = os.path.expanduser(destination_file)
            if os.path.exists(source_file):
                if not os.path.exists(destination_file):
                    os.makedirs(os.path.dirname(destination_file), exist_ok=True)
                    shutil.copyfile(source_file, destination_file)
        except Exception as e:
            print(e)         


def reload_handler(*args, **kwargs):
    data = __format_db_file("/etc/kylin-config/user.db")
    __del_discarded_key(__user_view, data)
    __merge_dict(__user_view, data)
    __dict2db__(__user_view, __destination_file)

if __name__ == "__main__":

    DBusGMainLoop(set_as_default=True)

    try:
        __destination_file = os.path.expanduser(__destination_file)

        bus_session = dbus.SessionBus()
        object_path = '/com/kylin/kysdk/conf2'
        bus_sesssion_name = dbus.service.BusName("com.kylin.kysdk.conf2", bus = bus_session)
        my_dbus_session_service = KYSettingsDBusSessionService(bus_sesssion_name, object_path)

        ##用户登录，更新用户配置
        __user_view = __format_db_file(__destination_file)
        reload_handler(None, None)

        # 连接到DBus系统总线
        bus = dbus.SystemBus()

        # 监听DBus信号
        bus.add_signal_receiver(reload_handler, 
                                signal_name='updated',
                                dbus_interface='com.kylin.kysdk.conf2',
                                bus_name='com.kylin.kysdk.conf2',
                                path="/com/kylin/kysdk/conf2")
    except Exception as e:
        print(e)
    mainloop = GLib.MainLoop()
    mainloop.run()