#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""gtk3.gui.py"""

# Copyright (C) 2011-2017 Pierluigi Villani

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import os
import io
import gi
gi.require_version("WebKit2", "4.0")
from gi.repository import Gtk, GObject, Gdk, GdkPixbuf, Pango
from gi.repository import WebKit2
import glal
import cairo
from themes import ThemeManager
from version import VERSION, VERSION_CHECK_ENABLED

pixmap_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                          '..', '..',
                                          'pixmaps')
ICON_FILENAME = os.path.join(pixmap_dir, 'cyclograph.svg')
if not os.path.isfile(ICON_FILENAME):
    pixmap_dir = '/usr/share/cyclograph/icons/'
    ICON_FILENAME = '/usr/share/icons/hicolor/scalable/apps/cyclograph.svg'


class Gui(Gtk.Window):
    """Main window"""
    def __init__(self, parent, title, size):
        super(Gui, self).__init__()

        self.cg_exit = None  # check on exit callback
        self.set_title(title)
        self.maximized = False
        self.set_default_size(size[0], size[1])
        if size[2]:
            self.maximize()
            self.maximized = True
        try:
            self.set_icon_from_file(ICON_FILENAME)
        except Exception:
            pass  # if librsvg2-common is not installed
        self.set_position(Gtk.WindowPosition.CENTER)

        self.notebook = Gtk.Notebook()
        self.notebook.set_property('show-tabs', True)

        agr = Gtk.AccelGroup()
        self.add_accel_group(agr)

        # Statusbar
        self.statusbar = Gtk.Statusbar()
        self.context_id = self.statusbar.get_context_id("Statusbar")
        self.sbtimer = glal.Timer(5000, self.clearstatusbartext)  # 5000ms timeout

        # Load icons
        icons = [('icon_add', os.path.join(pixmap_dir, 'icon_add.svg')),
                  ('icon_ckml', os.path.join(pixmap_dir, 'icon_ckml.svg')),
                  ('icon_delete', os.path.join(pixmap_dir, 'icon_delete.svg')),
                  ('icon_modify', os.path.join(pixmap_dir, 'icon_modify.svg')),
                  ('icon_plot', os.path.join(pixmap_dir, 'icon_plot.svg')),
                  ('icon_map', os.path.join(pixmap_dir, 'icon_map.svg')),
                  ('icon_info', os.path.join(pixmap_dir, 'icon_info.svg'))]

        factory = Gtk.IconFactory()
        for (icon_id, icon_file) in icons:
            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_file)
            except Exception:
                continue  # if librsvg2-common is not installed
            iconset = Gtk.IconSet.new_from_pixbuf(pixbuf)
            factory.add(icon_id, iconset)
        factory.add_default()

        # Action group
        self.menu_item_new = Gtk.Action(name="New",
                                        label=_(u"New"),
                                        tooltip=_(u"New Slope"),
                                        stock_id=Gtk.STOCK_NEW)
        self.menu_item_open = Gtk.Action(name="Open",
                                         label=_(u"Open"),
                                         tooltip=_(u"Open Slope"),
                                         stock_id=Gtk.STOCK_OPEN)
        self.menu_item_createkml = Gtk.Action(name="CreateKML",
                                              label=_(u"Create"),
                                              tooltip=_(u"Create KML"),
                                              stock_id='icon_ckml')
        self.menu_item_save = Gtk.Action(name="Save",
                                         label=_(u"Save"),
                                         tooltip=_(u"Save Slope"),
                                         stock_id=Gtk.STOCK_SAVE)

        actiongroup = Gtk.ActionGroup(name='Actions')
        actiongroup.add_action(self.menu_item_new)
        actiongroup.add_action(self.menu_item_open)
        actiongroup.add_action(self.menu_item_createkml)
        actiongroup.add_action(self.menu_item_save)

        # Toolbar
        toolbar = Gtk.Toolbar()
        context = toolbar.get_style_context()
        context.add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)

        self.action_add = Gtk.ToolButton.new_from_stock('icon_add')
        self.action_add.set_label_widget(Gtk.Label(label=_(u"Add")))
        self.action_add.set_homogeneous(False)
        self.action_add.set_tooltip_text(_(u"Add a check-point"))
        key, mod = Gtk.accelerator_parse('plus')
        self.action_add.add_accelerator("clicked", agr,
                                             key, mod, Gtk.AccelFlags.VISIBLE)
        self.action_edit = Gtk.ToolButton.new_from_stock('icon_modify')
        self.action_edit.set_label_widget(Gtk.Label(label=_(u"Edit")))
        self.action_edit.set_homogeneous(False)
        self.action_edit.set_tooltip_text(_(u"Edit a check-point"))
        self.action_delete = Gtk.ToolButton.new_from_stock('icon_delete')
        self.action_delete.set_label_widget(Gtk.Label(label=_(u"Delete")))
        self.action_delete.set_homogeneous(False)
        self.action_delete.set_tooltip_text(_(u"Remove a check-point"))
        key, mod = Gtk.accelerator_parse('minus')
        self.action_delete.add_accelerator("clicked", agr,
                                             key, mod, Gtk.AccelFlags.VISIBLE)
        self.action_plot = Gtk.ToolButton.new_from_stock('icon_plot')
        self.action_plot.set_homogeneous(False)
        self.action_plot.set_label_widget(Gtk.Label(label=_(u"Plot")))
        self.action_plot.set_tooltip_text(_(u"Plot your slope"))
        self.action_map = Gtk.ToolButton.new_from_stock('icon_map')
        self.action_map.set_homogeneous(False)
        self.action_map.set_label_widget(Gtk.Label(label=_(u"Map")))
        self.action_map.set_tooltip_text(_(u"Show the map of your slope"))
        self.action_properties = Gtk.ToolButton.new_from_stock('icon_info')
        self.action_properties.set_homogeneous(False)
        self.action_properties.set_label_widget(Gtk.Label(label=_(u"Info")))
        self.action_properties.set_tooltip_text(_(u"Informations about the slope"))

        self.menu_item_save.set_sensitive(False)
        self.action_add.set_sensitive(False)
        self.action_edit.set_sensitive(False)
        self.action_delete.set_sensitive(False)
        self.action_plot.set_sensitive(False)
        self.action_map.set_sensitive(False)
        self.action_properties.set_sensitive(False)

        toolbar.insert(self.menu_item_new.create_tool_item(), 0)
        toolbar.insert(self.menu_item_open.create_tool_item(), 1)
        toolbar.insert(self.menu_item_createkml.create_tool_item(), 2)
        toolbar.insert(self.menu_item_save.create_tool_item(), 3)
        toolbar.insert(Gtk.SeparatorToolItem(), 4)
        toolbar.insert(self.action_add, 5)
        toolbar.insert(self.action_edit, 6)
        toolbar.insert(self.action_delete, 7)
        toolbar.insert(Gtk.SeparatorToolItem(), 8)
        toolbar.insert(self.action_plot, 9)
        toolbar.insert(self.action_map, 10)
        toolbar.insert(self.action_properties, 11)

        # Creating the menubar.
        menubar = Gtk.MenuBar()
        filemenu = Gtk.Menu()
        self.smenu = Gtk.MenuItem.new_with_mnemonic(_(u"_File"))
        self.smenu.set_submenu(filemenu)

        item_new = self.menu_item_new.create_menu_item()
        key, mod = Gtk.accelerator_parse("<Control>N")
        item_new.add_accelerator("activate", agr,
                                           key, mod, Gtk.AccelFlags.VISIBLE)
        filemenu.append(item_new)

#        sep = Gtk.SeparatorMenuItem()
#        filemenu.append(sep)

        item_open = self.menu_item_open.create_menu_item()
        key, mod = Gtk.accelerator_parse("<Control>O")
        item_open.add_accelerator("activate", agr,
                                            key, mod, Gtk.AccelFlags.VISIBLE)
        filemenu.append(item_open)

        item_createkml = self.menu_item_createkml.create_menu_item()
        key, mod = Gtk.accelerator_parse("<Control>G")
        item_createkml.add_accelerator("activate", agr,
                                                 key, mod, Gtk.AccelFlags.VISIBLE)
        filemenu.append(item_createkml)

        item_save = self.menu_item_save.create_menu_item()
        key, mod = Gtk.accelerator_parse("<Control>S")
        item_save.add_accelerator("activate", agr,
                                            key, mod, Gtk.AccelFlags.VISIBLE)
        filemenu.append(item_save)

        self.menu_item_save_as = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_SAVE_AS, agr)
        self.menu_item_save_as.set_sensitive(False)
        key, mod = Gtk.accelerator_parse("<Control><alt>S")
        self.menu_item_save_as.add_accelerator("activate", agr,
                                            key, mod, Gtk.AccelFlags.VISIBLE)
        filemenu.append(self.menu_item_save_as)

#        sep = Gtk.SeparatorMenuItem()
#        filemenu.append(sep)

        self.menu_item_exit = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_QUIT, agr)
        filemenu.append(self.menu_item_exit)

        menubar.append(self.smenu)

        filemenu1 = Gtk.Menu()
        self.omenu = Gtk.MenuItem.new_with_mnemonic(_(u"_Options"))
        self.omenu.set_submenu(filemenu1)

        kmenu = Gtk.Menu()
        kmenum = Gtk.MenuItem.new_with_mnemonic("_Kml server")
        kmenum.set_submenu(kmenu)

        self.menu_item_s1 = Gtk.RadioMenuItem.new_with_label(
                                                        [], (u"geonames.org"))
        self.menu_item_s2 = Gtk.RadioMenuItem.new_with_label_from_widget(
                                        self.menu_item_s1, (u"earthtools.org"))
        self.menu_item_s3 = Gtk.RadioMenuItem.new_with_label_from_widget(
                                            self.menu_item_s1, (u"usgs.net"))

        kmenu.append(self.menu_item_s1)
        kmenu.append(self.menu_item_s2)
        kmenu.append(self.menu_item_s3)

        filemenu1.append(kmenum)

#        sep = Gtk.SeparatorMenuItem()
#        filemenu1.append(sep)

        self.preferences = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_PREFERENCES, agr)
        filemenu1.append(self.preferences)

        menubar.append(self.omenu)

        filemenu2 = Gtk.Menu()
        self.amenu = Gtk.MenuItem.new_with_label((u"?"))
        self.amenu.set_submenu(filemenu2)

        self.menu_item_about = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_ABOUT, agr)
        self.menu_item_about.connect("activate", onabout)
        filemenu2.append(self.menu_item_about)

        self.menu_item_bug = Gtk.MenuItem.new_with_label(_(u"Signal a bug"))
        filemenu2.append(self.menu_item_bug)

        menubar.append(self.amenu)

        vbox = Gtk.VBox()
        vbox.pack_start(menubar, False, False, 0)
        vbox.pack_start(toolbar, False, False, 0)
        vbox.pack_start(self.notebook, True, True, 0)
        vbox.pack_start(self.statusbar, False, False, 0)

        self.add(vbox)
        self.connect("delete-event", self.exit)
        self.connect('window-state-event', self.on_window_state_event)
        self.show_all()

    def exit(self, event=None, param=None):
        """ Exit from CycloGraph, check if there are unsaved slopes"""
        if self.cg_exit():
            Gtk.main_quit()
            return
        return True  # needed by gtk

    def getdimensions(self):
        """Return window width and height"""
        return self.get_size()

    def ismaximized(self):
        """Return true if window is maximized"""
        return self.maximized

    def addstatusbartext(self, text):
        """Add text to the statusbar"""
        self.statusbar.push(self.context_id, text)

    def clearstatusbartext(self):
        """Remove text from statusbar"""
        self.statusbar.pop(self.context_id)
        self.sbtimer.stop()

    def on_window_state_event(self, widget, event):
        "Update maximized variable to the current window state"
        if event.new_window_state & Gdk.WindowState.MAXIMIZED:
            self.maximized = True
        else:
            self.maximized = False


def onabout(event):
    """ About dialog"""
    about = Gtk.AboutDialog()
    about.set_program_name("CycloGraph")
    about.set_version(VERSION)
    about.set_copyright("Copyright (C) 2008-2017 Federico Brega, Pierluigi Villani")
    about.set_authors(("Federico Brega", "Pierluigi Villani"))
    about.set_license("""
CycloGraph is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.

CycloGraph is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY 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/.
""")
    about.set_website("http://cyclograph.sourceforge.net")
    about.set_logo(GdkPixbuf.Pixbuf.new_from_file(ICON_FILENAME))
    about.set_icon_from_file(ICON_FILENAME)
    about.run()
    about.destroy()


class Page(Gtk.ScrolledWindow):
    """Notebook page"""
    def __init__(self, parent):
        GObject.GObject.__init__(self)
        self.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)

        self.store = Gtk.ListStore(int, str, str, str)
        self.mylistctrl = Gtk.TreeView.new_with_model(self.store)
        self.mylistctrl.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        # can select multiple cp by dragging the mouse
        self.mylistctrl.set_rubber_banding(True)
        self.add(self.mylistctrl)
        self.savedfilepath = None
        self.modified = False
        self.slopecounternew = 0
        self.closebox = None

        rendererText = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn(u"#", rendererText, text=0)
        column.set_sort_column_id(0)
        self.mylistctrl.append_column(column)

        rendererText = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn(_(u"Distance [km]"), rendererText, text=1)
        column.set_sort_column_id(1)
        self.mylistctrl.append_column(column)

        rendererText = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn(_(u"Altitude [m]"), rendererText, text=2)
        column.set_sort_column_id(2)
        self.mylistctrl.append_column(column)

        rendererText = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn(_(u"Name"), rendererText, text=3)
        column.set_sort_column_id(3)
        self.mylistctrl.append_column(column)

        self.mylistctrl.set_headers_clickable(False)  # disable column sort

    def insert_row(self, row_num, chkpnt):
        """Insert item to this page at position row_num"""
        self.store.insert(row_num, [row_num, str(chkpnt[0]),
                                    str(chkpnt[1]), chkpnt[2]])
        treeiter = self.store.get_iter(path = (row_num,))
        while treeiter is not None:
            self.store[treeiter][0] = self.store[treeiter][0] + 1
            treeiter = self.store.iter_next(treeiter)

    def delete_row(self, row_num):
        """Removes row at position row_num in this page."""
        itera = self.store.get_iter(path = (row_num,))
        treeiter = self.store.iter_next(itera)
        while treeiter is not None:
            self.store[treeiter][0] = self.store[treeiter][0] - 1
            treeiter = self.store.iter_next(treeiter)
        self.store.remove(itera)

    def get_sel_row(self):
        """Gives the row number that is selected."""
        selection = self.mylistctrl.get_selection()
        model, selected = selection.get_selected_rows()
        editcp = -1
        if len(selected) > 0:
            editcp = selected[0].get_indices()[0]
        return editcp

    def get_sel_multi_row(self):
        """Gives a list with the row number of selected items."""
        selection = self.mylistctrl.get_selection()
        model, selected = selection.get_selected_rows()
        rm_cps = [path.get_indices()[0] for path in selected]
        return rm_cps


class Managecp(Gtk.Dialog):
    """Add and edit dialog"""
    def __init__(self, parent, title, dist="", alt="", name=""):
        GObject.GObject.__init__(self)
        self.set_title(title)
        self.set_transient_for(parent)
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
        self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
        self.set_size_request(220, 150)
        box = Gtk.VBox(spacing=10)
        box.set_border_width(10)
        vbox = self.get_content_area()
        vbox.pack_start(box, True, True, 0)
        box.show()

        labelbox = Gtk.VBox(spacing=10)
        labelbox.set_border_width(10)
        labelbox.pack_start(Gtk.Label(_(u"Distance:")), True, True, 0)
        labelbox.pack_start(Gtk.Label(_(u"Altitude:")), True, True, 0)
        labelbox.pack_start(Gtk.Label(_(u"Name:")), True, True, 0)

        entrybox = Gtk.VBox()
        self.distance = Gtk.Entry()
        self.distance.set_text(dist)
        self.distance.set_activates_default(True)
        entrybox.pack_start(self.distance, True, True, 0)
        self.altitude = Gtk.Entry()
        self.altitude.set_text(alt)
        self.altitude.set_activates_default(True)
        entrybox.pack_start(self.altitude, True, True, 0)
        self.cpname = Gtk.Entry()
        self.cpname.set_text(name)
        self.cpname.set_activates_default(True)
        entrybox.pack_start(self.cpname, True, True, 0)

        obox = Gtk.HBox()
        obox.pack_start(labelbox, False, False, 0)
        obox.pack_start(entrybox, True, True, 0)

        box.pack_start(obox, True, True, 0)
        box.show_all()

    def show_modal(self):
        """Shows the dialog and returns True if the value has to be changed."""
        return self.run() == Gtk.ResponseType.ACCEPT

    def destroy(self):
        """Destroy current managecp"""
        Gtk.Dialog.destroy(self)

    def getcp(self):
        """Gives the modified values."""
        dist = self.distance.get_text()
        alti = self.altitude.get_text()
        name = self.cpname.get_text()
        return (dist, alti, name)


class FormSlopeInfo(Gtk.Dialog):
    """info dialog about the slope"""
    def __init__(self, parent, slopedata):
        GObject.GObject.__init__(self)
        self.set_title(_(u"Slope Info"))
        self.set_transient_for(parent)
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
        self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)

        self.set_size_request(300, 420)
        box = Gtk.VBox(spacing=10)
        box.set_border_width(10)
        vbox = self.get_content_area()
        vbox.pack_start(box, True, True, 0)
        box.show()

        grid = Gtk.Grid()
        box.pack_start(grid, False, True, 0)
        grid.show()

        grid.add(Gtk.Label(label=_(u"Name:")))
        self.s_name = Gtk.Entry()
        self.s_name.set_text(slopedata['name'])
        grid.attach(self.s_name, 1, 0, 1, 1)
        grid.attach(Gtk.Label(label=_(u"State:")), 0, 1, 1, 1)
        self.s_state = Gtk.Entry()
        self.s_state.set_text(slopedata['state'])
        grid.attach(self.s_state, 1, 1, 1, 1)
        grid.attach(Gtk.Label(label=_(u"Author:")), 0, 2, 1, 1)
        self.s_author = Gtk.Entry()
        self.s_author.set_text(slopedata['author'])
        grid.attach(self.s_author, 1, 2, 1, 1)
        grid.attach(Gtk.Label(label=_(u"E-mail:")), 0, 3, 1, 1)
        self.s_email = Gtk.Entry()
        self.s_email.set_text(slopedata['email'])
        grid.attach(self.s_email, 1, 3, 1, 1)
        grid.attach(Gtk.Label(label=_(u"Average gradient:")), 0, 4, 1, 1)
        grid.attach(Gtk.Label(label=slopedata['average_grad']), 1, 4, 1, 1)
        grid.attach(Gtk.Label(label=_(u"Max gradient:")), 0, 5, 1, 1)
        grid.attach(Gtk.Label(label=slopedata['max_grad']), 1, 5, 1, 1)
        grid.attach(Gtk.Label(label=_(u"Height difference:")), 0, 6, 1, 1)
        grid.attach(Gtk.Label(label=slopedata['height_difference']), 1, 6, 1, 1)
        grid.attach(Gtk.Label(label=_(u"Height gain:")), 0, 7, 1, 1)
        grid.attach(Gtk.Label(label=slopedata['height_gain']), 1, 7, 1, 1)

        grid.attach(Gtk.Label(_(u"Note")+":"), 0, 8, 1, 1)
        grid.set_row_spacing(7)
        grid.set_column_spacing(5)

        self.s_comment = Gtk.TextBuffer()
        self.s_comment.set_text(slopedata['comment'])
        textview = Gtk.TextView()
        textview.set_buffer(self.s_comment)
        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_placement(Gtk.CornerType.TOP_LEFT)
        sw.add(textview)
        sw.show_all()
        box.pack_start(sw, True, True, 0)

        box.show_all()

    def getslopeinfo(self):
        """Returns the slope infos: name, state, comment"""
        startnote, endnote = self.s_comment.get_bounds()
        return {'name': self.s_name.get_text(),
                'state': self.s_state.get_text(),
                'author': self.s_author.get_text(),
                'email': self.s_email.get_text(),
                'comment': self.s_comment.get_text(startnote, endnote, True)}

    def show_modal(self):
        """Shows the dialog and returns True if the value has to be chenged."""
        return self.run() == Gtk.ResponseType.ACCEPT

    def destroy(self):
        """Destroy current FormSlopeInfo"""
        Gtk.Dialog.destroy(self)


class tab_label(Gtk.HBox):
    """Notebook tab custom label with close button"""
    def __init__(self, page, title):
        GObject.GObject.__init__(self)
        self.label = Gtk.Label(label=title)
        self.closebtn = Gtk.Button()
        image = Gtk.Image()
        image.set_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU)
        self.closebtn.set_image(image)
        self.closebtn.set_relief(Gtk.ReliefStyle.NONE)
        self.pack_start(self.label, True, True, 0)
        self.pack_end(self.closebtn, False, False, 0)
        self.show_all()


class Plot(Gtk.Window):
    """plot main class"""
    def __init__(self, parent, slope, plot_settings,
                 exportfun, exportfun_pdf, exportfun_html):
        super(Plot, self).__init__()

        title = "CycloGraph"
        if slope.name:
            title += " - " + slope.name
        self.set_title(title)
        self.settings = plot_settings
        self.set_default_size(self.settings['width'], self.settings['height'])
        # set minimum height and width that plot can have
        geometry = Gdk.Geometry()
        geometry.min_width = 300
        geometry.min_height = 300
        self.set_geometry_hints(self, geometry, 0)
        self.set_icon_from_file(ICON_FILENAME)

        menubar = Gtk.MenuBar()
        filemenu = Gtk.Menu()
        self.menu = Gtk.MenuItem.new_with_mnemonic(_(u"_Options"))
        self.menu.set_submenu(filemenu)

        agr = Gtk.AccelGroup()
        self.add_accel_group(agr)

        self.menu_item_save = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_SAVE, agr)
        filemenu.append(self.menu_item_save)
        self.menu_item_savepdf = Gtk.MenuItem.new_with_mnemonic(_(u"Save _PDF"))
        filemenu.append(self.menu_item_savepdf)
        self.menu_item_savehtml = Gtk.MenuItem.new_with_mnemonic(_(u"Save _html"))
        filemenu.append(self.menu_item_savehtml)
        self.menu_item_olines = Gtk.CheckMenuItem.new_with_label(_(u"Orizzontal lines"))
        self.menu_item_olines.set_active(self.settings['olines'])
        filemenu.append(self.menu_item_olines)
        self.menu_item_3d = Gtk.CheckMenuItem.new_with_label(_(u"3D effect"))
        self.menu_item_3d.set_active(self.settings['3d'])
        filemenu.append(self.menu_item_3d)
        self.menu_item_legend = Gtk.CheckMenuItem.new_with_label(_(u"Show legend"))
        self.menu_item_legend.set_active(self.settings['legend'])
        filemenu.append(self.menu_item_legend)

        tmenu = Gtk.Menu()
        tmenum = Gtk.MenuItem.new_with_mnemonic(_(u"_Theme"))
        tmenum.set_submenu(tmenu)

        self.themeitems = []
        self.radioitem = {}
        self.thememanager = ThemeManager()
        for theme in self.thememanager.getthemeslist():
            if self.settings['theme'] == theme:
                self.theme1 = Gtk.RadioMenuItem.new_with_label([], theme)
            self.themeitems.append(theme)
        self.theme1.connect("activate", self.changetheme)
        for theme in self.themeitems:
            if self.settings['theme'] != theme:
                rmi = Gtk.RadioMenuItem.new_with_label_from_widget(self.theme1, theme)
                rmi.connect("activate", self.changetheme)
                tmenu.append(rmi)
                self.radioitem[theme] = rmi
            else:
                self.radioitem[theme] = self.theme1
                tmenu.append(self.theme1)
        self.theme1.set_active(True)

        filemenu.append(tmenum)

        rmenu = Gtk.Menu()
        rmenum = Gtk.MenuItem.new_with_mnemonic(_(u"Saving _resolution"))
        rmenum.set_submenu(rmenu)

        menu_item_r1 = Gtk.RadioMenuItem.new_with_label([], (u"800x600"))
        menu_item_r2 = Gtk.RadioMenuItem.new_with_label_from_widget(menu_item_r1, (u"1024x768"))
        menu_item_r3 = Gtk.RadioMenuItem.new_with_label_from_widget(menu_item_r1, (u"1280x800"))
        menu_item_r4 = Gtk.RadioMenuItem.new_with_label_from_widget(menu_item_r1, (u"1600x1200"))
        menu_item_r1.set_active(self.settings['width'] == 800)
        menu_item_r2.set_active(self.settings['width'] == 1024)
        menu_item_r3.set_active(self.settings['width'] == 1280)
        menu_item_r4.set_active(self.settings['width'] == 1600)
        menu_item_r1.connect("activate", self.res1)
        menu_item_r2.connect("activate", self.res2)
        menu_item_r3.connect("activate", self.res3)
        menu_item_r4.connect("activate", self.res4)

        rmenu.append(menu_item_r1)
        rmenu.append(menu_item_r2)
        rmenu.append(menu_item_r3)
        rmenu.append(menu_item_r4)

        filemenu.append(rmenum)

        menubar.append(self.menu)

        self.menu_item_save.connect("activate", self.saveimage)
        self.menu_item_savepdf.connect("activate", self.savepdf)
        self.menu_item_savehtml.connect("activate", self.savehtml)
        self.menu_item_olines.connect("activate", self.olines)
        self.menu_item_3d.connect("activate", self.change3d)
        self.menu_item_legend.connect("activate", self.legend)

        darea = Gtk.DrawingArea()
        darea.connect("draw", self.on_paint)

        self.myslope = slope
        self.devc = glal.DeviceContext()
        self.myslope.calc()
        self.exportfun = exportfun
        self.exportfun_pdf = exportfun_pdf
        self.exportfun_html = exportfun_html

        vbox = Gtk.VBox()
        vbox.pack_start(menubar, False, False, 0)
        vbox.pack_start(darea, True, True, 0)
        self.add(vbox)
        self.show_all()

    def on_paint(self, widget, event):
        """Draw graph"""
        window = widget.get_window()
        devc = window.cairo_create()
        self.devc.init_draw_surf(devc, widget.get_allocation().width,
                                 widget.get_allocation().height)
        self.myslope.paint(self.settings, self.devc)

    def showplot(self):
        """ Show plot"""
        pass

    def saveimage(self, event):
        """ Save plot image"""
        self.exportfun(self.myslope, self.settings)

    def savepdf(self, event):
        """ Save pdf report"""
        self.exportfun_pdf(self.myslope, self.settings)

    def savehtml(self, event):
        """ Save html report"""
        self.exportfun_html(self.myslope, self.settings)

    def change3d(self, event):
        """ If active switch 3d effect off, else turn it on."""
        self.settings['3d'] = not self.settings['3d']
        self.queue_draw()

    def olines(self, event):
        """ If active draws orizzontal lines"""
        self.settings['olines'] = not self.settings['olines']
        self.queue_draw()

    def legend(self, event):
        """ If active draws legend"""
        self.settings['legend'] = not self.settings['legend']
        self.queue_draw()

    def changetheme(self, event):
        """Change the actual slope theme."""
        ritemt = self.radioitem.items()
        for theme in ritemt:
            if theme[1] == event:
                self.settings["theme"] = theme[0]
                self.queue_draw()
                break

    def res1(self, event=None):
        """Set 800x600"""
        self.settings['width'] = 800
        self.settings['height'] = 600

    def res2(self, event=None):
        """Set 1024x768"""
        self.settings['width'] = 1024
        self.settings['height'] = 768

    def res3(self, event=None):
        """Set 1280x800"""
        self.settings['width'] = 1280
        self.settings['height'] = 800

    def res4(self, event=None):
        """Set 1600x1200"""
        self.settings['width'] = 1600
        self.settings['height'] = 1200

FONT_TYP = {
            "300": "light",
            "400": "normal",
            "700": "bold",
           }


class Preferences(Gtk.Dialog):
    """Set program preferences"""
    def __init__(self, parent, pref, default_pref):
        GObject.GObject.__init__(self)
        self.set_title(_(u"Preferences"))
        self.set_transient_for(parent)
        self.set_modal(True)
        self.set_destroy_with_parent(True)

        self.colorlist = []

        for color in pref['colors']:
            components = [int(component) << 8 for component in color[4:-1].split(',')]
            self.colorlist.append(Gdk.Color(*components))

        self.default = default_pref
        self.set_size_request(340, 400)
        notebook = Gtk.Notebook()
        notebook.set_tab_pos(Gtk.PositionType.TOP)

        frame = Gtk.Frame()
        vbox = Gtk.VBox()
        vbox.set_border_width(5)
        hbox = Gtk.HBox()
        hbox.pack_start(vbox, False, False, 10)
        frame.add(hbox)
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        label = Gtk.Label(label="<b>"+_(u"Visualization")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)
        self.olines = Gtk.CheckButton(label=_(u"Orizzontal lines"))
        vbox.pack_start(self.olines, False, False, 0)
        self.olines.set_active(pref['olines'])
        self.effect3d = Gtk.CheckButton(label=_(u"3D effect"))
        vbox.pack_start(self.effect3d, False, False, 0)
        self.effect3d.set_active(pref['3d'])
        self.showinfo = Gtk.CheckButton(label=_(u"Show info"))
        vbox.pack_start(self.showinfo, False, False, 0)
        self.showinfo.set_active(pref['sinfo'])
        self.legend = Gtk.CheckButton(label=_(u"Show legend"))
        vbox.pack_start(self.legend, False, False, 0)
        self.legend.set_active(pref['legend'])

        label = Gtk.Label(label="<b>"+_(u"Resolution")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)
        self.res = Gtk.ComboBoxText.new()
        self.res.append_text('800 x 600')
        self.res.append_text('1024 x 768')
        self.res.append_text('1280 x 800')
        self.res.append_text('1600 x 1200')
        self.res.set_active(0)
        if pref['width'] == 1600:
            self.res.set_active(3)
        elif pref['width'] == 1280:
            self.res.set_active(2)
        elif pref['width'] == 1024:
            self.res.set_active(1)
        vbox.pack_start(self.res, False, False, 0)

        label = Gtk.Label(label="<b>"+_(u"Theme")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)
        self.theme = Gtk.ComboBoxText.new()
        current = 0
        for theme in pref['themelist']:
            self.theme.append_text(theme)
            if theme == pref['theme']:
                self.theme.set_active(current)
            current += 1
        vbox.pack_start(self.theme, False, False, 0)

        label = Gtk.Label(label="<b>"+_(u"Kml server")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)
        self.serv = Gtk.ComboBoxText.new()
        self.serv.append_text('geonames.org')
        self.serv.append_text('earthtools.org')
        self.serv.append_text('usgs.net')
        self.serv.set_active(0)
        if pref['serv'] == 'usgs.net':
            self.serv.set_active(2)
        elif pref['serv'] == 'earthtools.org':
            self.serv.set_active(1)
        vbox.pack_start(self.serv, False, False, 0)

        vchecklabel = Gtk.Label(label="<b>"+_(u"Latest version")+"</b>")
        vchecklabel.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(vchecklabel, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)
        self.vcheck = Gtk.CheckButton(label=_(u"Check online"))
        vbox.pack_start(self.vcheck, False, False, 0)
        self.vcheck.set_active(pref['vcheck'])

        notebook.append_page(frame, Gtk.Label(label="General"))

        frame = Gtk.Frame()
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        vbox = Gtk.VBox()
        vbox.set_border_width(5)
        hbox = Gtk.HBox()
        hbox.pack_start(vbox, False, False, 10)
        frame.add(hbox)

        label = Gtk.Label(label="<b>"+_(u"Description")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)

        desc = pref['fdesc']
        self.fdesc = Gtk.Button(label=desc['des']+' | '+str(desc["dim"]))
        self.fdesc.desc = desc
        self.fdesc.connect("clicked", self.font_button_clicked)
        vbox.pack_start(self.fdesc, False, False, 0)

        label = Gtk.Label(label="<b>"+_(u"Gradient")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)

        desc = pref['fgrad']
        self.fgrad = Gtk.Button(label=desc['des']+' | '+str(desc["dim"]))
        self.fgrad.desc = desc
        self.fgrad.connect("clicked", self.font_button_clicked)
        vbox.pack_start(self.fgrad, False, False, 0)

        label = Gtk.Label(label="<b>"+_(u"Title")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)

        desc = pref['ftitle']
        self.ftitle = Gtk.Button(label=desc['des']+' | '+str(desc["dim"]))
        self.ftitle.desc = desc
        self.ftitle.connect("clicked", self.font_button_clicked)
        vbox.pack_start(self.ftitle, False, False, 0)

        vbox.show_all()
        notebook.append_page(frame, Gtk.Label(label="Fonts"))

        frame = Gtk.Frame()
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        vbox = Gtk.VBox()
        vbox.set_border_width(5)
        frame.add(vbox)
        self.grid = Gtk.Grid()
        vbox.pack_start(self.grid, True, True, 0)
        self.grid.show()

        self.tick = 0.1
        self.levlist = []
        self.colblist = []
        for i in range(len(pref['levels'])):
            self.levlist.append(Gtk.SpinButton())
            self.levlist[i].set_range(0.0, 90.0)
            self.levlist[i].set_value(pref['levels'][i])
            self.levlist[i].set_increments(self.tick, 1)
            self.levlist[i].set_numeric(True)
            self.levlist[i].set_digits(1)
            self.levlist[i].connect("value_changed", self.changed_level)

            self.colblist.append(
                            Gtk.ColorButton.new_with_color(self.colorlist[i]))

            hbx = Gtk.HBox()
            hbx.pack_start(Gtk.Label(label=">"), False, False, 5)
            hbx.pack_start(self.levlist[i], False, False, 5)
            hbx.pack_start(Gtk.Label(label="%"), False, False, 5)
            self.grid.attach(hbx, 0, i, 1, 1)
            self.grid.attach(self.colblist[i], 1, i, 1, 1)

        self.grid.set_row_spacing(10)
        self.grid.set_column_spacing(10)

        vbox.show_all()

        notebook.append_page(frame, Gtk.Label(label="Gradient colors"))

        frame = Gtk.Frame()
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        vbox = Gtk.VBox()
        vbox.set_border_width(5)
        hbox = Gtk.HBox()
        hbox.pack_start(vbox, False, False, 10)
        frame.add(hbox)

        label = Gtk.Label(label="<b>"+_(u"Name")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)

        self.aname = Gtk.Entry()
        self.aname.set_text(pref['aname'])
        vbox.pack_start(self.aname, False, False, 0)

        label = Gtk.Label(label="<b>"+_(u"E-mail")+"</b>")
        label.set_use_markup(True)
        hhbox = Gtk.HBox()
        hhbox.pack_start(label, False, False, 0)
        vbox.pack_start(hhbox, False, False, 5)

        self.amail = Gtk.Entry()
        self.amail.set_text(pref['amail'])
        vbox.pack_start(self.amail, False, False, 0)

        vbox.show_all()
        notebook.append_page(frame, Gtk.Label(label="Author"))
        notebook.show_all()

        bbox = Gtk.HBox()
        button_k = Gtk.Button(stock=Gtk.STOCK_OK)
        button_c = Gtk.Button(stock=Gtk.STOCK_CANCEL)
        button_d = Gtk.Button(label=_(u"Restore Default"))
        bbox.pack_end(button_k, False, False, 5)
        bbox.pack_end(button_c, False, False, 5)
        bbox.pack_start(button_d, False, False, 5)
        button_k.connect("clicked", self.ok_clicked)
        button_d.connect("clicked", self.restore_default)
        button_c.connect("clicked", self.destroy)

        box = Gtk.VBox()
        box.pack_start(notebook, True, True, 5)
        box.pack_start(bbox, False, False, 5)
        carea = self.get_content_area()
        carea.pack_start(box, True, True, 0)
        carea.show_all()
        if not VERSION_CHECK_ENABLED:
            #Check at last because any show_all of a parent widget made after
            # this block would invalidate the effect, showing again the widgets
            vchecklabel.hide()
            self.vcheck.hide()

    def changed_level(self, event):
        "Changed one of the gradient levels"
        self.levlist[0].set_range(0.0, self.levlist[1].get_value() - self.tick)
        for i in range(1, len(self.levlist)-1):
            self.levlist[i].set_range(self.levlist[i-1].get_value() + self.tick,
                                      self.levlist[i+1].get_value() - self.tick)
        self.levlist[len(self.levlist)-1].set_range(
              self.levlist[len(self.levlist)-2].get_value() + self.tick, 90.0)

    def ok_clicked(self, event):
        "Close preferences dialog and save info"
        self.response(True)

    def restore_default(self, event):
        """Restore preferences to default value"""
        self.olines.set_active(bool(self.default['orizzontal lines']))
        self.legend.set_active(bool(self.default['legend']))
        self.effect3d.set_active(bool(self.default['effect-3d']))
        self.showinfo.set_active(bool(self.default['slopeinfo']))
        self.vcheck.set_active(bool(self.default['latestVersionCheck']))
        self.res.set_active(0)
        if self.default['width'] == 1600:
            self.res.set_active(3)
        elif self.default['width'] == 1280:
            self.res.set_active(2)
        elif self.default['width'] == 1024:
            self.res.set_active(1)
        current = 0
        model = self.theme.get_model()
        for text in model:
            if text[0] == self.default['theme']:
                self.theme.set_active(current)
            current += 1
        self.serv.set_active(0)
        if self.default['server'] == 'usgs.net':
            self.serv.set_active(2)
        elif self.default['server'] == 'earthtools.org':
            self.serv.set_active(1)
        self.fdesc.set_label(self.default['font-des 1']+' | '+self.default['font-dim 1'])
        self.fdesc.desc = {
                               "des": self.default['font-des 1'],
                               "typ": self.default['font-typ 1'],
                               "dim": self.default['font-dim 1']
                           }
        self.fgrad.set_label(self.default['font-des g']+' | '+self.default['font-dim g'])
        self.fgrad.desc = {
                               "des": self.default['font-des g'],
                               "typ": self.default['font-typ g'],
                               "dim": self.default['font-dim g']
                           }
        self.ftitle.set_label(self.default['font-des t']+' | '+self.default['font-dim t'])
        self.ftitle.desc = {
                               "des": self.default['font-des t'],
                               "typ": self.default['font-typ t'],
                               "dim": self.default['font-dim t']
                           }

        self.aname.set_text(self.default['authorname'])
        self.amail.set_text(self.default['authormail'])
        colorlist = [self.default["color "+str(i)] for i in range(1, 8)]
        self.colorlist = []
        for color in colorlist:
            components = [int(component) << 8 for component in color[4:-1].split(',')]
            self.colorlist.append(Gdk.Color(*components))
        for i in range(len(colorlist)):
            self.colblist[i].set_color(self.colorlist[i])
        levellist = [self.default["level "+str(i)] for i in range(1, 8)]
        for k in range(len(self.levlist)):
            i = len(self.levlist) - k-1
            self.levlist[i].set_value(float(levellist[i]))

    def font_button_clicked(self, button):
        """If a font button is clicked show a font dialog to change font"""
        dlg = Gtk.FontSelectionDialog(_(u"Select Font"))
        dlg.set_font_name(button.desc["des"]+' '+button.desc["typ"].capitalize()+' '+str(button.desc["dim"]))
        dlg.set_icon_from_file(ICON_FILENAME)
        result = dlg.run()
        if result == Gtk.ResponseType.OK:
            font = Pango.FontDescription(dlg.get_font_name())
            res = str(int(font.get_weight()))
            dlg.destroy()
            if res in FONT_TYP:
                weight = FONT_TYP[res]
            else:
                weight = "normal"
            button.desc = {
                        "des": font.get_family(),
                        "typ": weight,
                        "dim": str(font.get_size()/Pango.SCALE)
                      }
            button.set_label(font.get_family()+' | '+str(font.get_size()/Pango.SCALE))
        dlg.destroy()

    def show_modal(self):
        """Shows the dialog and returns True if the values have to be chenged."""
        return self.run() == 1

    def getconfig(self):
        """Returns selected config options"""
        res = self.res.get_active_text().split(' ')
        levels = []
        for i in range(len(self.levlist)):
            levels.append(self.levlist[i].get_value())
            self.colorlist[i] = self.colblist[i].get_color()
        settings = {
                    'olines': self.olines.get_active(),
                    'theme': self.theme.get_active_text(),
                    'sinfo': self.showinfo.get_active(),
                    'legend': self.legend.get_active(),
                    'vcheck': self.vcheck.get_active(),
                    '3d': self.effect3d.get_active(),
                    'aname': self.aname.get_text(),
                    'amail': self.amail.get_text(),
                    'fdesc': self.fdesc.desc,
                    'ftitle': self.ftitle.desc,
                    'fgrad': self.fgrad.desc,
                    'width': res[0],
                    'height': res[2],
                    'serv': self.serv.get_active_text(),
                    'colors': ['rgb(%d,%d,%d)' % (color.red >> 8, color.green >> 8,
                            color.blue >> 8) for color in self.colorlist],
                    'levels': levels
                   }
        return settings

    def destroy(self, event=None):
        """Destroy current Preferences"""
        Gtk.Dialog.destroy(self)


class Map(Gtk.Dialog):
    """Show map of slopes"""
    def __init__(self, parent, slopename, stringc, savefnct):
        Gtk.Window.__init__(self)

        self.set_size_request(800, 600)  # FIXME:take webpage dimension
        self.set_title(_(u"Map") + " - " + slopename)
        self.set_icon_from_file(ICON_FILENAME)
        self.set_resizable(True)
        self.set_type_hint(Gdk.WindowTypeHint.NORMAL)

        self.savefnct = savefnct

        ctx = WebKit2.WebContext.get_default()
        self.view = WebKit2.WebView.new_with_context(ctx)
        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.add(self.view)

        swframe = Gtk.Frame()
        swframe.add(sw)

        obox = Gtk.HBox()
        obox.pack_start(swframe, True, True, 0)

        bbox = Gtk.HBox()
        button_s = Gtk.Button(stock=Gtk.STOCK_SAVE)
        button_c = Gtk.Button(stock=Gtk.STOCK_CANCEL)

        bbox.pack_end(button_s, False, False, 5)
        bbox.pack_end(button_c, False, False, 5)
        button_s.connect("clicked", self.onsave)
        button_c.connect("clicked", self.cancel)

        box = Gtk.VBox()
        box.pack_start(obox, True, True, 0)
        box.pack_start(bbox, False, False, 5)
        vbox = self.get_content_area()
        vbox.pack_start(box, True, True, 0)
        self.show_all()
        MAP_SCRIPT = ""
        try:
            fid = open(os.path.join(os.path.dirname(__file__),
                                         "../map.html"), 'r')
            for line in fid:
                MAP_SCRIPT += line
            fid.close()
        except IOError:
            print("map.html not loaded\n")
            return
        HTML_MAP = MAP_SCRIPT % (stringc,)
        self.view.load_html(HTML_MAP, "file:///")

    def onsave(self, event):
        """ Save call"""
        self.savefnct(self)

    def cancel(self, event):
        """ Cancel Map dialog"""
        self.destroy()
        
    def on_snapshot_created(self, obj, result, filepath):
        surface = obj.get_snapshot_finish(result)
        pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0,
                        surface.get_width(),
                        surface.get_height())
        fformat = filepath.rsplit('.', 1)[1]

        if fformat.lower() == 'png':
            surface.write_to_png(filepath)
        if fformat.lower() == 'bmp':
            pixbuf.savev(filepath, "bmp", [], [])
        if fformat.lower() == 'jpg':
            pixbuf.savev(filepath, "jpeg", ["quality"], ["100"])

    def saveimage(self, filepath):
        """ Save map image"""
        self.view.get_snapshot(WebKit2.SnapshotRegion.VISIBLE,
                               WebKit2.SnapshotOptions.NONE,
                               None,
                               self.on_snapshot_created, filepath)


class Create_kml(Gtk.Dialog):
    """Create kml routes"""
    MODE = {#_(u'Open Route Service'): 'ORS',
            #_(u'OSRM'): 'OSRM',
            _(u'brouter'): 'BROU',
            _(u'yournavigation'): 'YOURS',
            _(u"Draw on the map"): 'DRAW'}

    def __init__(self, parent, downloadfunc, savefunc):
        Gtk.Window.__init__(self)

        self.set_size_request(640, 480)  # FIXME:take webpage dimension
        self.set_title(_(u"Create Kml"))
        self.set_icon_from_file(ICON_FILENAME)
        self.set_resizable(True)
        self.set_type_hint(Gdk.WindowTypeHint.NORMAL)
        self.downloadfunc = downloadfunc
        self.savefunc = savefunc
        self.content = None
        self.mode = 'BROU'

        ctx = WebKit2.WebContext.get_default()
        self.view = WebKit2.WebView.new_with_context(ctx)
        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_placement(Gtk.CornerType.TOP_LEFT)
        sw.add(self.view)

        store = Gtk.ListStore(str)
        #store.append([_(u'Open Route Service')])
        #store.append([_(u'OSRM')])
        store.append([_(u'brouter')])
        store.append([_(u'yournavigation')])
        store.append([_(u'Draw on the map')])

        treeview = Gtk.TreeView.new_with_model(store)
        treeview.connect("cursor-changed", self.mode_changed)

        renderertext = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Views", renderertext, text=0)
        column.set_sort_column_id(0)
        treeview.append_column(column)

        frame = Gtk.Frame()
        frame.set_label(_(u'Modes'))
        frame.add(treeview)

        swframe = Gtk.Frame()
        swframe.add(sw)
        treeview.set_cursor(0)

        treeview.set_headers_visible(False)
        obox = Gtk.HBox()
        obox.pack_start(frame, False, True, 5)
        obox.pack_start(swframe, True, True, 5)

        bbox = Gtk.HBox()
        button_k = Gtk.Button(stock=Gtk.STOCK_OK)
        button_s = Gtk.Button(stock=Gtk.STOCK_SAVE)
        button_c = Gtk.Button(stock=Gtk.STOCK_CANCEL)
        bbox.pack_end(button_k, False, False, 5)
        bbox.pack_end(button_s, False, False, 5)
        bbox.pack_end(button_c, False, False, 5)
        button_k.connect("clicked", self.import_kml)
        button_s.connect("clicked", self.save_kml)
        button_c.connect("clicked", self.cancel)

        box = Gtk.VBox()
        box.pack_start(obox, True, True, 5)
        box.pack_start(bbox, False, False, 5)
        vbox = self.get_content_area()
        vbox.pack_start(box, True, True, 0)
        self.show_all()
        self.webview_init()

    def webview_init(self):
        """ Check mode and set webview accordingly"""
        if self.mode == 'ORS':
            self.view.load_uri("http://openrouteservice.org/")
        elif self.mode == 'OSRM':
            self.view.load_uri("http://map.project-osrm.org/")
        elif self.mode == 'BROU':
            self.view.load_uri('http://brouter.de/brouter-web/')
        elif self.mode == 'YOURS':
            self.view.load_uri('http://yournavigation.org/')
        elif self.mode == 'DRAW':
            HTML_DRAW = ""
            try:
                fid = open(os.path.join(os.path.dirname(__file__), "../openlayers.html"), 'r')
                for line in fid:
                    HTML_DRAW += line
                fid.close()
            except IOError:
                print("openlayers.html not loaded\n")
                exit(1)
            self.view.load_html(HTML_DRAW.replace("file://./draw_on_map.js", "file://"+os.path.join(os.path.dirname(__file__), "../draw_on_map.js")), "file:///")

    def mode_changed(self, widget):
        """ Change current mode"""
        selection = widget.get_selection()
        if selection is None:
            return
        model, treeiter = selection.get_selected()
        if treeiter is None:
            return
        newmode = self.MODE[model.get_value(treeiter, 0)]
        if newmode != self.mode:
            self.mode = newmode
            self.webview_init()

    def import_kml(self, event):
        """ Import route in CycloGraph"""
        self.download('IMPORT')

    def ors_js_finished(self, obj, result, typ):
        jsresult = self.view.get_title()
        gpxcontent = str(jsresult)
        self.view.run_javascript('document.title=oldtitle;', None, None)
        from xml.sax.saxutils import unescape
        self.content = io.StringIO(unescape(gpxcontent)).read()
        if typ == 'SAVE':
            if not self.content:
                return
            self.savefunc(self.content, self.mode)
        else:
            self.response(True)
        return

    def get_ors(self, typ):
        """ Returns gpx content from ORS service"""
        self.view.run_javascript("oldtitle=document.title;document.title=document.getElementById('gpx').innerHTML", None, self.ors_js_finished, typ)
        return
        
    def osrm_js_finished(self, obj, result, typ):
        jsresult = self.view.get_title()
        gpxcontent = str(jsresult)
        url = gpxcontent.split('\'')
        self.view.run_javascript('document.title=oldtitle;', None, None)
        self.content = self.downloadfunc(url[1]).read().decode('utf-8')
        if typ == 'SAVE':
            if not self.content:
                return
            self.savefunc(self.content, self.mode)
        else:
            self.response(True)
        return
        
    def get_osrm(self, typ):
        """ Returns gpx content from ORSM service"""
        self.view.run_javascript("oldtitle=document.title;document.title=document.getElementsByClassName('text-link')[1].getAttribute('onclick')", None, self.osrm_js_finished, typ)
        return
        
    def brou_js_finished(self, obj, result, typ):
        jsresult = self.view.get_title()
        elemtext = str(jsresult)
        self.view.run_javascript('document.title=oldtitle;', None, None)
        self.content = self.downloadfunc(elemtext).read().decode('utf-8')
        if typ == 'SAVE':
            if not self.content:
                return
            self.savefunc(self.content, self.mode)
        else:
            self.response(True)
        return
        
    def get_brou(self, typ):
        """ Returns kml content from BROU service"""
        self.view.run_javascript("oldtitle=document.title;document.title=$(\".value\").find('a:contains(\"GPX\")')[0].href", None, self.brou_js_finished, typ)
        return
            
    def yours_js_finished(self, obj, result, typ):
        jsresult = self.view.get_title()
        elemtext = str(jsresult)
        text = elemtext.split('href="http://yournavigation.org/?')
        turl = "http://www.yournavigation.org/api/1.0/gosmore.php?format=kml&"
        if len(text) > 1:
            turl += text[1].split("\">")[0]
            turl = turl.replace("&amp;", "&")
        self.view.run_javascript('document.title=oldtitle;', None, None)
        self.content = self.downloadfunc(turl).read().decode('utf-8')
        if typ == 'SAVE':
            if not self.content:
                return
            self.savefunc(self.content, self.mode)
        else:
            self.response(True)
        return
        
    def get_yours(self, typ):
        """ Returns kml content from YOURS service"""
        self.view.run_javascript("oldtitle=document.title;document.title=document.getElementById('feature_info').innerHTML", None, self.yours_js_finished, typ)
        return

    def draw_js_finished(self, obj, result, typ):
        kmlstring = self.view.get_title()
        self.view.run_javascript('document.title=oldtitle;', None, None)
        self.content = io.StringIO(kmlstring).read()
        if typ == 'SAVE':
            if not self.content:
                return
            self.savefunc(self.content, self.mode)
        else:
            self.response(True)
        return
        
    def get_draw(self, typ):
        """ Returns kml content from DRAW mode"""
        self.view.run_javascript("oldtitle=document.title;document.title=createKml()", None, self.draw_js_finished, typ)
        return

    def download(self, typ):
        """ Download selected route"""
        #Reset the content, it will be filled asynchronously
        self.content = None
        if self.mode == 'ORS':
            self.get_ors(typ)
        elif self.mode == 'OSRM':
            self.get_osrm(typ)
        elif self.mode == 'BROU':
            self.get_brou(typ)
        elif self.mode == 'YOURS':
            self.get_yours(typ)
        elif self.mode == 'DRAW':
            self.get_draw(typ)

    def save_kml(self, event):
        """Save selected route to file"""
        self.download('SAVE')

    def cancel(self, event):
        """ Cancel create kml dialog"""
        self.destroy()

    def show_modal(self):
        """Shows the dialog and returns True if the value has to be changed."""
        return self.run() == 1

FONT_TYP = {
            "300": "light",
            "400": "normal",
            "700": "bold",
           }


def preferences(parent, cgpref, defaultpref):
    """ Show Preference dialog"""
    pref = Preferences(parent, cgpref, defaultpref)
    pref_conf = {}
    if pref.show_modal():
        pref_conf = pref.getconfig()
    pref.destroy()
    return pref_conf


def formslopeinfo(parent, slopedata):
    """ Show slope's info dialog"""
    dlg = FormSlopeInfo(parent, slopedata)
    if dlg.show_modal():
        data = dlg.getslopeinfo()
        dlg.destroy()
        return data
    else:
        dlg.destroy()
        return {}


def FileDialog(parent, title, dirname, filename, other, file_types, rw, fd_open, fd_save):
    """ Show file dialog for open or save slopes"""
    if rw == fd_open:
        dlg = Gtk.FileChooserDialog(title, parent, Gtk.FileChooserAction.OPEN,
                                    (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                                     Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
    elif rw == fd_save:
        dlg = Gtk.FileChooserDialog(title, parent, Gtk.FileChooserAction.SAVE,
                                    (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                                     Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
        dlg.set_do_overwrite_confirmation(True)
        if filename:
            dlg.set_current_name(filename)
    for elem in file_types:
        ffilter = Gtk.FileFilter()
        ffilter.set_name(elem[0])
        for pattern in elem[1].split(' '):
            ffilter.add_pattern(pattern)
            ffilter.add_pattern(pattern.upper())
            # print(pattern)
        # print("----")
        dlg.add_filter(ffilter)
    head, tail = os.path.split(dirname)
    dlg.set_current_folder(head)
    if tail:
        dlg.set_current_name(tail)
    response = dlg.run()

    if response == Gtk.ResponseType.OK:
        filename = dlg.get_filename()
        dlg.destroy()
        return str(filename)
    else:
        dlg.destroy()
        return None


class ProgressDialog(Gtk.Dialog):
    """Progress dialog for import Kml function"""
    def __init__(self, title, label, limit):
        GObject.GObject.__init__(self)

        self.set_title(title)
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)

        self.set_size_request(330, 130)
        box = Gtk.VBox()
        self.limit = limit
        self.label = Gtk.Label(label=label)
        self.pbar = Gtk.ProgressBar()
        align = Gtk.Alignment.new(0.5, 0.5, 0.5, 0.5)
        align.show()
        align.add(self.pbar)
        self.pbar.show()
        self.pbar.set_fraction(0.0)
        self.pbar.set_text("0"+" %")

        box.pack_start(self.label, False, False, 10)
        box.pack_start(align, False, False, 5)

        self.wanttoabort = False
        self.connect("response", self.abort)

        carea = self.get_content_area()
        carea.pack_start(box, True, True, 0)

        self.show_all()

    def update(self, value):
        """Update the progress shown and return if user want to abort."""
        self.pbar.set_fraction(value/self.limit)
        self.pbar.set_text(str(value/10)+" %")
        return self.wanttoabort

    def abort(self, dialog, response):
        """When the abort button is pressed this method is called and it updates
        the status of this object to take track of user action"""
        self.wanttoabort = (response in (Gtk.ResponseType.REJECT,
                                         Gtk.ResponseType.DELETE_EVENT))

    def destroy(self):
        """Destroy current ProgressDialog"""
        Gtk.Dialog.destroy(self)


class NumcpsDialog(Gtk.Dialog):
    """ask cps number you want to import"""
    def __init__(self, max_num_cps, start_dist, max_dist, file_ext):
        GObject.GObject.__init__(self)

        self.set_title(_(u"number of checkpoints"))
        self.set_modal(True)
        self.set_destroy_with_parent(True)
        # self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
        self.connect("delete-event", self.destroy)

        self.set_size_request(330, 150)
        box = Gtk.VBox()
        self.notebook = Gtk.Notebook()
        self.notebook.set_show_tabs(False)

        frame = Gtk.Frame()
        vbox_1 = Gtk.VBox()

        label = Gtk.Label(label=_(u"Choose the type of import you want"))
        vbox_1.pack_start(label, False, False, 15)

        hboxr = Gtk.HBox()
        vboxr = Gtk.VBox()
        self.button1 = Gtk.RadioButton.new_with_label_from_widget(None, _(u"Automatic"))
        self.button1.set_active(True)
        vboxr.pack_start(self.button1, False, False, 0)

        self.button2 = Gtk.RadioButton.new_from_widget(self.button1)
        self.button2.set_label(_(u"Select the number of checkpoints"))
        vboxr.pack_start(self.button2, False, False, 0)

        self.button3 = Gtk.RadioButton.new_from_widget(self.button1)
        self.button3.set_label(_(u"Select the distance rate"))
        vboxr.pack_start(self.button3, False, False, 0)

        self.button4 = Gtk.RadioButton.new_from_widget(self.button1)
        self.button4.set_label(_(u"Use every point (discouraged)"))
        vboxr.pack_start(self.button4, False, False, 0)

        hboxr.pack_start(vboxr, False, False, 30)

        hbx = Gtk.HBox()
        self.tick = 0.1
        self.startdist = start_dist
        self.maxdist = max_dist

        self.bstartdist = Gtk.SpinButton()
        self.bstartdist.set_range(start_dist, max_dist)
        self.bstartdist.set_value(start_dist)
        self.bstartdist.set_increments(self.tick, 1)
        self.bstartdist.set_numeric(True)
        self.bstartdist.set_digits(3)
        self.bstartdist.connect("value_changed", self.changed_dist)

        self.benddist = Gtk.SpinButton()
        self.benddist.set_range(start_dist, max_dist)
        self.benddist.set_value(max_dist)
        self.benddist.set_increments(self.tick, 1)
        self.benddist.set_numeric(True)
        self.benddist.set_digits(3)
        self.benddist.connect("value_changed", self.changed_dist)

        hbx.pack_start(Gtk.Label(label=_(u"Start")), False, False, 10)
        hbx.pack_start(self.bstartdist, False, False, 10)
        hbx.pack_start(Gtk.Label(label=_(u"End")), False, False, 10)
        hbx.pack_start(self.benddist, False, False, 10)

        bbox = Gtk.HBox()
        button_c = Gtk.Button(label=_(u"Cancel"))
        button_n = Gtk.Button(label=_(u"Next"))
        bbox.pack_end(button_n, False, False, 5)
        bbox.pack_end(button_c, False, False, 5)
        button_n.connect("clicked", self.next_clicked)
        button_c.connect("clicked", self.destroy)
        vbox_1.pack_end(bbox, False, False, 10)
        vbox_1.pack_end(hbx, False, False, 5)
        vbox_1.pack_end(hboxr, False, False, 5)

        frame.add(vbox_1)
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        self.notebook.append_page(frame, Gtk.Label(label="1"))

        frame = Gtk.Frame()
        label = Gtk.Label(label=_(u"The %s file contains %d points.\nChoose how many will be imported.") % (file_ext, max_num_cps))
        self.gpxnum = Gtk.HScale()
        self.gpxnum.set_range(0, max_num_cps)
        self.gpxnum.set_increments(1, 1)
        self.gpxnum.set_digits(0)
        self.gpxnum.set_size_request(160, 38)
        self.gpxnum.set_value(0)

        box.pack_start(label, False, False, 5)
        box.pack_start(self.gpxnum, False, False, 5)

        bbox = Gtk.HBox()
        button_n = Gtk.Button(label=_(u"Finish"))
        button_c = Gtk.Button(label=_(u"Back"))
        bbox.pack_end(button_n, False, False, 5)
        bbox.pack_end(button_c, False, False, 5)
        button_n.connect("clicked", self.next_clicked)
        button_c.connect("clicked", self.back_clicked)
        box.pack_end(bbox, False, False, 10)

        frame.add(box)
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        self.notebook.append_page(frame, Gtk.Label(label="2"))

        frame = Gtk.Frame()
        boxdist = Gtk.VBox()
        hboxdist = Gtk.HBox()
        selrange = self.benddist.get_value() - self.bstartdist.get_value()
        label = Gtk.Label(label=_(u"The %s file contains a route of %.3f Km.\nChoose what range you want between points.") % (file_ext, selrange))
        self.spingpxdist = Gtk.SpinButton()
        self.spingpxdist.set_range(0, selrange)
        self.spingpxdist.set_value(0)
        self.spingpxdist.set_increments(self.tick, 1)
        self.spingpxdist.set_numeric(True)
        self.spingpxdist.set_digits(3)
        self.spingpxdist.connect("value_changed", self.changed_rangedist)
        self.gpxdist = Gtk.HScale()
        self.gpxdist.set_range(0, selrange)
        self.gpxdist.set_increments(self.tick, 1)
        self.gpxdist.set_digits(3)
        self.gpxdist.set_size_request(160, 38)
        self.gpxdist.set_value(0)
        self.gpxdist.set_draw_value(False)
        self.gpxdist.connect("value_changed", self.changed_rangescaledist)

        hboxdist.pack_start(self.spingpxdist, False, False, 10)
        hboxdist.pack_start(self.gpxdist, False, False, 5)
        boxdist.pack_start(label, False, False, 5)
        boxdist.pack_start(hboxdist, False, False, 15)

        bbox = Gtk.HBox()
        button_n = Gtk.Button(label=_(u"Finish"))
        button_c = Gtk.Button(label=_(u"Back"))
        bbox.pack_end(button_n, False, False, 5)
        bbox.pack_end(button_c, False, False, 5)
        button_n.connect("clicked", self.next_clicked)
        button_c.connect("clicked", self.back_clicked)
        boxdist.pack_end(bbox, False, False, 10)

        frame.add(boxdist)
        frame.set_shadow_type(Gtk.ShadowType.NONE)
        self.notebook.append_page(frame, Gtk.Label(label="3"))

        self.notebook.set_current_page(0)
        self.notebook.show_all()

        carea = self.get_content_area()
        carea.pack_start(self.notebook, True, True, 0)

        self.show_all()

    def changed_dist(self, event):
        "Changed dist"
        self.bstartdist.set_range(self.startdist, self.benddist.get_value() - self.tick)
        self.benddist.set_range(self.bstartdist.get_value() + self.tick, self.maxdist)

    def changed_rangedist(self, event):
        "Changed range dist"
        self.gpxdist.set_value(self.spingpxdist.get_value())

    def changed_rangescaledist(self, event):
        "Changed range dist"
        self.spingpxdist.set_value(self.gpxdist.get_value())

    def next_clicked(self, event):
        "Show next page"
        if self.notebook.get_current_page() == 0:
            if self.button1.get_active():
                self.response(True)
            elif self.button2.get_active():
                self.notebook.set_current_page(1)
                self.notebook.show_all()
            elif self.button3.get_active():
                selrange = self.benddist.get_value() - self.bstartdist.get_value()
                self.spingpxdist.set_range(0, selrange)
                self.spingpxdist.set_value(0)
                self.gpxdist.set_range(0, selrange)
                self.gpxdist.set_value(0)
                self.notebook.set_current_page(2)
                self.notebook.show_all()
            elif self.button4.get_active():
                self.response(True)
        else:
            self.response(True)

    def back_clicked(self, event):
        "Show initial page"
        self.notebook.set_current_page(0)
        self.notebook.show_all()

    def destroy(self, event=None, param=None):
        """Destroy current dialog"""
        self.response(False)
        Gtk.Dialog.destroy(self)


def geterrnoroute(parent):
    """Get an error message explaining that you should have selected one route"""
    mdlg = Gtk.MessageDialog(parent,
            Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING,
            Gtk.ButtonsType.OK, _(u'No route'))
    mdlg.format_secondary_text(_(u"Specify one route first."))
    mdlg.run()
    mdlg.destroy()


def managecperr(parent):
    """Get an error message explaining that you should have inserted altitude and distance"""
    mdlg = Gtk.MessageDialog(parent,
        Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING,
        Gtk.ButtonsType.OK, _("Form incomplete"))
    mdlg.format_secondary_text(_("Distance and altitude are required."))
    mdlg.run()
    mdlg.destroy()


def mapcoorderr(parent):
    """Get an error message explaining that there are no coords in the slope"""
    mdlg = Gtk.MessageDialog(parent,
        Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING,
        Gtk.ButtonsType.OK, _("No coordinates"))
    mdlg.format_secondary_text(_("there aren't coordinates associated with this slope."))
    mdlg.run()
    mdlg.destroy()


def geterrnocp(parent):
    """Get an error message explaining that you should have at least 2 cps to plot"""
    mdlg = Gtk.MessageDialog(parent,
            Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR,
            Gtk.ButtonsType.OK, _(u'Not enough check points'))
    mdlg.format_secondary_text(_(u"""There aren't enougth check points to plot.
 At least two points are required to plot."""))
    mdlg.run()
    mdlg.destroy()


def numcpsdlg(max_num_cps, start_dist, max_dist, file_ext):
    """ask what number of cps in a gpx or tcx files have to be imported"""
    dlg = NumcpsDialog(max_num_cps, start_dist, max_dist, file_ext)
    response = dlg.run()
    if response is False:
        return (-1, 0, start_dist, max_dist)
    if dlg.button1.get_active():
        valstart = dlg.bstartdist.get_value()
        valend = dlg.benddist.get_value()
        dlg.destroy()
        return (0, -1, valstart, valend)
    elif dlg.button2.get_active():
        val = dlg.gpxnum.get_value()
        valstart = dlg.bstartdist.get_value()
        valend = dlg.benddist.get_value()
        dlg.destroy()
        return (0, int(val), valstart, valend)
    elif dlg.button3.get_active():
        val = dlg.gpxdist.get_value()
        valstart = dlg.bstartdist.get_value()
        valend = dlg.benddist.get_value()
        dlg.destroy()
        return (1, val, valstart, valend)
    elif dlg.button4.get_active():
        valstart = dlg.bstartdist.get_value()
        valend = dlg.benddist.get_value()
        dlg.destroy()
        return (0, max_num_cps, valstart, valend)


def assistant_end(parent, value):
    parent.Close()
    return (0, 20)


def save_changes(parent, filename):
    """Show a message if you close a modified and not saved slope"""
    response = None

    text = "<b>"+(_(u"Save changes to %s before closing?") % filename)+"</b>"
    secondary_text = _(u"If you don't save, all your changes will be "
                       "permanently lost.")
    mdlg = Gtk.MessageDialog(parent, Gtk.DialogFlags.DESTROY_WITH_PARENT,
                          Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE, text)
    mdlg.set_title(_(u'Save changes'))
    mdlg.set_markup(text)
    mdlg.format_secondary_text(secondary_text)
    mdlg.add_buttons(_(u'Close without saving'), Gtk.ResponseType.REJECT,
                  Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
                  Gtk.ResponseType.ACCEPT)
    mdlg.set_default_response(Gtk.ResponseType.ACCEPT)
    response = mdlg.run()
    mdlg.destroy()
    if response == Gtk.ResponseType.ACCEPT:
        return 'SAVE'
    if response == Gtk.ResponseType.REJECT:
        return 'DISCARD'
    if response == Gtk.ResponseType.CANCEL:
        return 'CANCEL'
    return response

# vim:sw=4:softtabstop=4:expandtab
