#!/usr/bin/python3
import logging
import os
import subprocess
import sys

from gi.repository import Gio # needs to come before gi.overrides.GLib!
from gi.overrides.GLib import Variant


class GSettings():
    def __init__(self, schema_id):
        """
        Wrapper around Gio Settings that deals with running under sudo
        """
        self.schema_id = schema_id
        if os.environ.get('SUDO_USER'):
            self.is_sudo = True
            logging.debug('Running with sudo. Real user: %s', os.environ.get('SUDO_USER'))
        else:
            self.schema = Gio.Settings.new(self.schema_id)
            self.is_sudo = False
            logging.debug('Running as regular user')

    def _convert_variant_to_array(self, variant):
        if variant is None:
            return []

        if variant.get_type_string() == 'as':
            return variant.get_strv()

        assert(variant.get_type_string() == 'a(ss)')

        values = []
        # Process variant of type "a(ss)" (array of tuples with two strings)
        nChildren = variant.n_children()
        for i in range(nChildren):
            # Process variant of type "(ss)" (tuple with two strings)
            val = variant.get_child_value(i)
            typeVariant = val.get_child_value(0)
            type = typeVariant.get_string()
            idVariant = val.get_child_value(1)
            id = idVariant.get_string()
            values.append((type, id))
        return values

    def _convert_array_to_variant(self, array, type):
        if len(array) == 0:
            return Variant(type, None)

        if type == 'as':
            return Variant('as', array)

        assert(type == 'a(ss)')

        children = []
        for (type, id) in array:
            typeVariant = Variant.new_string(type)
            idVariant = Variant.new_string(id)
            child = Variant.new_tuple(typeVariant, idVariant)
            children.append(child)
        return Variant.new_array(None, children)

    def get(self, key):
        if self.is_sudo:
            args = ['sudo', '-H', '-u', os.environ.get('SUDO_USER'),
                    'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%s/bus' % os.environ.get('SUDO_UID'),
                    'gsettings', 'get', self.schema_id, key]
            if sys.version_info.major <= 3 and sys.version_info.minor < 7:
                # capture_output got added in Python 3.7
                try:
                    output = subprocess.check_output(args)
                    value = eval(output)
                except(subprocess.CalledProcessError):
                    value = None
                    logging.warning('Could not convert to sources')
            else:
                process = subprocess.run(args, capture_output=True)
                if process.returncode == 0:
                    value = eval(process.stdout)
                else:
                    value = None
                    logging.warning('Could not convert to sources')
        else:
            variant = self.schema.get_value(key)
            value = self._convert_variant_to_array(variant)
        return value

    def set(self, key, value, type):
        if self.is_sudo:
            variant = str(value)
            subprocess.run(
              ['sudo', '-H', '-u', os.environ.get('SUDO_USER'),
               'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%s/bus' % os.environ.get('SUDO_UID'),
               'gsettings', 'set', self.schema_id, key, variant])
        else:
            variant = self._convert_array_to_variant(value, type)
            self.schema.set_value(key, variant)
