#!/usr/bin/env python
#
# -*-python-*-
#
# indicator-network - user interface for connman
# Copyright 2010 Canonical Ltd.
#
# Authors:
# Kalle Valo <kalle.valo@canonical.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import pygtk
pygtk.require('2.0')
import gtk
import dbus
import dbus.mainloop.glib
import xml.etree.ElementTree
import sys
import locale
import gettext

class MobileWizard(gtk.Window):

    def add_providers(self, store):
        store.clear()

        self.provider = None
        providers = self.country.getiterator("provider")
        for provider in providers:
            n = provider.find("name")
            provider_name = n.text

            gsm = provider.find("gsm")
            if gsm == None:
                # FIXME: how to handle if no gsm in operator
                continue

            apns = gsm.getiterator("apn")
            for a in apns:
                apn_value = a.attrib["value"]
                n = a.find("name")
                if n == None:
                    # FIXME: what to show if apn has no name
                    apn_name = apn_value
                else:
                    apn_name = n.text

                if len(apns) > 1:
                    name = "%s - %s" % (provider_name, apn_name)
                else:
                    name = provider_name

                store.append([provider_name, apn_value, name])

    def populate_providers(self, countrycode):
        self.country = None
        countries = self.tree.getiterator("country")
        for c in countries:
            if countrycode == c.attrib["code"]:
                self.country = c

        if self.country == None:
            print "country not found", countrycode
            return

        self.add_providers(self.provider_store)

    def provider_changed(self, combobox):
        iterator = self.provider_combo.get_active_iter()
        # if iterator == None:
        #     return
        if iterator:
            self.apn = self.provider_store[iterator][1]
            self.connect_button.set_sensitive(True)
        else:
            self.apn = ""
            self.connect_button.set_sensitive(False)

        self.summary_label.set_text(self.apn)

    def country_changed(self, combobox):
        active_iter = combobox.get_active_iter()

        if active_iter == None:
            return

        row = self.country_store[active_iter]
        self.populate_providers(row[0])

    def applied(self, assistant):
        if self.automatic_button.get_active():
            apn = self.apn
        else:
            apn = self.apn_entry.get_text()

        print "setting APN: '%s'" % (apn)
        self.service.SetProperty("APN", apn);

        try:
            self.service.Connect()
	except dbus.DBusException, error:
            print "Failed to create mobile connection: %s %s" % (error._dbus_error_name,
                                                                 error.message)

        self.quit()

    def quit(self):
        gtk.main_quit()

    def canceled(self, assistant):
        self.quit()

    def automatic_toggled(self, togglebutton):
        if not togglebutton.get_active():
            return

        iterator = self.provider_combo.get_active_iter()
        if iterator:
            self.connect_button.set_sensitive(True)
        else:
            self.connect_button.set_sensitive(False)

        self.region_box.show()
        self.provider_box.show()
        self.show_apn_box.show()
        self.edit_apn_box.hide()

    def manual_toggled(self, togglebutton):
        if not togglebutton.get_active():
            return

        self.region_box.hide()
        self.provider_box.hide()
        self.show_apn_box.hide()
        self.edit_apn_box.show_all()
        self.connect_button.set_sensitive(True)

    def get_service_properties(self):
        print "service_path %s" % (self.service_path)
        
        # FIXME: proper handling if service doesn't exist
        self.service = dbus.Interface(self.bus.get_object("net.connman",
                                                     self.service_path),
                                 "net.connman.Service")

        self.service_properties = self.service.GetProperties()

    def gsm_mcc_mnc_detect(self, mcc, mnc):
        """Try to find an APN for a network identified with mcc and
        mnc. If an APN is found, the function will set self.apn and
        return True. If no suitable APN is found, or more than one is
        found, False is returned."""
        
        apns = None

        gsms = self.tree.findall("country/provider/gsm")
        for gsm in gsms:
            nids = gsm.findall("network-id")

            network_found = False

            for nid in nids:
                if nid.attrib["mcc"] == mcc and nid.attrib["mnc"] == mnc:
                    network_found = True
                    break

            if network_found:
                apns = gsm.findall("apn")
                break

        # If there's only one APN for this network, let's use it. Otherwise
        # we must ask the user to choose.
        if len(apns) == 1:
            self.apn = apns[0].attrib["value"]
            return True
        else:
            return False

    def __init__(self, servicepath):
        gtk.Window.__init__(self)
        self.set_title(_("Mobile Wizard"))

        self.set_default_size(400, 300)

        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
	self.bus = dbus.SystemBus()

        self.service_path = servicepath
        self.get_service_properties()
        self.tree = xml.etree.ElementTree.ElementTree()

        # FIXME: this should come from pkg-config
        self.tree.parse("/usr/share/mobile-broadband-provider-info/serviceproviders.xml")

        if "MCC" in self.service_properties and \
                "MNC" in self.service_properties:
            result = self.gsm_mcc_mnc_detect(self.service_properties["MCC"],
                                             self.service_properties["MNC"])
            if result:
                print "setting automatically found APN: '%s'" % (self.apn)
                self.service.SetProperty("APN", self.apn);
                sys.exit()

        countrytable = {}

        f = open("/usr/share/zoneinfo/iso3166.tab")
        lines = f.readlines()
        for l in lines:
            if l.startswith('#'):
                continue

            l = l.strip('\n')

            r = l.split('\t')
            if len(r) != 2:
                continue

            code = r[0]
            name = r[1]
            countrytable[code.lower()] = name

        self.country_store = gtk.ListStore(str, str)
        self.country_store.set_sort_column_id(1, gtk.SORT_ASCENDING)
        for country in self.tree.getiterator("country"):
            code = country.attrib["code"]
            if countrytable.has_key(code):
                name = countrytable[code]
            else:
                name = code
            self.country_store.append([code, name])

        sizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)

        vbox = gtk.VBox()
        self.add(vbox)

        s = _("A new mobile connection '%s' was detected. Now we need to " \
            "find out the APN name needed for the connection.") % \
            (self.service_properties["Name"])
        label = gtk.Label(s)
        label.set_line_wrap(True)
        label.show_all()
        vbox.pack_start(label, False, False)

        # automatic/manual
        hbox = gtk.HBox()
        vbox.pack_start(hbox, False, False)

        label = gtk.Label(_("Access point:"))
        hbox.pack_start(label, False, False)
        sizegroup.add_widget(label)

        self.automatic_button = gtk.RadioButton(None, _("Automatic"))
        self.automatic_button.connect("toggled", self.automatic_toggled)
        hbox.pack_start(self.automatic_button)

        self.manual_button = gtk.RadioButton(self.automatic_button, _("Manual"))
        self.manual_button.connect("toggled", self.manual_toggled)
        hbox.pack_start(self.manual_button)

        hbox.show_all()

        # country
        self.region_box = gtk.HBox()
        vbox.pack_start(self.region_box, False, False)

        label = gtk.Label(_("Region:"))
        self.region_box.pack_start(label, False, False)
        sizegroup.add_widget(label)

        self.country_combo = gtk.ComboBox(self.country_store)
        cell = gtk.CellRendererText()
        self.country_combo.pack_start(cell, True)
        self.country_combo.add_attribute(cell, 'text', 1)
        self.country_combo.connect("changed", self.country_changed)
        self.region_box.pack_start(self.country_combo, True, True)

        self.region_box.show_all()

        # provider
        self.provider_box = gtk.HBox()
        vbox.pack_start(self.provider_box, False, False)

        label = gtk.Label(_("Provider:"))
        self.provider_box.pack_start(label, False, False)
        sizegroup.add_widget(label)

        # columns: provider_name, apn_value, visible_name
        self.provider_store = gtk.ListStore(str, str, str)
        self.provider_store.set_sort_column_id(2, gtk.SORT_ASCENDING)
        self.provider_combo = gtk.ComboBox(self.provider_store)
        self.provider_combo.connect("changed", self.provider_changed)
        cell = gtk.CellRendererText()
        self.provider_combo.pack_start(cell, True)
        self.provider_combo.add_attribute(cell, 'text', 2)
        self.provider_box.pack_start(self.provider_combo, True, True)

        self.provider_box.show_all()

        # chosen apn
        self.show_apn_box = gtk.HBox()
        vbox.pack_start(self.show_apn_box, False, False)

        label = gtk.Label(_("APN:"))
        self.show_apn_box.pack_start(label, False, False)
        sizegroup.add_widget(label)

        self.summary_label = gtk.Label()
        self.show_apn_box.pack_start(self.summary_label, False, False)

        self.show_apn_box.show_all()

        # edit apn
        self.edit_apn_box = gtk.HBox()
        vbox.pack_start(self.edit_apn_box, False, False)

        label = gtk.Label(_("APN:"))
        self.edit_apn_box.pack_start(label, False, False)
        sizegroup.add_widget(label)

        self.apn_entry = gtk.Entry()
        self.edit_apn_box.pack_start(self.apn_entry, False, False)

        # buttons
        hbox = gtk.HBox()
        vbox.pack_start(hbox, False, False)

        self.connect_button = gtk.Button(_("Connect"))
        hbox.pack_end(self.connect_button, False, False)
        self.connect_button.connect("clicked", self.applied)
        self.connect_button.set_sensitive(False)

        button = gtk.Button(_("Cancel"))
        hbox.pack_end(button, False, False)
        button.connect("clicked", self.canceled)

        hbox.show_all()

        vbox.show()
        self.show()

def usage(name):
    print "Usage: %s <SERVICE_PATH>" % (name)
    print "Example: %s /profile/default/cellular_1234567_primarycontext1" % \
        (name)

def main():
    name = sys.argv.pop(0)

    if len(sys.argv) != 1:
        usage(name)
        return 1

    path = sys.argv.pop(0)

    settings = MobileWizard(path)
    gtk.main()

if __name__ == "__main__":
    APP = 'indicator-network'
    DIR = '/usr/share/locale'
    locale.setlocale(locale.LC_ALL, '')
    gettext.bindtextdomain(APP, DIR)
    gettext.textdomain(APP)
    _ = gettext.gettext

    main()
