#!/usr/bin/env python

import aptdaemon.client as client
import aptdaemon.errors as errors
from SystemUpdater.Core.errors import *
from SystemUpdater.Core.enums import *
from aptdaemon.enums import (
                            EXIT_SUCCESS,
                            EXIT_FAILED,
                            EXIT_CANCELLED,
                            STATUS_FINISHED
                            )

from defer import inline_callbacks
import logging
from gettext import gettext as _
import dbus
import traceback


class InstallBackendAptdaemon():
    """Makes use of aptdaemon to refresh the cache and to install updates."""

    def __init__(self, window_main):
        self.window_main = window_main

        self.client = client.AptClient()

    @inline_callbacks
    def update(self):
        """刷新包cache"""
        try:
            trans = yield self.client.update_cache(defer=True)
            # 注册回调函数 接收更新的状态
            yield self._show_transaction(trans, self.ACTION_UPDATE)
        except errors.NotAuthorizedError:
            self._action_done(self.ACTION_UPDATE,
                            authorized=False, success=False,
                            error_string='', error_desc='')
        except Exception:
            self._action_done(self.ACTION_UPDATE,
                            is_cancelled=False, success=False,
                            error_string='', error_desc='')
            raise

    @inline_callbacks
    def commit(self,action,pkgs_install, pkgs_upgrade, pkgs_remove,pkgs_downgrade = []):
        """Commit a list of package adds and removes"""
        try:
            reinstall = purge = []
            trans = yield self.client.commit_packages(
                pkgs_install, reinstall, pkgs_remove, purge = purge, upgrade = pkgs_upgrade,
                downgrade = pkgs_downgrade,defer=True)
            self.dbus_send.transaction = trans
            
            yield self._show_transaction(trans, self.action,
                                        _("Installing updates…"), True)
        except errors.NotAuthorizedError:
            self._action_done(action,
                            authorized=False, success=False,
                            error_string='', error_desc='')
        except errors.TransactionFailed as e:
            logging.error(str(e))
        except dbus.DBusException as e:
            if e.get_dbus_name() != "org.freedesktop.DBus.Error.NoReply":
                raise
            self._action_done(action,
                            authorized=False, success=False,
                            error_string='', error_desc='')
        except Exception:
            self._action_done(action,
                            is_cancelled=False, success=False,
                            error_string='', error_desc='')
            raise

    #进度回调
    def _on_progress_changed(self, trans,progress,action):
        #不要101这种未知状态
        if progress == 101:
            return

    #同步状态回调
    def _on_status_changed(self, trans, status,action):
        if action == self.ACTION_UPDATE and status == STATUS_FINISHED:
            return

    def _on_details_changed(self, trans, details,action):
        self.aptd_base.details = details
        self._dist_status_changed(action)


    def _on_cancellable_changed(self, trans, Cancelable,action):
        #下面的这些 不发送取消信号
        if action == self.ACTION_REMOVE_PACKAGES:
            return

        if action != self.ACTION_UPDATE:
            logging.info("\033[1;32m" + "Emitting" + "\033[0m" +" Cancelable: %r",Cancelable) 
        self.dbus_send.Cancelable(Cancelable)
        self.aptd_base.cancelable = Cancelable

    def _on_config_file_conflict(self, transaction, old, new):
        logging.info("Config file conflict oldconf = %s , newconf = %s...",str(old),str(new))
        logging.info("Default To Replace Old Configfile...")

        transaction.resolve_config_file_conflict(old, "keep")

    #增加记录当产生错误的时候 详细信息 
    def _on_error_changed(self, trans,error_code, error_details):
        self.aptd_base.error_details = str(error_details)
        logging.error(str(error_details))

    @inline_callbacks
    def _show_transaction(self, trans, action):
        trans.connect("finished", self._on_finished, action)
        trans.connect("status-changed", self._on_status_changed,action)
        trans.connect("progress-changed", self._on_progress_changed,action)
        #取消升级
        trans.connect("cancellable-changed", self._on_cancellable_changed,action)
        #下载的进度信息
        trans.connect("progress-details-changed", self._on_progress_download_changed,action)
        trans.connect("status-details-changed", self._on_details_changed,action)
        trans.connect("error", self._on_error_changed)

        trans.connect("config-file-conflict", self._on_config_file_conflict)

        yield trans.run()

    def _on_finished(self, trans, status, action):
        try:
            error_string = ''
            error_desc = ''
            error_code = ''
            is_success = (status == EXIT_SUCCESS)
            
            if status == EXIT_FAILED:
                error_code = trans.error.code
                error_string = get_other_error_string_from_enum(error_code)
                error_desc = get_other_error_description_from_enum(error_code)
            elif status == EXIT_CANCELLED:
                error_code = EXIT_CANCELLED
                error_string = get_error_string_from_enum(error_code)
                error_desc = get_error_description_from_enum(error_code)
            elif status == EXIT_SUCCESS and action == self.ACTION_REMOVE_PACKAGES:
                error_string = _("Uninstallation completed")

            self._action_done(action,
                            is_cancelled=(status == EXIT_CANCELLED), success=is_success,
                            error_string=error_string, error_desc=error_desc,error_code=error_code)
        except Exception as e:
            logging.error(e)
            traceback.print_exc()

