#!/usr/bin/env python

from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from __future__ import unicode_literals

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

pages = {}

import os
import sys
import random
import signal
import dbus.glib
from optparse import OptionParser

#support running uninstalled
_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if os.path.exists(os.path.join(_dirname, "CHANGELOG.md")):
    sys.path.insert(0, _dirname)

from blueman.Constants import *
from blueman.Functions import *
from blueman.gui.DeviceSelectorWidget import DeviceSelectorWidget
from blueman.main.applet.BluezAgent import TempAgent
from blueman.bluez.Manager import Manager
from blueman.bluez.BlueZInterface import BlueZInterface
from blueman.main.FakeDevice import FakeDevice
from blueman.main.Device import Device
from blueman.main.AppletService import AppletService

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

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

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

        usage = "Usage: %prog [options]"
        parser = OptionParser(usage)
        parser.add_option("-d", "--device", dest="device",
                          action="store", help=_("Start configuration assistant for this device"), metavar="ADDRESS")

        (options, args) = parser.parse_args()

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

        self.options = options

        self.Device = None
        self.Adapter = None
        self.pair = True
        self.service = None

        self.Builder = Gtk.Builder()
        self.Builder.set_translation_domain("blueman")
        self.Builder.add_from_file(UI_PATH + "/assistant.ui")
        self.assistant = self.Builder.get_object("assistant")
        self.assistant.set_title(_("Bluetooth Assistant"))

        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_header_image(pages[PAGE_INTRO], get_icon("blueman", 32))
        self.assistant.set_page_complete(pages[PAGE_INTRO], True)

        pages[PAGE_DEVLIST] = self.Builder.get_object("a_page1")
        self.assistant.set_page_header_image(pages[PAGE_DEVLIST], get_icon("blueman", 32))

        pages[PAGE_PASSKEY] = self.Builder.get_object("a_page2")
        self.assistant.set_page_header_image(pages[PAGE_PASSKEY], get_icon("dialog-password", 32))

        pages[PAGE_PAIRING] = self.Builder.get_object("l_page3")
        self.assistant.set_page_header_image(pages[PAGE_PAIRING], get_icon("dialog-password", 32))

        pages[PAGE_CONNECT] = self.Builder.get_object("a_page4")
        self.assistant.set_page_header_image(pages[PAGE_CONNECT], get_icon("network-transmit-recieve", 32))

        pages[PAGE_CONNECTING] = self.Builder.get_object("l_page5")
        self.assistant.set_page_header_image(pages[PAGE_CONNECTING], get_icon("network-transmit-recieve", 32))

        pages[PAGE_FINISH] = self.Builder.get_object("l_page6")
        self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32))

        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.IsValidAdapter():
            d = Gtk.MessageDialog(type=Gtk.MessageType.ERROR, )
            d.props.text = _("No adapters found")
            d.props.icon_name = "blueman"
            d.props.title = "Blueman Assistant"
            d.add_button("window-close", Gtk.ResponseType.CANCEL)
            d.run()
            exit(1)

        self.assistant.show()

        if options.device != None:
            m = Manager()
            try:
                adapter = m.get_adapter()
            except:
                print("Error: No Adapters present")
                exit(1)
            try:
                d = adapter.find_device(options.device)
                self.Device = Device(d)
                self.Adapter = adapter
                if self.Device.Paired:
                    self.assistant.set_current_page(PAGE_CONNECT)
                else:
                    self.assistant.set_current_page(PAGE_PASSKEY)
            except:
                info = {}
                info["Address"] = options.device
                info["Name"] = info["Address"].replace(":", "-")
                info["Alias"] = info["Name"]
                info["Fake"] = True

                self.Device = FakeDevice(info)
                self.Adapter = adapter
                self.assistant.set_current_page(PAGE_PASSKEY)

        else:
            self.dev_widget.List.DiscoverDevices()

        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 self.Device.Fake or 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.Fake and not self.Device.Paired and not self.pair:
                return PAGE_CONNECT
            #self.assistant.set_page_complete(pages[PAGE_PASSKEY], True)
            return PAGE_PAIRING
        elif page == PAGE_PAIRING:
            if len(self.Device.get_services()) == 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, list, device, iter):
        if not device:
            self.assistant.set_page_complete(pages[PAGE_DEVLIST], False)
            self.Device = None
            self.Adapter = list.Adapter
        else:
            self.assistant.set_page_complete(pages[PAGE_DEVLIST], True)
            self.Device = device
            self.Adapter = list.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:
            if self.Device.Fake and not self.pair:
                pages[PAGE_PAIRING].set_markup(_("<b>Adding Device...</b>"))
                self.assistant.set_page_title(pages[PAGE_PAIRING], _("Adding"))
            else:
                pages[PAGE_PAIRING].set_markup(_("<b>Pairing in progress...</b>"))

            if BlueZInterface.get_interface_version()[0] < 5:
                def ok(dev):
                    self.Device = Device(dev)
                    self.assistant.set_current_page(PAGE_CONNECT)

                def err(err):
                    print(err)
                    pages[PAGE_FINISH].set_markup(_("<b>Failed to add device</b>"))
                    self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32))
                    self.assistant.set_current_page(PAGE_FINISH)

                if self.pair:
                    agent_path = "/org/blueman/agent/temp/" + self.Device.Address.replace(":", "")
                    agent = TempAgent(self.applet.Plugins.StatusIcon, agent_path, Gtk.get_current_event_time())
                    self.Adapter.create_paired_device(self.Device.Address, agent_path, "", reply_handler=ok,
                                                      error_handler=err)
                else:
                    self.Adapter.create_device(self.Device.Address, reply_handler=ok, error_handler=err)
            else:
                if self.pair:
                    def ok():
                        self.Device = Device(device)
                        self.assistant.set_current_page(PAGE_CONNECT)

                    def err(err):
                        print(err)
                        pages[PAGE_FINISH].set_markup(_("<b>Failed to add device</b>"))
                        self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32))
                        self.assistant.set_current_page(PAGE_FINISH)

                    device = self.Adapter.find_device(self.Device.Address)
                    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)

            print(self.Device.get_services())
            rbs = []

            for service in self.Device.get_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:
            print("connect")

            def success(*args):
                pages[PAGE_FINISH].set_markup(_("<b>Device added and connected successfuly</b>"))
                self.assistant.set_page_complete(pages[PAGE_CONNECTING], True)
                self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32))
                self.assistant.set_current_page(PAGE_FINISH)

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

            self.applet.connect_service(self.service.device.get_object_path(), self.service.uuid,
                                        reply_handler=success, error_handler=fail)


set_proc_title()
Assistant()
