#!/usr/bin/python
# coding=utf-8
import os
import sys
import signal
import logging
from locale import bind_textdomain_codeset

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

# support running uninstalled
_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if 'BLUEMAN_SOURCE' in os.environ:
    sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path
    os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data")

from blueman.Functions import (
    setup_icon_path,
    set_proc_title,
    check_bluetooth_status,
    create_logger,
    create_parser,
    bmexit
)

from blueman.Constants import UI_PATH
from blueman.gui.DeviceSelectorWidget import DeviceSelectorWidget
from blueman.bluez.Manager import Manager
from blueman.main.DBusProxies import AppletService
from blueman.services.Functions import get_services
from blueman.gui.CommonUi import ErrorDialog

# Workaround introspection bug, gnome bug 622084
signal.signal(signal.SIGINT, signal.SIG_DFL)

PAGE_INTRO = 0
PAGE_DEVLIST = 1
PAGE_PASSKEY = 2
PAGE_PAIRING = 3
PAGE_CONNECT = 4
PAGE_CONNECTING = 5
PAGE_FINISH = 6

pages = {}


class Assistant:
    def __init__(self, parsed_args):
        setup_icon_path()

        check_bluetooth_status(_("Bluetooth needs to be turned on for the Bluetooth assistant to work"), bmexit)

        self.Manager = Manager()
        self.Device = None
        self.Adapter = None
        self.pair = True
        self.service = None

        self.Builder = Gtk.Builder()
        self.Builder.set_translation_domain("blueman")
        bind_textdomain_codeset("blueman", "UTF-8")
        self.Builder.add_from_file(UI_PATH + "/assistant.ui")
        self.assistant = self.Builder.get_object("assistant")
        self.assistant.set_title(_("Bluetooth Assistant"))
        self.assistant.set_name("BluemanAssistant")

        self.applet = AppletService()

        self.assistant.connect("prepare", self.on_prepare)
        self.assistant.connect("close", self.on_close)
        self.assistant.connect("cancel", self.on_close)

        pages[PAGE_INTRO] = self.Builder.get_object("l_page0")
        self.assistant.set_page_complete(pages[PAGE_INTRO], True)

        pages[PAGE_DEVLIST] = self.Builder.get_object("a_page1")
        pages[PAGE_PASSKEY] = self.Builder.get_object("a_page2")
        pages[PAGE_PAIRING] = self.Builder.get_object("l_page3")
        pages[PAGE_CONNECT] = self.Builder.get_object("a_page4")
        pages[PAGE_CONNECTING] = self.Builder.get_object("l_page5")
        pages[PAGE_FINISH] = self.Builder.get_object("l_page6")

        self.svc_vbox = self.Builder.get_object("svcs")

        self.Builder.get_object("r_dontp").connect("toggled", self.on_pairing_method_changed, False)
        self.Builder.get_object("r_pair").connect("toggled", self.on_pairing_method_changed, True)

        self.dev_widget = DeviceSelectorWidget()
        self.dev_widget.List.connect("device-selected", self.on_device_selected)
        self.dev_widget.List.connect("row-activated", self.on_row_activated)

        self.assistant.set_forward_page_func(self.next_page_fn, None)

        pages[PAGE_DEVLIST].add(self.dev_widget)

        self.dev_widget.show()

        if not self.dev_widget.List.is_valid_adapter():
            d = ErrorDialog(_("No adapters found"), icon_name="blueman", title="Blueman Assistant")
            d.run()
            bmexit()

        self.assistant.show()

        if parsed_args.device is not None:
            try:
                self.Adapter = self.Manager.get_adapter()
            except ValueError:
                logging.error("Error: No Adapters present")
                bmexit()
            self.Device = self.Manager.find_device(parsed_args.device, self.Adapter.get_object_path())
            if self.Device['Paired']:
                self.assistant.set_current_page(PAGE_CONNECT)
            else:
                self.assistant.set_current_page(PAGE_PASSKEY)

        else:
            self.dev_widget.List.discover_devices()

        Gtk.main()

    def on_row_activated(self, treeview, path, view_column, *args):
        self.assistant.set_current_page(self.next_page_fn(self.assistant.get_current_page(), None))

    def next_page_fn(self, page, data):
        if page == PAGE_INTRO:
            return PAGE_DEVLIST

        elif page == PAGE_DEVLIST:
            if self.Device:
                if not self.Device['Paired']:
                    return PAGE_PASSKEY
                else:
                    return PAGE_CONNECT
            else:
                return PAGE_PASSKEY
        elif page == PAGE_PASSKEY:
            if self.Device and not self.Device['Paired'] and not self.pair:
                return PAGE_CONNECT
            return PAGE_PAIRING
        elif page == PAGE_PAIRING:
            if len(get_services(self.Device)) == 0:
                return PAGE_FINISH

            return PAGE_CONNECT
        elif page == PAGE_CONNECT:

            if self.service:
                return PAGE_CONNECTING
            else:
                return PAGE_FINISH
        elif page == PAGE_CONNECTING:
            return PAGE_FINISH
        elif page == PAGE_FINISH:
            return PAGE_FINISH + 1

        return page

    def on_pairing_method_changed(self, radio_button, pair):
        if radio_button.props.active:
            self.assistant.set_page_complete(pages[PAGE_PASSKEY], True)
            self.pair = pair

    def on_device_selected(self, lst, device, tree_iter):
        if not device:
            self.assistant.set_page_complete(pages[PAGE_DEVLIST], False)
            self.Device = None
            self.Adapter = lst.Adapter
        else:
            self.assistant.set_page_complete(pages[PAGE_DEVLIST], True)
            self.Device = device
            self.Adapter = lst.Adapter

    def on_close(self, assistant):
        Gtk.main_quit()

    def on_service_toggled(self, rb, service):
        if rb.props.active:
            self.service = service
            self.assistant.set_page_complete(pages[PAGE_CONNECT], True)

    def on_prepare(self, assistant, page):
        num = assistant.get_current_page()
        if num == PAGE_PASSKEY:
            self.assistant.set_page_complete(pages[PAGE_PASSKEY], True)

        elif num == PAGE_PAIRING:
            pages[PAGE_PAIRING].set_markup(_("<b>Pairing in progress...</b>"))

            if self.pair:
                def ok():
                    self.Device = device
                    self.assistant.set_current_page(PAGE_CONNECT)

                def err(err):
                    logging.error(err)
                    pages[PAGE_FINISH].set_markup(_("<b>Failed to add device</b>"))
                    self.assistant.set_current_page(PAGE_FINISH)

                device = self.Manager.find_device(self.Device['Address'], self.Adapter.get_object_path())
                device.pair(reply_handler=ok, error_handler=err)

        elif num == PAGE_CONNECT:
            self.svc_vbox.foreach(lambda x, y: self.svc_vbox.remove(x), None)

            services = get_services(self.Device)
            logging.info(services)
            rbs = []

            for service in services:
                rbs.append(Gtk.RadioButton(service.name))
                rbs[-1].connect("toggled", self.on_service_toggled, service)
                self.svc_vbox.pack_start(rbs[-1], False, False, 0)

                if len(rbs) > 1:
                    rbs[-1].join_group(rbs[0])

            rbs.append(Gtk.RadioButton(_("Don't connect")))
            rbs[-1].join_group(rbs[0])
            rbs[-1].connect("toggled", self.on_service_toggled, None)
            self.svc_vbox.pack_start(rbs[-1], False, False, 8)

            self.svc_vbox.show_all()

            rbs[0].emit("toggled")
            if len(self.svc_vbox.get_children()) == 1:
                self.assistant.set_current_page(self.next_page_fn(self.assistant.get_current_page(), None))

        elif num == PAGE_CONNECTING:
            logging.info("connect")

            def success(*args):
                pages[PAGE_FINISH].set_markup(_("<b>Device added and connected successfully</b>"))
                self.assistant.set_page_complete(pages[PAGE_CONNECTING], True)
                self.assistant.set_current_page(PAGE_FINISH)

            def fail(*args):
                pages[PAGE_FINISH].set_markup(_("<b>Device added successfully, but failed to connect</b>"))
                self.assistant.set_page_complete(pages[PAGE_CONNECTING], True)
                self.assistant.set_current_page(PAGE_FINISH)

            self.applet.ConnectService("(os)", self.service.device.get_object_path(), self.service.uuid,
                                       result_handler=success, error_handler=fail)


if __name__ == "__main__":
    parser = create_parser()
    parser.add_argument("-d", "--device", dest="device",
                        action="store", help=_("Start configuration assistant for this device"), metavar="ADDRESS")

    args = parser.parse_args()

    if args.LEVEL.upper() == "DEBUG":
        log_level = logging.DEBUG
    elif args.LEVEL.upper() == "INFO":
        log_level = logging.INFO
    elif args.LEVEL.upper() == "WARNING":
        log_level = logging.WARNING
    elif args.LEVEL.upper() == "ERROR":
        log_level = logging.ERROR
    elif args.LEVEL.upper() == "CRITICAL":
        log_level = logging.CRITICAL
    else:
        log_level = logging.WARNING

    create_logger(log_level, "blueman-assistant", syslog=args.syslog)

    set_proc_title()
    Assistant(args)
