"""GUI related classes."""

import os
import subprocess
import gettext
import codecs
from socket import setdefaulttimeout, timeout
from urllib2 import urlopen, URLError
from thread import start_new_thread
from Tkinter import *
import tkFileDialog as fd
from ScrolledText import ScrolledText

from PIL import Image, ImageTk

from constants import *


setdefaulttimeout(5.0)


class App:

    """Application's main window."""

    def __init__(self, master, config):
        self.master = master
        self.config = config

        self.translatedPark = StringVar()
        self.translatedRwy = StringVar()
        self.translatedPark.set(_('None'))
        self.translatedRwy.set(_('Default'))
#------ Menu ------------------------------------------------------------------
        self.menubar = Menu(self.master)

        self.filemenu = Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label=_('Load'), command=self.configLoad)
        self.filemenu.add_command(label=_('Save as...'),
                                  command=self.configSave)
        self.filemenu.add_separator()
        self.filemenu.add_command(label=_('Save & Quit'),
                                  command=self.SaveAndQuit)
        self.filemenu.add_command(label=_('Quit'), command=self.quit)
        self.menubar.add_cascade(label=_('File'), menu=self.filemenu)

        self.settmenu = Menu(self.menubar, tearoff=0)
        self.settmenu.add_checkbutton(label=_('Show installed airports only'),
                                      variable=self.config.filtredAptList,
                                      command=self.filterAirports)
        self.settmenu.add_command(label=_('Update list of installed airports'),
                                  command=self.updateInstalledAptList)
        self.settmenu.add_separator()
        self.settmenu.add_command(label=_('Preferences'),
                                  command=self.showConfigWindow)
        self.menubar.add_cascade(label=_('Settings'), menu=self.settmenu)

        self.toolsmenu = Menu(self.menubar, tearoff=0)
        self.toolsmenu.add_command(label='METAR',
                                  command=self.showMETARWindow)
        self.menubar.add_cascade(label=_('Tools'), menu=self.toolsmenu)

        self.helpmenu = Menu(self.menubar, tearoff=0)
        self.helpmenu.add_command(label=_('Help'), command=self.showHelpWindow)
        self.helpmenu.add_separator()
        self.helpmenu.add_command(label=_('About'), command=self.about)
        self.menubar.add_cascade(label=_('Help'), menu=self.helpmenu)

        self.master.config(menu=self.menubar)

        self.frame = Frame(self.master)
        self.frame.pack(side='top', fill='both', expand=True)

        self.frame0 = Frame(self.frame, borderwidth=4)
        self.frame0.pack(side='top', fill='x')
#------ Aircraft list ---------------------------------------------------------
        self.frame1 = Frame(self.frame0, borderwidth=8)
        self.frame1.pack(side='left', fill='both', expand=True)

        self.frame11 = Frame(self.frame1, borderwidth=1)
        self.frame11.pack(side='top', fill='both', expand=True)

        self.scrollbar = Scrollbar(self.frame11, orient='vertical')
        self.aircraftList = Listbox(self.frame11, bg=TEXT_BG_COL,
                                    exportselection=0,
                                    yscrollcommand=self.scrollbar.set,
                                    height=14)
        self.scrollbar.config(command=self.aircraftList.yview, takefocus=0)
        self.aircraftList.pack(side='left', fill='both', expand=True)
        self.scrollbar.pack(side='left', fill='y')
        self.aircraftList.see(self.getIndex('a'))
        self.aircraftList.bind('<Button-1>', self.focusAircraftList)

        self.frame12 = Frame(self.frame1, borderwidth=1)
        self.frame12.pack(side='top', fill='x')

        self.aircraftSearch = Entry(self.frame12, bg=TEXT_BG_COL)
        self.aircraftSearch.pack(side='left', fill='x', expand=True)
        self.aircraftSearch.bind('<Return>', self.searchAircrafts)
        self.aircraftSearch.bind('<KP_Enter>', self.searchAircrafts)

        self.aircraftSearchB = Button(self.frame12, text=_('Search'),
                                      command=self.searchAircrafts)
        self.aircraftSearchB.pack(side='left')
#------ Middle panel ----------------------------------------------------------
        self.frame2 = Frame(self.frame0, borderwidth=1, relief='sunken')
        self.frame2.pack(side='left', fill='both')
        # Aircraft
        self.frame21 = Frame(self.frame2, borderwidth=4)
        self.frame21.pack(side='top')

        self.aircraftLabel = Label(self.frame21,
                                   textvariable=self.config.aircraft)
        self.aircraftLabel.pack(side='top')

        self.thumbnail = Label(self.frame21, width=171, height=128)
        self.thumbnail.pack(side='top')
        self.image = self.getImage()
        self.thumbnail.config(image=self.image)
        # Airport, rwy and parking
        self.frame22 = Frame(self.frame2, borderwidth=4)
        self.frame22.pack(side='top', fill='x')
        # First column
        self.frame221 = Frame(self.frame22, borderwidth=4)
        self.frame221.pack(side='left', fill='x')

        self.airport_label = Label(self.frame221, text=_('Airport:'))
        self.airport_label.pack(side='top')

        self.rwy_label = Label(self.frame221, text=_('Rwy:'))
        self.rwy_label.pack(side='top')

        self.park_label = Label(self.frame221, text=_('Parking:'))
        self.park_label.pack(side='top')
        # Second column
        self.frame222 = Frame(self.frame22, borderwidth=4)
        self.frame222.pack(side='left', fill='x')

        self.airportLabel = Label(self.frame222, width=12,
                                  textvariable=self.config.airport,
                                  relief='groove', borderwidth=2)
        self.airportLabel.pack(side='top')
        self.airportLabel.bind('<Button-1>', self.popupCarrier)

        self.rwyLabel = Label(self.frame222, width=12,
                              textvariable=self.translatedRwy,
                              relief='groove', borderwidth=2)
        self.rwyLabel.pack(side='top')
        self.rwyLabel.bind('<Button-1>', self.popupRwy)

        self.parkLabel = Label(self.frame222, width=12,
                               textvariable=self.translatedPark,
                               relief='groove', borderwidth=2)
        self.parkLabel.pack(side='top')
        self.parkLabel.bind('<Button-1>', self.popupPark)
        # AI Scenarios
        self.frame23 = Frame(self.frame2)
        self.frame23.pack(side='top')

        self.scenarios = Label(self.frame23, text=_('Select Scenario'),
                               relief='groove')
        self.scenarios.pack(side='left')
        self.scenarios.bind('<Button-1>', self.popupScenarios)

        self.frame24 = Frame(self.frame2)
        self.frame24.pack(side='top')

        self.scenariosLabel = Label(self.frame24,
                                    text=_('Selected Scenarios:'))
        self.scenariosLabel.pack(side='left')

        self.selectedScenarios = IntVar()
        self.countSelectedScenarios()

        self.scenariosCount = Label(self.frame24,
                               textvariable=self.selectedScenarios)
        self.scenariosCount.pack(side='left')
#------ Airport list ----------------------------------------------------------
        self.frame3 = Frame(self.frame0, borderwidth=8)
        self.frame3.pack(side='left', fill='both', expand=True)

        self.frame31 = Frame(self.frame3, borderwidth=1)
        self.frame31.pack(side='top', fill='both', expand=True)

        self.sAirports = Scrollbar(self.frame31, orient='vertical')
        self.airportList = Listbox(self.frame31, bg=TEXT_BG_COL,
                                   exportselection=0,
                                   yscrollcommand=self.sAirports.set,
                                   height=14)
        self.sAirports.config(command=self.airportList.yview, takefocus=0)
        self.airportList.pack(side='left', fill='both', expand=True)
        self.sAirports.pack(side='left', fill='y')
        self.airportList.see(self.getIndex('p'))
        self.airportList.bind('<Button-1>', self.focusAirportList)

        self.frame32 = Frame(self.frame3, borderwidth=1)
        self.frame32.pack(side='top', fill='x')

        self.airportSearch = Entry(self.frame32, bg=TEXT_BG_COL)
        self.airportSearch.pack(side='left', fill='x', expand=True)
        self.airportSearch.bind('<Return>', self.searchAirports)
        self.airportSearch.bind('<KP_Enter>', self.searchAirports)

        self.airportSearchB = Button(self.frame32, text=_('Search'),
                                     command=self.searchAirports)
        self.airportSearchB.pack(side='left')
#------ Buttons ---------------------------------------------------------------
        self.frame4 = Frame(self.frame, borderwidth=4)
        self.frame4.pack(side='top', fill='x')

        self.frame41 = Frame(self.frame4, borderwidth=4)
        self.frame41.pack(side='left', fill='x')
        # TerraSync
        self.ts = Checkbutton(self.frame4, text="TerraSync",
                              variable=self.config.TS, command=self.runTS)
        self.ts.pack(side='left')

        self.frame42 = Frame(self.frame4, borderwidth=4)
        self.frame42.pack(side='right')
        # Buttons
        self.sq_button = Button(self.frame42, text=_('Save & Quit'),
                                   command=self.SaveAndQuit)
        self.sq_button.pack(side='left')

        self.reset_button = Button(self.frame42, text=_('Reset'), width=10,
                                   command=self.reset)
        self.reset_button.pack(side='left')

        self.run_button = Button(self.frame42, text=_('Run FG'), width=10,
                                 command=self.runFG)
        self.run_button.pack(side='left')
#------ Text window -----------------------------------------------------------
        self.frame5 = Frame(self.frame)
        self.frame5.pack(side='top', fill='both', expand=True)

        self.frame51 = Frame(self.frame5)
        self.frame51.pack(side='left', fill='both', expand=True)

        self.text = ScrolledText(self.frame51, bg=TEXT_BG_COL, wrap='none')
        self.text.pack(side='left', fill='both', expand=True)

#------------------------------------------------------------------------------

        self.default_fg = self.rwyLabel.cget('fg')
        self.default_bg = self.master.cget('bg')
        self.scenarioListOpen = False
        self.mainLoopIsRuning = False
        self.currentCarrier = []
        self.old_rwy = self.config.rwy.get()
        self.old_park = self.config.park.get()
        self.reset(first_run=True)
        self.startLoops()
        self.runTS()

    def about(self):
        """Create 'About' window"""
        try:
            self.aboutWindow.destroy()
        except AttributeError:
            pass

        if _('Translation:') == 'Translation:':
            translator = ''
        else:
            translator = '\n\n\n' + _('Translation:')
        about_text = COPYRIGHT + translator

        self.aboutWindow = Toplevel(borderwidth=4)
        self.aboutWindow.title(_('About'))
        self.aboutWindow.resizable(width=False, height=False)
        self.aboutWindow.transient(self.master)
        self.aboutTitle = Label(self.aboutWindow, font='Helvetica 28 bold',
                                text=NAME)
        self.aboutTitle.pack()
        self.aboutFrame1 = Frame(self.aboutWindow, borderwidth=1,
                                 relief='sunken', padx=8, pady=12)
        self.aboutFrame1.pack()
        self.aboutText = Label(self.aboutFrame1, text=about_text)
        self.aboutText.pack()
        self.aboutFrame2 = Frame(self.aboutWindow, borderwidth=12)
        self.aboutFrame2.pack()
        self.aboutLicense = Button(self.aboutFrame2, text=_('License'),
                                   command=self.aboutShowLicense)
        self.aboutLicense.pack(side='left')
        self.aboutClose = Button(self.aboutFrame2, text=_('Close'),
                                 command=self.aboutWindow.destroy)
        self.aboutClose.pack(side='left')

    def aboutShowLicense(self):
        self.aboutText.configure(text=LICENSE)
        self.aboutTitle.destroy()
        self.aboutLicense.destroy()

    def buildAircraftList(self):
        if self.aircraftList:
            self.aircraftList.delete(0, 'end')

        for i in self.config.aircraft_list:
            self.aircraftList.insert('end', i)

    def buildAirportList(self):
        L = zip(self.config.airport_icao, self.config.airport_name)
        if self.airportList:
            self.airportList.delete(0, 'end')

        for i in L:
            if len(i[0]) == 3:
                i = list(i)
                i[1] = ' ' + i[1]
            try:
                i = '   '.join(i)
            except TypeError:
                i = i[0]
            self.airportList.insert('end', i)

    def commentText(self):
        """Highlight comments in text window."""
        t = self.text
        index = '1.0'
        used_index = [None]
        t.tag_delete('#')

        while index not in used_index:
            comment = t.search('#', index)
            comment = str(comment)

            if comment:
                endline = comment.split('.')[0] + '.end'
                t.tag_add('#', comment, endline)
                t.tag_config('#', foreground=COMMENT_COL)
                used_index.append(index)
                line = comment.split('.')[0]
                index = str(int(line) + 1) + '.0'
            else:
                index = None
        if self.mainLoopIsRuning:
            self.master.after(500, self.commentText)
        else:
            return

    def configLoad(self):
        p = fd.askopenfilename(initialdir=DATA_DIR,
                               filetypes=[(_('Config Files'), '*.fgo')])
        if p:
            text = self.text.get('0.0', 'end')
            self.reset(path=p)
            self.config.write(text=text)
            self.countSelectedScenarios()

    def configSave(self):
        asf = fd.asksaveasfilename
        p = asf(initialdir=DATA_DIR, filetypes=[(_('Config Files'), '*.fgo')])
        if p:
            try:
                if p[-4:] != '.fgo':
                    p += '.fgo'
            except TypeError:
                pass
            t = self.text.get('0.0', 'end')
            self.config.write(text=t, path=p)

    def countSelectedScenarios(self):
        if self.config.scenario.get():
            s = self.config.scenario.get().split()
            self.selectedScenarios.set(len(s))
        else:
            self.selectedScenarios.set(0)

    def filterAirports(self):
        """Update airportList.

        Apply filter to airportList if self.config.filtredAptList is True.

        """
        self.config.updateAptLists()
        self.buildAirportList()
        self.airportList.see(self.getIndex('p'))
        self.airportList.select_set(self.getIndex('p'))

    def focusAircraftList(self, event):
        self.aircraftList.focus_set()

    def focusAirportList(self, event):
        self.airportList.focus_set()

    def getAircraft(self):
        """Get aircraftList current selection and return aircraft name."""
        index = self.aircraftList.curselection()
        if index:
            return self.aircraftList.get(index)

        aircraft = self.aircraftList.get(ACTIVE)
        if not aircraft:
            aircraft = 'None'
        return aircraft

    def getAirport(self):
        """Get airportList current selection and return airport ICAO."""
        index = self.airportList.curselection()
        if index:
            return self.airportList.get(index).split()[0]
        try:
            return self.airportList.get(ACTIVE).split()[0]
        except IndexError:
            return self.config.airport.get()

    def getImage(self):
        """Find thumbnail in aircraft directory."""
        try:
            name = self.config.aircraft.get()
            index = self.config.aircraft_list.index(name)
            path = os.path.join(self.config.aircraft_path[index],
                                'thumbnail.jpg')
            image = ImageTk.PhotoImage(Image.open(path))
        except:
            image = ImageTk.PhotoImage(Image.open(THUMBNAIL))
        return image

    def getIndex(self, type_):
        """Get aircraft name ('a') or airport ICAO ('p')
        and return its index."""
        if type_ == 'a':
            name = self.config.aircraft.get()
            try:
                return self.config.aircraft_list.index(name)
            except ValueError:
                try:
                    return self.config.aircraft_list.index(DEFAULT_AIRCRAFT)
                except ValueError:
                    return 0
        if type_ == 'p':
            name = self.config.airport.get()
            try:
                return self.config.airport_icao.index(name)
            except ValueError:
                try:
                    return self.config.airport_icao.index(DEFAULT_AIRPORT)
                except ValueError:
                    return 0

    def popupCarrier(self, event):
        """Make pop up menu."""
        popup = Menu(tearoff=0)
        popup.add_command(label=_('None'), command=self.resetCarrier)
        for i in self.config.carrier_list:
            popup.add_command(label=i[0],
                              command=lambda i=i: self.setCarrier(i))
        popup.tk_popup(event.x_root, event.y_root, 0)

    def popupPark(self, event):
        """Make pop up menu."""
        popup = Menu(tearoff=0)
        if self.config.airport.get() != 'None':
            popup.add_command(label=_('None'),
                              command=lambda: self.config.park.set('None'))
            count = 1
            for i in self.read_airport_data(self.config.airport.get(), 'park'):
                #  Cut menu
                if count % 20:
                    popup.add_command(label=i,
                                   command=lambda i=i: self.config.park.set(i))
                else:
                    popup.add_command(label=i,
                                   command=lambda i=i: self.config.park.set(i),
                                   columnbreak=1)
                count += 1
        else:
            L = self.currentCarrier[1:-1]
            for i in L:
                popup.add_command(label=i,
                                  command=lambda i=i: self.config.park.set(i))

        popup.tk_popup(event.x_root, event.y_root, 0)

    def popupRwy(self, event):
        """Make pop up menu."""
        if self.config.airport.get() != 'None':
            popup = Menu(tearoff=0)
            popup.add_command(label=_('Default'),
                              command=lambda: self.config.rwy.set('Default'))
            for i in self.read_airport_data(self.config.airport.get(), 'rwy'):
                popup.add_command(label=i, command=lambda i=i:
                                  self.config.rwy.set(i))
            popup.tk_popup(event.x_root, event.y_root, 0)

    def popupScenarios(self, event):
        """Make pop up list."""
        if not self.scenarioListOpen:
            self.scenarioListOpen = True
            self.scenarioList = Toplevel(borderwidth=1, relief='raised')
            self.scenarioList.overrideredirect(True)
            self.scenarioList.geometry('+%d+%d' % (event.x_root, event.y_root))

            frame = Frame(self.scenarioList)
            frame.pack(side='top')

            popupScrollbar = Scrollbar(frame, orient='vertical')
            self.popup = Listbox(frame, bg=TEXT_BG_COL, exportselection=0,
                                 selectmode=MULTIPLE,
                                 yscrollcommand=popupScrollbar.set)
            popupScrollbar.config(command=self.popup.yview, takefocus=0)
            self.popup.pack(side='left')
            popupScrollbar.pack(side='left', fill='y')
            self.popup.bind('<Button-3>', self.scenarioDescription)
            self.popup.bind('<Button-2>', self.popupScenariosClose)

            frame1 = Frame(self.scenarioList)
            frame1.pack(side='top', fill='x')

            button = Button(frame1, text=_('OK'),
                            command=self.popupScenariosClose)
            button.pack(fill='x')

            for i in self.config.scenario_list:
                self.popup.insert('end', i)

            self.popupScenariosSelect()

    def popupScenariosClose(self, event=None):

        try:
            self.descriptionWindow.destroy()
        except AttributeError:
            pass

        L = []
        for i in self.popup.curselection():
            L.append(self.config.scenario_list[int(i)])
        self.config.scenario.set(' '.join(L))
        self.scenarioList.destroy()
        self.countSelectedScenarios()
        self.scenarioListOpen = False

    def popupScenariosSelect(self):
        L = list(self.config.scenario.get().split())
        for i in L:
            if i in self.config.scenario_list:
                self.popup.selection_set(self.config.scenario_list.index(i))

    def quit(self):
        """Quit application."""
        try:
            os.kill(self.TerraSync.pid, 9)
        except AttributeError:
            pass
        self.master.quit()

#    def read_airport_data(self, icao, type_):
#        """Get runway or parking names."""
#        res = []
#        # If airport data source is set to: From scenery...
#        if self.config.apt_data_source.get():
#            paths = []
#            L = self.config.FG_scenery.get().split(':')
#            for path in L:
#                paths.append(os.path.join(path, AIRPORTS_DIR))
#
#            for path in paths:
#                for i in range(3):
#                    path = os.path.join(path, icao[i])
#                if os.path.exists(path):
#                    files = os.listdir(path)
#                    # Runway
#                    if type_ == 'rwy':
#                        threshold = '.'.join([icao, 'threshold.xml'])
#                        for f in files:
#                            file_path = os.path.join(path, f)
#                            if f == threshold and not res:
#                                res = self.read_threshold(file_path)
#                    # Parking
#                    else:
#                        parking = '.'.join([icao, 'parking.xml'])
#                        groundnet = '.'.join([icao, 'groundnet.xml'])
#                        for f in files:
#                            file_path = os.path.join(path, f)
#                            if f == parking or f == groundnet and not res:
#                                res = self.read_parking(file_path)
#        # If airport data source is set to: Standard...
#        else:
#            path = os.path.join(self.config.ai_path, AIRPORTS_DIR)
#            if os.path.exists(path):
#                # Runway
#                if type_ == 'rwy':
#                    index = self.getIndex('p')
#                    rwy = self.config.airport_rwy[index]
#                    for i in rwy:
#                        res.append(i)
#                        # Compute other end of the runway.
#                        if not i.startswith('H'):
#                            number = int(i[:2])
#                            if number <= 36 and number > 18:
#                                prefix = str(number - 18)
#                            elif number > 0 and number <= 18:
#                                prefix = str(number + 18)
#                            suffix = ''
#                            if i.endswith('L'):
#                                suffix = 'R'
#                            elif i.endswith('R'):
#                                suffix = 'L'
#                            elif i.endswith('C'):
#                                suffix = 'C'
#                            res.append(prefix + suffix)
#                # Parking
#                else:
#                    dirs = os.listdir(path)
#                    if icao in dirs:
#                        path = os.path.join(path, icao)
#                        file_path = os.path.join(path, 'parking.xml')
#                        if os.path.exists(file_path):
#                            res = self.read_parking(file_path)
#
#        return res

    def read_airport_data(self, icao, type_):
        """Get runway or parking names.

        type_ should be: 'rwy' or 'park'

        """
        res = []
        if type_ == 'rwy':
            path = os.path.join(self.config.ai_path, AIRPORTS_DIR)
            if os.path.exists(path):
                # Runway
                if type_ == 'rwy':
                    index = self.getIndex('p')
                    rwy = self.config.airport_rwy[index]
                    for i in rwy:
                        res.append(i)
                        # Compute other end of the runway.
                        if not i.startswith('H'):
                            number = int(i[:2])
                            if number <= 36 and number > 18:
                                prefix = str(number - 18)
                            elif number > 0 and number <= 18:
                                prefix = str(number + 18)
                            suffix = ''
                            if i.endswith('L'):
                                suffix = 'R'
                            elif i.endswith('R'):
                                suffix = 'L'
                            elif i.endswith('C'):
                                suffix = 'C'
                            res.append(prefix + suffix)
        else:
            # If airport data source is set to: From scenery...
            if self.config.apt_data_source.get():
                paths = []
                L = self.config.FG_scenery.get().split(':')
                for path in L:
                    paths.append(os.path.join(path, AIRPORTS_DIR))

                for path in paths:
                    for i in range(3):
                        path = os.path.join(path, icao[i])
                    if os.path.exists(path):
                        files = os.listdir(path)
                        parking = '.'.join([icao, 'parking.xml'])
                        groundnet = '.'.join([icao, 'groundnet.xml'])
                        for f in files:
                            file_path = os.path.join(path, f)
                            if f == parking or f == groundnet and not res:
                                res = self.read_parking(file_path)
            # If airport data source is set to: Standard...
            else:
                path = os.path.join(self.config.ai_path, AIRPORTS_DIR)
                if os.path.exists(path):
                    dirs = os.listdir(path)
                    if icao in dirs:
                        path = os.path.join(path, icao)
                        file_path = os.path.join(path, 'parking.xml')
                        if os.path.exists(file_path):
                            res = self.read_parking(file_path)

        return res

    def read_parking(self, xml_file):
        """Read parking positions from XML file."""
        res = []
        fin = open(xml_file)

        for line in fin:
            s_line = line.strip().split()

            if s_line:
                data = s_line[0]

                if data.lower() == '</parkinglist>':
                    fin.close()
                    # Remove doubles.
                    res = list(set(res))
                    res.sort()
                    return res

                if 'name=' in data.lower():
                    name = line.split('"')
                    entry = name[1]
                elif 'number=' in data.lower():
                    data = data.split('"')
                    if data[1]:
                        entry = ''.join([entry, data[1]])
                        res.append(entry)

        fin.close()
        # Remove doubles.
        res = list(set(res))
        res.sort()
        return res

    def read_scenario(self, scenario):
        """Read description from given scenario."""
        L = []
        flag = False
        file_name = scenario + '.xml'
        path = os.path.join(self.config.ai_path, file_name)
        fin = codecs.open(path, encoding='utf-8')

        for line in fin:
            line = line.strip()

            if '<description>' in line.lower():
                L.append(line[13:])
                flag = True
            elif '</description>' in line.lower():
                L.append(line[:-14])
                flag = False
            elif flag:
                L.append(line)

        return '\n'.join(L)

#    def read_threshold(self, xml_file):
#        """Read runway information from XML file."""
#        res = []
#        fin = open(xml_file)
#
#        for line in fin:
#            line = line.strip()
#            if '<rwy>' in line.lower():
#                line = line[5:-6]
#                res.append(line)
#
#        fin.close()
#        return res

    def reset(self, event=None, path=None, first_run=False):
        """Reset data"""
        # Don't call config.update() at application's initialization
        # as config object is updated at its creation anyway.
        if not first_run:
            self.config.update(path)
        self.buildAircraftList()
        self.buildAirportList()
        self.aircraftSearch.delete(0, 'end')
        self.airportSearch.delete(0, 'end')
        self.airportList.see(self.getIndex('p'))
        self.airportList.select_set(self.getIndex('p'))
        self.aircraftList.see(self.getIndex('a'))
        self.aircraftList.select_set(self.getIndex('a'))
        self.image = self.getImage()
        self.thumbnail.config(image=self.image)
        self.resetText()
        # Update selected carrier
        if self.config.carrier.get() != 'None':

            for i in range(len(self.config.carrier_list)):
                if self.config.carrier.get() == self.config.carrier_list[i][0]:
                    self.currentCarrier = self.config.carrier_list[i]

            self.setCarrier(self.currentCarrier)
        else:
            self.resetCarrier()

    def resetCarrier(self):
        if self.config.carrier.get() != 'None':
            self.config.park.set('None')
        self.config.carrier.set('None')
        self.airport_label.config(text=_('Airport:'))
        self.airportLabel.config(textvariable=self.config.airport,
                                 bg=self.default_bg)
        self.rwy_label.config(fg=self.default_fg)
        self.rwyLabel.config(fg=self.default_fg)
        self.config.airport.set(self.getAirport())
        self.image = self.getImage()
        self.thumbnail.config(image=self.image)

        try:
            c = self.config.scenario.get().split()
            if self.currentCarrier[-1] in c:
                c.pop(c.index(self.currentCarrier[-1]))
                self.config.scenario.set(' '.join(c))
        except IndexError:
            pass

        self.countSelectedScenarios()

    def resetText(self):
        t = self.text
        t.delete('1.0', 'end')
        t.insert('end', self.config.text)

    def runFG(self):
        t = self.text.get('0.0', 'end')
        self.config.write(text=t)
        path = self.config.FG_bin.get()
        options = [path]
        FG_working_dir = HOME_DIR
        # Add TerraSync protocol.
        if self.config.TS.get():
            arg = ('--atlas=socket,out,5,localhost,%s,udp' %
                   self.config.TS_port.get())
            options.append(arg)

        config_in = open(CONFIG)
        # Parse config file.
        for line in config_in:
            line = line.strip()

            if line.startswith('--'):
                options.append(line)

            if line.startswith('AI_SCENARIOS='):
                L = line[13:].split()
                for scenario in L:
                    options.append('--ai-scenario=' + scenario)
            # Obsolete keyword, should be removed in the future.
            elif line[:9] == 'HOME_DIR=':
                if os.path.exists(line[9:]):
                    FG_working_dir = line[9:]
            elif line[:15] == 'FG_WORKING_DIR=':
                if os.path.exists(line[15:]):
                    FG_working_dir = line[15:]
            elif line[:7] == 'FG_BIN=':
                options[0] = line[7:]

        config_in.close()
        print '\n' + '=' * 80 + '\n'
        print _('Starting %s with following options:') % options[0]

        for i in options[1:]:
            print '\t%s' % i
        print '\n' + '-' * 80 + '\n'

        try:
            launcher = FGLauncher(self.master, options, FG_working_dir)
            self.stopLoops()
            self.frame.wait_window(launcher.top)
            self.startLoops()
        except OSError:
            self.runFGErrorMessage()

    def runFGErrorMessage(self):
        error = Toplevel(borderwidth=12)
        error.transient(self.master)
        error.title(_('Error'))

        title = Label(error, font=('Helvetica', 18, 'bold'),
                      text=_('Unable to run FlightGear!'))
        title.pack(fill='x')

        msg = Label(error, text=_('Please make sure that paths: FG_BIN '
        'and FG_ROOT\nin "Preferences" window are '
        'pointing to right directories.') + '\n')
        msg.pack(fill='x')

        button = Button(error, text=_('Close'),
                        command=error.destroy)
        button.pack()

    def runTS(self):
        if self.config.TS_port.get()\
           and self.config.TS_scenery.get()\
           and os.path.exists(self.config.TS_bin.get()):
            self.ts.configure(state='normal')
        else:
            self.ts.configure(state='disabled')

        if self.config.TS.get() and self.ts.cget('state') == 'normal':
            options = '%s -p %s -S -d %s' % (self.config.TS_bin.get(),
                                             self.config.TS_port.get(),
                                             self.config.TS_scenery.get())
            self.TerraSync = subprocess.Popen(options.split())
            self.TerraSync.poll()
            print '-' * 80
            print _('Starting TerraSync with following command:')
            print options
            print '-' * 80
        else:
            try:
                os.kill(self.TerraSync.pid, 15)
                print '-' * 80
                print _('Stopping TerraSync')
                print '-' * 80
            except AttributeError:
                return

    def SaveAndQuit(self):
        """Save options to file and quit."""
        try:
            os.kill(self.TerraSync.pid, 9)
        except AttributeError:
            pass
        # Save window resolution.
        geometry = self.master.geometry().split('+')[0]
        self.config.window_geometry.set(geometry)

        t = self.text.get('0.0', 'end')
        self.config.write(text=t)
        self.master.quit()

    def scenarioDescription(self, event):
        """Make pop up window showing AI scenario description."""
        index = self.popup.nearest(event.y)
        try:
            name = self.config.scenario_list[index]
        except IndexError:
            return
        text = self.read_scenario(name)

        try:
            self.descriptionWindow.destroy()
        except AttributeError:
            pass

        if text:
            text = name.center(80) + '\n' + ('-' * 80) + '\n' + text
            pos = self.master.geometry().split('+')
            self.descriptionWindow = Toplevel(borderwidth=1, relief='raised')
            self.descriptionWindow.overrideredirect(True)
            self.descriptionWindow.geometry('+%d+%d' % (int(pos[1]) + 10,
                                                        int(pos[2]) + 30))
            self.descriptionText = Label(self.descriptionWindow, justify=LEFT,
                                         text=text, bg=MESSAGE_BG_COL)
            self.descriptionText.pack()
            self.descriptionText.bind('<Button-3>',
                                      self.scenarioDescriptionClose)

    def scenarioDescriptionClose(self, event):
        self.descriptionWindow.destroy()

    def searchAircrafts(self, event=None):
        entry = self.aircraftSearch.get().lower()

        if entry != '':
            self.buildAircraftList()
            L = []

            for i in range(self.aircraftList.size()):

                if entry in self.aircraftList.get(i).lower():
                    L.append(self.aircraftList.get(i))

            self.aircraftList.delete(0, 'end')
            for i in L:
                self.aircraftList.insert('end', i)

        else:
            self.buildAircraftList()

        if self.aircraftList.get(0):
            self.currentAircraft = ('0', )

    def searchAirports(self, event=None):
        entry = self.airportSearch.get()

        if entry != '':
            self.buildAirportList()
            L = []

            if entry.isupper():
                for i in range(self.airportList.size()):
                    if entry == self.airportList.get(i)[:len(entry)]:
                        L.append(self.airportList.get(i))
            else:
                entry = entry.lower()
                for i in range(self.airportList.size()):
                    if entry in self.airportList.get(i).lower():
                        L.append(self.airportList.get(i))

            self.airportList.delete(0, 'end')
            for i in L:
                self.airportList.insert('end', i)

        else:
            self.buildAirportList()

        if self.airportList.get(0):
            self.currentAirport = ('0', )

    def setCarrier(self, L):
        old_scenario = ''
        if self.currentCarrier:
            old_scenario = self.currentCarrier[-1]
        if self.config.carrier.get() != L[0]:
            self.config.park.set('None')
        self.config.carrier.set(L[0])
        self.currentCarrier = L
        self.airport_label.config(text=_('Carrier:'))
        self.airportLabel.config(textvariable=self.config.carrier,
                                 bg=CARRIER_COL)
        self.rwy_label.config(fg=GRAYED_OUT_COL)
        self.rwyLabel.config(fg=GRAYED_OUT_COL)
        self.config.rwy.set('Default')
        self.config.airport.set('None')
        scenario = self.currentCarrier[-1]

        if scenario not in self.config.scenario.get().split():
            if old_scenario:
                L = self.config.scenario.get().split()
                if old_scenario in L:
                    L.pop(L.index(old_scenario))
                    self.config.scenario.set(' '.join(L))

            c = (self.config.scenario.get(), scenario)
            self.config.scenario.set(' '.join(c))

        self.countSelectedScenarios()

    def showConfigWindow(self):
        text = self.text.get('0.0', 'end')
        self.configWindow = ConfigWindow(self.master, self.config, text)
        # Wait for window to close and reset data if Save&Quit button was used.
        self.frame.wait_window(self.configWindow.top)
        if self.configWindow.reset_flag:
            self.reset()

    def showHelpWindow(self):
        """Display help window."""
        try:
            self.helpWindow.destroy()
        except AttributeError:
            pass
        # Find currently used language.
        language = self.config.language.get()
        if language:
            lang_code = language
        else:
            lang_code = gettext.translation(MESSAGES, LOCALE_DIR).info()['language']
        path = os.path.join(HELP_DIR, lang_code)
        if not os.path.isfile(path):
            lang_code = 'en'
            path = os.path.join(HELP_DIR, lang_code)

        readme_in = codecs.open(path, encoding='utf-8')
        text = readme_in.read()
        readme_in.close()

        self.helpWindow = Toplevel(self.master)
        self.helpWindow.title(_('Help'))
        self.helpWindow.transient(self.master)

        self.helpText = ScrolledText(self.helpWindow, bg=TEXT_BG_COL)
        self.helpText.pack(side='left', fill='both', expand=True)
        self.helpText.insert('end', text)
        self.helpText.configure(state='disabled')

    def showMETARWindow(self, event=None):
        try:
            self.metar.quit()
        except AttributeError:
            pass

        self.metar = Metar(self.master, self.config, MESSAGE_BG_COL)

    def startLoops(self):
        """Activate all loops."""
        self.mainLoopIsRuning = True
        self.commentText()
        self.updateAircraft()
        self.updateAirport()
#        print '***** LOOPS ACTIVATED *****'

    def stopLoops(self):
        """Stop all loops."""
        self.mainLoopIsRuning = False
#        print '***** LOOPS DEACTIVATED *****'

    def updateAircraft(self):
        """Update aircraft selection."""
        now = self.getAircraft()

        if now != self.config.aircraft.get():
            self.config.aircraft.set(now)
            self.image = self.getImage()
            self.thumbnail.config(image=self.image)

        if self.mainLoopIsRuning:
            self.master.after(100, self.updateAircraft)
        else:
            return

    def updateAirport(self):
        """Update airport selection."""
        if self.config.airport.get() != 'None':
            selected_apt = self.getAirport()

            if selected_apt != self.config.airport.get():
                self.config.park.set('None')
                self.config.rwy.set('Default')
                self.config.airport.set(selected_apt)

            # Let user select only one option: rwy or park position.
            if self.config.rwy.get() != 'Default':
                if self.config.rwy.get() != self.old_rwy:
                    self.old_rwy = self.config.rwy.get()
                    self.config.park.set('None')
            if self.config.park.get() != 'None':
                if self.config.park.get() != self.old_park:
                    self.old_park = self.config.park.get()
                    self.config.rwy.set('Default')
            else:
                self.old_park = self.config.park.get()
                self.old_rwy = self.config.rwy.get()

            if self.old_rwy != 'Default' and self.old_park != 'None':
                self.old_rwy = 'Default'

        # Translate rwy and park buttons
        self.translatedPark.set(_(self.config.park.get()))
        self.translatedRwy.set(_(self.config.rwy.get()))

        if self.mainLoopIsRuning:
            self.master.after(250, self.updateAirport)
        else:
            return

    def updateInstalledAptList(self):
        """Rebuild installed airports list."""
        if self.config.filtredAptList.get():
            self.config.makeInstalledAptList()
            self.filterAirports()


class ConfigWindow:

    """Display preferences window."""

    def __init__(self, master, config, text):
        self.master = master
        self.config = config
        self.text = text

        self.apt_data_source = StringVar()
        self.FG_bin = StringVar()
        self.FG_root = StringVar()
        self.FG_scenery = StringVar()
        self.FG_working_dir = StringVar()
        self.language = StringVar()
        self.TS_bin = StringVar()
        self.TS_port = StringVar()
        self.TS_scenery = StringVar()

        if self.config.apt_data_source.get():
            self.apt_data_source.set(_('Scenery'))
        else:
            self.apt_data_source.set(_('Default'))
        self.FG_bin.set(self.config.FG_bin.get())
        self.FG_root.set(self.config.FG_root.get())
        self.FG_scenery.set(self.config.FG_scenery.get())
        self.FG_working_dir.set(self.config.FG_working_dir.get())
        if self.config.language.get():
            self.language.set(self.config.language.get())
        else:
            self.language.set('-')
        self.TS_bin.set(self.config.TS_bin.get())
        if self.config.TS_port.get():
            self.TS_port.set(self.config.TS_port.get())
        else:
            self.defaultPort()
        self.TS_scenery.set(self.config.TS_scenery.get())

        self.reset_flag = False

# -----------------------------------------------------------------------------

        self.top = Toplevel(self.master)
        self.top.grab_set()  # Focus input on that window.
        self.top.title(_('Preferences'))
        self.top.resizable(width=False, height=False)
        self.top.transient(self.master)

        self.main = Frame(self.top, borderwidth=0)
        self.main.pack(side='top', padx=12)

        self.frame = Frame(self.main, borderwidth=1, relief='sunken')
        self.frame.pack(side='top')
# ----- Tabs ------------------------------------------------------------------
        self.tabs = Frame(self.frame)
        self.tabs.pack(side='top', fill='x')

        self.tabFG = Button(self.tabs, text=_('FlightGear settings'),
                            borderwidth=1, relief='ridge',
                            command=self.showFGSettings)
        self.tabFG.pack(side='left')

        self.tabTS = Button(self.tabs, text=_('TerraSync settings'),
                            borderwidth=1, relief='ridge',
                            command=self.showTSSettings)
        self.tabTS.pack(side='left')

        self.tabMisc = Button(self.tabs, text=_('Miscellaneous'),
                            borderwidth=1, relief='ridge',
                            command=self.showMiscSettings)
        self.tabMisc.pack(side='left')
# ----- Main content ----------------------------------------------------------
        # Here is placed content from: widgetFG, widgetTS, and widgetMics.
        self.frame = Frame(self.frame, borderwidth=1, relief='raised')
        self.frame.pack(side='top', fill='x')
# ----- Buttons ---------------------------------------------------------------
        self.frame_Buttons = Frame(self.main, borderwidth=12)
        self.frame_Buttons.pack(side='bottom')

        self.frame_save_button = Frame(self.frame_Buttons, borderwidth=4)
        self.frame_save_button.pack(side='left')

        self.save = Button(self.frame_save_button, text=_('Save settings'),
                           command=self.saveAndQuit)
        self.save.pack(side='left')

        self.frame_close_button = Frame(self.frame_Buttons, borderwidth=4)
        self.frame_close_button.pack(side='right')

        self.close = Button(self.frame_close_button, text=_('Cancel'),
                            command=self.quit)
        self.close.pack(side='left')
# -----------------------------------------------------------------------------
        # Show FG settings tab by default.
        self.showFGSettings()

    def cleanUpWidgets(self):
        """Destroy active widget."""
        try:
            self.frame_FG.destroy()
        except AttributeError:
            pass
        try:
            self.frame_TS.destroy()
        except AttributeError:
            pass
        try:
            self.frame_misc.destroy()
        except AttributeError:
            pass

    def defaultPort(self):
        self.TS_port.set('5501')

    def findFG_bin(self):
        try:
            p = fd.askopenfilename(parent=self.top,
                                   initialdir=HOME_DIR,
                                   title=_('Path to executable file:'))
            if p:
                self.FG_bin.set(p)

        except TclError:
            return

    def findFG_root(self):
        try:
            p = fd.askdirectory(parent=self.top,
                                initialdir=HOME_DIR,
                                title='FG_ROOT:')
            if p:
                self.FG_root.set(p)

        except TclError:
            return

    def findFG_scenery(self):
        try:
            p = fd.askdirectory(parent=self.top,
                                initialdir=HOME_DIR,
                                title='FG_SCENERY:')
            if p:
                self.FG_scenery.set(p)

        except TclError:
            return

    def findFgWorkingDir(self):
        try:
            p = fd.askdirectory(parent=self.top,
                                initialdir=HOME_DIR,
                                title=_('Working directory (optional):'))
            if p:
                self.FG_working_dir.set(p)

        except TclError:
            return

    def findTS_bin(self):
        try:
            p = fd.askopenfilename(parent=self.top,
                                   initialdir=HOME_DIR,
                                   title=_('Path to executable file:'))
            if p:
                self.TS_bin.set(p)

        except TclError:
            return

    def findTS_scenery(self):
        try:
            p = fd.askdirectory(parent=self.top,
                                initialdir=HOME_DIR,
                                title=_('Scenery path:'))
            if p:
                self.TS_scenery.set(p)

        except TclError:
            return

    def getLanguages(self):
        """Walk through locale directory and return list of
        supported languages based on directory names."""
        res = []
        for d in os.listdir(LOCALE_DIR):
            if os.path.isdir(os.path.join(LOCALE_DIR, d)):
                res.append(d)
        res.sort()
        res = ['-'] + res
        return res

    def quit(self):
        """Quit without saving."""
        self.top.destroy()

    def resetTabs(self):
        """Reset tabs."""
        self.tabFG.configure(borderwidth=2, relief='ridge')
        self.tabTS.configure(borderwidth=2, relief='ridge')
        self.tabMisc.configure(borderwidth=2, relief='ridge')

    def saveAndQuit(self):
        if self.apt_data_source.get() == _('Scenery').decode('utf-8'):
            self.config.apt_data_source.set(1)
        else:
            self.config.apt_data_source.set(0)

        self.config.FG_bin.set(self.FG_bin.get())
        self.config.FG_root.set(self.FG_root.get())
        self.config.FG_scenery.set(self.FG_scenery.get())
        self.config.FG_working_dir.set(self.FG_working_dir.get())
        if self.language.get() == '-':
            self.config.language.set('')
        else:
            self.config.language.set(self.language.get())
        self.config.TS_bin.set(self.TS_bin.get())
        self.config.TS_port.set(self.TS_port.get())
        self.config.TS_scenery.set(self.TS_scenery.get())
        self.config.write(text=self.text)
        self.reset_flag = True
        self.top.destroy()

    def showFGSettings(self):
        if self.tabFG.cget('relief') != 'raised':
            self.resetTabs()
            self.tabFG.configure(borderwidth=1, relief='raised')
            self.cleanUpWidgets()
            self.widgetFG()

    def showTSSettings(self):
        if self.tabTS.cget('relief') != 'raised':
            self.resetTabs()
            self.tabTS.configure(borderwidth=1, relief='raised')
            self.cleanUpWidgets()
            self.widgetTS()

    def showMiscSettings(self):
        if self.tabMisc.cget('relief') != 'raised':
            self.resetTabs()
            self.tabMisc.configure(borderwidth=1, relief='raised')
            self.cleanUpWidgets()
            self.widgetMisc()

    def widgetFG(self):
        """FlightGear settings widget."""
        self.frame_FG = Frame(self.frame, borderwidth=8)
        self.frame_FG.pack(side='top')

        self.FG_label = Label(self.frame_FG, text=_('FlightGear settings'))
        self.FG_label.pack(side='top')

        # FG_BIN
        self.frame_FG_1 = Frame(self.frame_FG, borderwidth=4)
        self.frame_FG_1.pack(side='top')

        self.frame_FG_11 = Frame(self.frame_FG_1)
        self.frame_FG_11.pack(side='top', fill='x')

        self.FG_binLabel = Label(self.frame_FG_11,
                                 text=_('Path to executable file:'))
        self.FG_binLabel.pack(side='left')

        self.frame_FG_12 = Frame(self.frame_FG_1)
        self.frame_FG_12.pack(side='top')

        self.FG_binEntry = Entry(self.frame_FG_12, bg=TEXT_BG_COL,
                                 width=50, textvariable=self.FG_bin)
        self.FG_binEntry.pack(side='left')

        self.FG_binFind = Button(self.frame_FG_12, text=_('Find'),
                                 command=self.findFG_bin)
        self.FG_binFind.pack(side='left')
        # FG_ROOT
        self.frame_FG_2 = Frame(self.frame_FG, borderwidth=4)
        self.frame_FG_2.pack(side='top')

        self.frame_FG_21 = Frame(self.frame_FG_2)
        self.frame_FG_21.pack(side='top', fill='x')

        self.FG_rootLabel = Label(self.frame_FG_21, text='FG_ROOT:')
        self.FG_rootLabel.pack(side='left')

        self.frame_FG_22 = Frame(self.frame_FG_2)
        self.frame_FG_22.pack(side='top')

        self.FG_rootEntry = Entry(self.frame_FG_22, bg=TEXT_BG_COL,
                                  width=50, textvariable=self.FG_root)
        self.FG_rootEntry.pack(side='left')

        self.FG_rootFind = Button(self.frame_FG_22, text=_('Find'),
                                  command=self.findFG_root)
        self.FG_rootFind.pack(side='left')
        # FG_SCENERY
        self.frame_FG_3 = Frame(self.frame_FG, borderwidth=4)
        self.frame_FG_3.pack(side='top')

        self.frame_FG_31 = Frame(self.frame_FG_3)
        self.frame_FG_31.pack(side='top', fill='x')

        self.FG_sceneryLabel = Label(self.frame_FG_31, text='FG_SCENERY:')
        self.FG_sceneryLabel.pack(side='left')

        self.frame_FG_32 = Frame(self.frame_FG_3)
        self.frame_FG_32.pack(side='top')

        self.FG_sceneryEntry = Entry(self.frame_FG_32, bg=TEXT_BG_COL,
                                  width=50, textvariable=self.FG_scenery)
        self.FG_sceneryEntry.pack(side='left')

        self.FG_sceneryFind = Button(self.frame_FG_32, text=_('Find'),
                                     command=self.findFG_scenery)
        self.FG_sceneryFind.pack(side='left')

        # FG working directory
        self.frame_FG_4 = Frame(self.frame_FG, borderwidth=4)
        self.frame_FG_4.pack(side='top')

        self.frame_FG_41 = Frame(self.frame_FG_4)
        self.frame_FG_41.pack(side='top', fill='x')

        self.FG_working_dirLabel = Label(self.frame_FG_41,
                                       text=_('Working directory (optional):'))
        self.FG_working_dirLabel.pack(side='left')

        self.frame_FG_42 = Frame(self.frame_FG_4)
        self.frame_FG_42.pack(side='top')

        self.FG_working_dirEntry = Entry(self.frame_FG_42, bg=TEXT_BG_COL,
                               width=50, textvariable=self.FG_working_dir)
        self.FG_working_dirEntry.pack(side='left')

        self.FG_working_dirFind = Button(self.frame_FG_42, text=_('Find'),
                               command=self.findFgWorkingDir)
        self.FG_working_dirFind.pack(side='left')

    def widgetTS(self):
        """TerraSync settings widget."""
        self.frame_TS = Frame(self.frame, borderwidth=8)
        self.frame_TS.pack(side='top')

        self.TS_label = Label(self.frame_TS, text=_('TerraSync settings'))
        self.TS_label.pack(side='top')

        # TS_BIN
        self.frame_TS_1 = Frame(self.frame_TS, borderwidth=4)
        self.frame_TS_1.pack(side='top')

        self.frame_TS_11 = Frame(self.frame_TS_1)
        self.frame_TS_11.pack(side='top', fill='x')

        self.TS_binLabel = Label(self.frame_TS_11,
                                 text=_('Path to executable file:'))
        self.TS_binLabel.pack(side='left')

        self.frame_TS_12 = Frame(self.frame_TS_1)
        self.frame_TS_12.pack(side='top')

        self.TS_binEntry = Entry(self.frame_TS_12, bg=TEXT_BG_COL,
                                 width=50, textvariable=self.TS_bin)
        self.TS_binEntry.pack(side='left')

        self.TS_binFind = Button(self.frame_TS_12, text=_('Find'),
                                 command=self.findTS_bin)
        self.TS_binFind.pack(side='left')
        # TS scenery
        self.frame_TS_2 = Frame(self.frame_TS, borderwidth=4)
        self.frame_TS_2.pack(side='top')

        self.frame_TS_21 = Frame(self.frame_TS_2)
        self.frame_TS_21.pack(side='top', fill='x')

        self.TS_sceneryLabel = Label(self.frame_TS_21, text=_('Scenery path:'))
        self.TS_sceneryLabel.pack(side='left')

        self.frame_TS_22 = Frame(self.frame_TS_2)
        self.frame_TS_22.pack(side='top')

        self.TS_sceneryEntry = Entry(self.frame_TS_22, bg=TEXT_BG_COL,
                                     width=50, textvariable=self.TS_scenery)
        self.TS_sceneryEntry.pack(side='left')

        self.TS_sceneryFind = Button(self.frame_TS_22, text=_('Find'),
                                     command=self.findTS_scenery)
        self.TS_sceneryFind.pack(side='left')
        # TS port
        self.frame_TS_3 = Frame(self.frame_TS, borderwidth=4)
        self.frame_TS_3.pack(side='top', fill='x')

        self.frame_TS_31 = Frame(self.frame_TS_3)
        self.frame_TS_31.pack(side='top', fill='x')

        self.TS_portLabel = Label(self.frame_TS_31, text=_('Port:'))
        self.TS_portLabel.pack(side='left')

        self.frame_TS_32 = Frame(self.frame_TS_3)
        self.frame_TS_32.pack(side='top', fill='x')

        self.TS_portEntry = Entry(self.frame_TS_32, bg=TEXT_BG_COL,
                                  width=6, textvariable=self.TS_port)
        self.TS_portEntry.pack(side='left')

        self.TS_portDefault = Button(self.frame_TS_32, text=_('Default'),
                                     command=self.defaultPort)
        self.TS_portDefault.pack(side='left')

    def widgetMisc(self):
        """Miscellaneous settings widget."""
        self.frame_misc = Frame(self.frame, borderwidth=8)
        self.frame_misc.pack(side='top', fill='x')

        self.misc_label = Label(self.frame_misc, text=_('Miscellaneous'))
        self.misc_label.pack(side='top', fill='x')

        # Language menu
        self.frame_misc_1 = Frame(self.frame_misc, borderwidth=4)
        self.frame_misc_1.pack(side='top', fill='x')

        self.frame_misc_11 = Frame(self.frame_misc_1)
        self.frame_misc_11.pack(side='left', fill='x')

        self.lang_label = Label(self.frame_misc_11, text=_('Change language:'))
        self.lang_label.pack(side='left')

        self.langMenu = OptionMenu(self.frame_misc_11, self.language,
                                   *self.getLanguages())
        self.langMenu.pack(side='left')
        # Apt source menu
        self.frame_misc_12 = Frame(self.frame_misc_1)
        self.frame_misc_12.pack(side='right', fill='x')

        self.apt_label = Label(self.frame_misc_12,
                               text=_('Airport data source:'))
        self.apt_label.pack(side='left')

        self.aptMenu = OptionMenu(self.frame_misc_12, self.apt_data_source,
                                  *(_('Default'), _('Scenery')))
        self.aptMenu.pack(side='left')
        # Rebuild apt button
        self.frame_misc_2 = Frame(self.frame_misc, borderwidth=4)
        self.frame_misc_2.pack(side='top', fill='x')

        self.frame_misc_21 = Frame(self.frame_misc_2)
        self.frame_misc_21.pack(side='top', fill='x')

        self.rebuildApt = Button(self.frame_misc_21,
                                 text=_('Rebuild Airport Database'),
                                 command=self.config.rebuildApt)
        self.rebuildApt.pack(side='top', fill='x')


class FGLauncher:

    """Launch FG and create new window that indicates that FG is running."""

    def __init__(self, master, options, FG_working_dir):
        self.master = master
        self.options = options
        self.FG_working_dir = FG_working_dir

        self._window()
        self.master.update()
        self._runFG()

    def quit(self):
        """Clean up data and destroy the window."""
        del self.master
        del self.options
        self.top.destroy()

    def _doNotQuit(self):
        """Dumb method to override window's close button."""
        return

    def _checkIfFGHasQuit(self):
        if self.process.poll() is None:
            self.master.after(1000, self._checkIfFGHasQuit)
        else:
            self.quit()

    def _runFG(self):
        self.process = subprocess.Popen(self.options, cwd=self.FG_working_dir)
        self._checkIfFGHasQuit()

    def _window(self):
        message = _('FlightGear is running...')
        self.top = Toplevel(self.master)
        self.top.protocol("WM_DELETE_WINDOW", self._doNotQuit)
        self.top.resizable(width=False, height=False)
        self.top.grab_set()  # Focus input on that window.
        self.top.transient(self.master)

        self.label = Label(self.top, borderwidth=20,
                           text=message, font='Helvetica 16')
        self.label.pack()


class Metar:

    """Simple widget to display METAR reports from weather.noaa.gov/."""

    def __init__(self, master, config, background):
        self.master = master
        self.background = background

        self.icao = config.airport
        self.apt_path = config.apt_path
        self.metar_path = config.metar_path

        self.decoded = IntVar()
        self.nearest_station = StringVar()
        self.report = StringVar()

        self.decoded.set(0)
        self.nearest_station.set('')
        self.report.set('')

        self.metar_list = config.readMetarDat()
        self.apt_dict = config.readCoord()

#------- Main Window ----------------------------------------------------------
        self.top = Toplevel(self.master, borderwidth=4)
        self.top.transient(self.master)
        self.top.resizable(width=False, height=False)
        # Override window close button.
        self.top.protocol("WM_DELETE_WINDOW", self.quit)
        self.top.title('METAR')

        self.frame1 = Frame(self.top)
        self.frame1.pack(side='top', fill='x')
#------ Decoded check button --------------------------------------------------
        self.decoded_cb = Checkbutton(self.frame1, text=_('Decoded'),
                                     variable=self.decoded)
        self.decoded_cb.pack(side='left')

        self.frame2 = Frame(self.top, borderwidth=2, relief='sunken')
        self.frame2.pack(side='top')
#------ Report window ---------------------------------------------------------
        self.text = Label(self.frame2, width=0, height=0, bg=self.background,
                          textvariable=self.report)
        self.text.pack(side='top')
        self.text.bind('<Button-1>', self.fetch)
#------------------------------------------------------------------------------
        self._welcomeMessage()

    def fetch(self, event=None):
        """Fetch METAR report."""
        self.text.unbind('<Button-1>')
        self.report.set(_('Fetching report...'))
        # Wait until text is updated.
        self.master.update()
        start_new_thread(self._fetch, ())

    def quit(self):
        """Clean up data and destroy this window."""
        del self.metar_list
        del self.apt_path
        del self.metar_path
        del self.icao
        del self.master
        del self.background
        del self.apt_dict

        self.top.destroy()

    def _bindButton(self):
        try:
            self.text.bind('<Button-1>', self.fetch)
        except TclError:
            return

    def _compare_pos(self, a, b):
        lat = (abs(a[0] - b[0]))
        lon = (abs(a[1] - b[1]))
        return lat + lon

    def _fetch(self):
        """Fetch METAR report."""
        if self.nearest_station.get() and \
           self.nearest_station.get() == self._nearestMetar(self.icao.get()):
            icao = self.nearest_station.get()
        else:
            icao = self.icao.get()

        if icao == 'None':
            return

        self.nearest_station.set('')
        if self._isOnMetarList(icao):
            if self.decoded.get():
                decoded = 'decoded'
            else:
                decoded = 'stations'

            url = \
            ('http://weather.noaa.gov/pub/data/observations/metar/%s/%s.TXT' %
                                                               (decoded, icao))
            try:
                report = urlopen(url).read()
#                print ' DOWNLOAD HAS BEEN COMPLETED! '.center(40, '*')
                report = report.strip()
            # FIXME
            # The timeout exception seems not to be caught on my machine (with
            # Debian Squeeze and Python 2.5 or 2.6) if internet connection is
            # disabled. Have no idea what is wrong?!
            except timeout:
                report = _('Unable to download data.')
            except URLError:
                report = _('Unable to download data.')
            self.report.set(report)
            self._setLabelSize()
        else:
            self.nearest_station.set(self._nearestMetar(icao))
            self.fetch()
        # Bind button to text widget after some delay to avoid double clicking.
        self.master.after(1000, self._bindButton)

    def _isOnMetarList(self, icao):
        """Return True if selected airport is on METAR station list."""
        if icao in self.metar_list:
            return True

    def _nearestMetar(self, icao):
        """Find nearest METAR station"""
        nearest_metar = ''
        nearest_dist = 999
        try:
            airport_pos = self.apt_dict[icao]
        except KeyError:
            return ''
        for icao in self.metar_list:
            try:
                metar_pos = self.apt_dict[icao]
                distance = self._compare_pos(airport_pos, metar_pos)
                if distance < nearest_dist:
                    nearest_metar = icao
                    nearest_dist = distance
            except KeyError:
                pass
        return nearest_metar

    def _setLabelSize(self):
        """Adjust label dimensions according to text size."""
        report = self.report.get()
        report = report.split('\n')
        width = -1
        for line in report:
            if len(line) > width:
                width = len(line)
        height = len(report) + 2
        try:
            self.text.configure(width=width, height=height)
        except TclError:
            pass

    def _welcomeMessage(self):
        """Show message at widget's initialization"""
        # Disable widget in case of IOError.
        if self.metar_list[0] == 'IOError':
            self.text.unbind('<Button-1>')
            message = ' ' * 30
        else:
            message = _('Click here to download the METAR report\n'
                        'for selected (or nearest) airport.')

        self.report.set(message)
        self._setLabelSize()
