#!/usr/bin/python3

from gi.repository import GLib
from pydbus import SystemBus
import isodumper.raw_write as raw_write
import threading
import gettext
import logging
import time

DEAMON_ORG = 'org.mageia.Magiback'
DEAMON_INTERFACE = DEAMON_ORG
ISODUMPER_INTERFACE = DEAMON_ORG + ".Isodumper"
# Keep the authorization during KEEPER (in seconds)
KEEPER = 3600
auth = False
last_auth = 0

logging.basicConfig(filename="/var/log/magiback.log",
                    format='%(asctime)s %(levelname)-8s %(message)s',
                    level=logging.DEBUG)

class Isodumper(raw_write.Dumper):
    """
		<node>
			<interface name='org.mageia.Magiback.Isodumper'>
				<method name='do_write'>
					<arg type='s' name='source' direction='in'/>
					<arg type='s' name='target' direction='in'/>
					<arg type='x' name='size' direction='in'/>
				</method>
				<method name='do_format'>
					<arg type='s' name='target' direction='in'/>
					<arg type='s' name='label' direction='in'/>
					<arg type='s' name='key' direction='in'/>
					<arg type='s' name='fs_type' direction='in'/>
					<arg type='s' name='order' direction='in'/>
				</method>
				<method name='check_write'>
					<arg type='s' name='target' direction='in'/>
					<arg type='s' name='source' direction='in'/>
				</method>
				<method name='do_persistence'>
					<arg type='s' name='target' direction='in'/>
					<arg type='s' name='label' direction='in'/>
					<arg type='s' name='key' direction='in'/>
					<arg type='s' name='fs_type' direction='in'/>
				</method>
				<method name='set_backup_mode'>
					<arg type='x' name='uid' direction='in'/>
					<arg type='x' name='gid' direction='in'/>
				</method>
				<method name='unset_backup_mode'>
				</method>
				<method name='end'>
					<arg type='b' name='success' direction='out'/>
					<arg type='s' name='message' direction='out'/>
				</method>
				<method name='close'>
				</method>
                <property name="done" type="b" access="read"/>
                <property name="progress" type="i" access="read"/>
                <property name="message" type="s" access="read"/>
                <property name="state" type="b" access="read"/>
			</interface>
		</node>
    """
    def __init__(self):
        super().__init__()
        APP = "isodumper"
        DIR = "/usr/share/locale"
        # Call translation catalog
        gettext.install(APP, localedir=DIR,)
        self.finished = threading.Event()
        # finished is cleared at start of operation, and set at the end
        self.finished.clear()
        self._progress = 0
        self.loop = GLib.MainLoop()
        self.return_state = False
        self.return_message = ""
        self.authorized_sender_read = set()
        self.authorized_sender_write = set()
        self.sum_check = ""
        self.sum_check_searched = False
        self.signature_checked = False
        self.writing_perm = False
        self.writing_target = ""
        self.backup_mode = False
        self.uid = 0
        self.gid = 0
        self.last_auth = time.perf_counter()

    def do_write(self, source, target, size, dbus_context):
        self.finished.clear()
        if check_permission('org.mageia.Magiback.Isodumper.write', dbus_context):
            self.thread = threading.Thread(target=self._do_write, args=(source, target, size, self.backup_mode, self.uid, self.gid))
            self.thread.start()
            logging.info("Writing thread started")
            self.writing_perm = True
            self.writing_target = target
        else:
            self.return_message = "Writing: Access denied"
            self.return_state = False
            logging.debug(self.return_message)
            self.finished.set()

    def do_format(self, target, label, key, fs_type, order, dbus_context):
        self.finished.clear()
        if (self.writing_perm and self.writing_target == target) or check_permission('org.mageia.Magiback.Isodumper.write', dbus_context):
            self.thread = threading.Thread(target=self._do_format, args=(target, label, key, fs_type, order.encode("utf-8")))
            self.thread.start()
            logging.info("Partitioning thread started")
        else:
            self.return_message = "Partitioning: Access denied"
            self.return_state = False
            logging.info(self.return_message)
            self.finished.set()
        self.writing_target = ""

    @property
    def done(self):
        return self.finished.wait(1)

    @property
    def message(self):
        return self.return_message

    @property
    def state(self):
        return self.return_state

    def end(self):
        if hasattr(self, 'thread'):
            self.thread.join()
        self._progress = 0
        self.finished.clear()
        return self.return_state, self.return_message

    def close(self):
        logging.info("Closing")
        # Close the loop from the main function
        loop.quit()

    @property
    def progress(self):
        return self._progress

    def check_write(self, target, source):
        if hasattr(self, 'key_thread'):
            self.key_thread.join()
        self.thread = threading.Thread(target=self._check_write, args=(target, source,))
        self.thread.start()

    def set_backup_mode(self, uid, gid):
        logging.info("Set in backup mode")
        self.backup_mode = True
        self.uid = uid
        self.gid = gid

    def unset_backup_mode(self):
        logging.info("Unset the backup mode")
        self.backup_mode = False
        self.uid = 0
        self.gid = 0

    def run(self):
        self.loop.run()


def check_permission(action, dbus_context):
    """ Check permission
    """
    global auth
    global last_auth
    cur = time.perf_counter()
    if cur - last_auth > KEEPER or not auth:
        auth = dbus_context.is_authorized(action, {'polkit.icon_name': 'isodumper.png', }, interactive=True)
        if auth:
            last_auth = cur
        return auth
    else:
        return True


class ConfFile(object):
    """
		<node>
			<interface name='org.mageia.Magiback'>
				<method name='setName'>
					<arg type='s' name='a' direction='in'/>
				</method>
				<method name='getFile'>
					<arg type='s' name='content' direction='out'/>
				</method>
				<method name='saveFile'>
					<arg type='s' name='content' direction='in'/>
				</method>
			</interface>
		</node>
    """
    def __init__(self):
        super().__init__()

    def setName(self, file_name):
        self.file_name = file_name

    def getFile(self):
        with open(self.file_name, 'r') as tcf:
            # read the file
            content=""
            while 1:
                line = tcf.readline()
                if not line:
                    break
                content += line
        return content

    def saveFile(self, tc, dbus_context):
        if check_permission('org.mageia.Magiback.write', dbus_context):
            try:
                with open(self.file_name, 'w') as tcf:
                    tcf.write(tc)
            except:
                return False
            return True


class Logging(object):
    """
		<node>
			<interface name='org.mageia.Magiback.Logging'>
				<method name='debug'>
					<arg type='s' name='message' direction='in'/>
				</method>
				<method name='info'>
					<arg type='s' name='message' direction='in'/>
				</method>
				<method name='warning'>
					<arg type='s' name='message' direction='in'/>
				</method>
				<method name='error'>
					<arg type='s' name='message' direction='in'/>
				</method>
			</interface>
		</node>
    """
    def __init__(self):
        super().__init__()

    def debug(self, message):
        logging.debug(message)

    def info(self, message):
        logging.info(message)

    def warning(self, message):
        logging.warning(message)

    def error(self, message):
        logging.error(message)

if __name__ == '__main__':
    print("Running Magiback service.")
    bus = SystemBus()
    conf_file = ConfFile()
    log = Logging()
    bus.publish(DEAMON_ORG, conf_file, ("Isodumper", Isodumper()), ('Logging', Logging()))
    loop = GLib.MainLoop()
    loop.run()
    logging.shutdown()
