Index: src/mlx/flight.py
===================================================================
--- src/mlx/flight.py	(revision 31)
+++ src/mlx/flight.py	(revision 59)
@@ -34,5 +34,5 @@
         self.flareTimeFromFS = False
         self.entranceExam = False
-        self.zfw = 50000
+        self.zfw = None
 
         self.options = Options()
Index: src/mlx/fs.py
===================================================================
--- src/mlx/fs.py	(revision 27)
+++ src/mlx/fs.py	(revision 59)
@@ -4,4 +4,6 @@
 
 import const
+
+import fsuipc
 
 #-------------------------------------------------------------------------------
@@ -13,4 +15,8 @@
         simulator of the given type."""
         print "fs.ConnectionListener.connected, fsType:", fsType, ", descriptor:", descriptor
+
+    def connectionFailed(self):
+        """Called when the connection could not be established."""
+        print "fs.ConnectionListener.connectionFailed"        
 
     def disconnected(self):
@@ -34,6 +40,5 @@
     assert type in [const.SIM_MSFS9, const.SIM_MSFSX], \
            "Only MS Flight Simulator 2004 and X are supported"
-    import fsuipc
-    return fsuipc.Simulator(connectionListener)
+    return fsuipc.Simulator(connectionListener, connectAttempts = 3)
 
 #-------------------------------------------------------------------------------
Index: src/mlx/fsuipc.py
===================================================================
--- src/mlx/fsuipc.py	(revision 51)
+++ src/mlx/fsuipc.py	(revision 59)
@@ -59,5 +59,12 @@
             return None
 
+    # The number of times a read is attempted
     NUM_READATTEMPTS = 3
+
+    # The number of connection attempts
+    NUM_CONNECTATTEMPTS = 3
+
+    # The interval between successive connect attempts
+    CONNECT_INTERVAL = 0.25
 
     @staticmethod
@@ -172,13 +179,16 @@
             return cmp(self._nextFire, other._nextFire)
 
-    def __init__(self, connectionListener):
+    def __init__(self, connectionListener,
+                 connectAttempts = -1, connectInterval = 0.2):
         """Construct the handler with the given connection listener."""
         threading.Thread.__init__(self)
 
         self._connectionListener = connectionListener
+        self._connectAttempts = connectAttempts
+        self._connectInterval = connectInterval
 
         self._requestCondition = threading.Condition()
         self._connectionRequested = False
-        self._connected = False
+        self._connected = False        
 
         self._requests = []
@@ -266,7 +276,13 @@
         """Disconnect from the flight simulator."""
         with self._requestCondition:
+            self._requests = []
             if self._connectionRequested:
-                self._connectionRequested = False
+                self._connectionRequested = False                
                 self._requestCondition.notify()
+
+    def clearRequests(self):
+        """Clear the outstanding one-shot requests."""
+        with self._requestCondition:
+            self._requests = []
 
     def run(self):
@@ -286,5 +302,5 @@
                 self._requestCondition.wait()
             
-    def _connect(self):
+    def _connect(self, autoReconnection = False):
         """Try to connect to the flight simulator via FSUIPC
 
@@ -292,18 +308,30 @@
         not due to no longer requested.
         """
+        attempts = 0
         while self._connectionRequested:
             try:
+                attempts += 1
                 pyuipc.open(pyuipc.SIM_ANY)
                 description = "(FSUIPC version: 0x%04x, library version: 0x%04x, FS version: %d)" % \
                     (pyuipc.fsuipc_version, pyuipc.lib_version, 
                      pyuipc.fs_version)
-                Handler._callSafe(lambda:     
-                                  self._connectionListener.connected(const.SIM_MSFS9, 
-                                                                     description))
+                if not autoReconnection:
+                    Handler._callSafe(lambda:     
+                                      self._connectionListener.connected(const.SIM_MSFS9, 
+                                                                         description))
                 self._connected = True
                 return True
             except Exception, e:
                 print "fsuipc.Handler._connect: connection failed: " + str(e)
-                time.sleep(0.1)
+                if attempts<self.NUM_CONNECTATTEMPTS:
+                    time.sleep(self.CONNECT_INTERVAL)
+                else:
+                    self._connectionRequested = False
+                    if autoReconnection:
+                        Handler._callSafe(lambda:     
+                                          self._connectionListener.disconnected())
+                    else:
+                        Handler._callSafe(lambda:     
+                                          self._connectionListener.connectionFailed())
 
         return False
@@ -337,19 +365,6 @@
         if self._connected:
             pyuipc.close()
-            Handler._callSafe(lambda: self._connectionListener.disconnected())
             self._connected = False
-
-    def _failRequests(self, request):
-        """Fail the outstanding, single-shot requuests."""
-        request.fail()
-        with self._requestCondition:
-            for request in self._requests:
-                try:
-                    self._requestCondition.release()
-                    request.fail()
-                finally:
-                    self._requestCondition.acquire()
-            self._requests = []        
-
+            
     def _processRequest(self, request, time):
         """Process the given request. 
@@ -377,7 +392,8 @@
 
             if needReconnect:
+                with self._requestCondition:
+                    self._requests.insert(0, request)
                 self._disconnect()
-                self._failRequests(request)
-                self._connect()
+                self._connect(autoReconnection = True)
         finally:
             self._requestCondition.acquire()
@@ -437,5 +453,6 @@
                    (0x0580, "d") ]           # Heading
 
-    def __init__(self, connectionListener):
+    def __init__(self, connectionListener, connectAttempts = -1,
+                 connectInterval = 0.2):
         """Construct the simulator.
         
@@ -460,5 +477,7 @@
         self._aircraft = None
 
-        self._handler = Handler(connectionListener)
+        self._handler = Handler(connectionListener,
+                                connectAttempts = connectAttempts,
+                                connectInterval = connectInterval)
         self._handler.start()
 
@@ -484,5 +503,17 @@
         self._aircraftModel = None
         self._handler.connect()
-        self._startDefaultNormal()
+        if self._normalRequestID is None:
+            self._startDefaultNormal()
+
+    def reconnect(self):
+        """Initiate a reconnection to the simulator.
+
+        It does not reset already set up data, just calls connect() on the
+        handler."""
+        self._handler.connect()
+
+    def requestZFW(self, callback):
+        """Send a request for the ZFW."""
+        self._handler.requestRead([(0x3bfc, "d")], self._handleZFW, extra = callback)
                                                             
     def startMonitoring(self):
@@ -683,4 +714,9 @@
         else:
             self._addFlareRate(data[2])
+
+    def _handleZFW(self, data, callback):
+        """Callback for a ZFW retrieval request."""
+        zfw = data[0] * const.LBSTOKG / 256.0
+        callback(zfw)
                                                   
 #------------------------------------------------------------------------------
Index: src/mlx/gui/flight.py
===================================================================
--- src/mlx/gui/flight.py	(revision 58)
+++ src/mlx/gui/flight.py	(revision 59)
@@ -494,4 +494,27 @@
 #-----------------------------------------------------------------------------
 
+class PayloadPage(Page):
+    """Page to allow setting up the payload."""
+    def __init__(self, wizard):
+        """Construct the page."""
+        help = "The briefing contains the weights below.\n" \
+               "Setup the cargo weight and check if the simulator\n" \
+               "reports the expected Zero Fuel Weight."
+        super(PayloadPage, self).__init__(wizard, "Payload", help)
+
+        button = gtk.Button("_Query ZFW")
+        button.connect("clicked", self._zfwRequested)
+        self.setMainWidget(button)
+
+    def _zfwRequested(self, button):
+        """Called when the ZFW is requested from the simulator."""
+        self._wizard.gui.simulator.requestZFW(self._handleZFW)
+
+    def _handleZFW(self, zfw):
+        """Called when the ZFW value is retrieved."""
+        print "ZFW", zfw
+
+#-----------------------------------------------------------------------------
+
 class Wizard(gtk.VBox):
     """The flight wizard."""
@@ -509,4 +532,5 @@
         self._pages.append(GateSelectionPage(self))
         self._pages.append(ConnectPage(self))
+        self._pages.append(PayloadPage(self))
 
         maxWidth = 0
@@ -523,17 +547,5 @@
         self.set_size_request(maxWidth, maxHeight)
 
-        self._fleet = None
-        self._fleetCallback = None
-        self._updatePlaneCallback = None
-        
-        self._loginResult = None
-        self._bookedFlight = None
-        self._departureGate = "-"
-
-        self._logger = Logger(output = gui)
-        self._flight = None
-        self._simulator = None
-        
-        self.setCurrentPage(0)
+        self._initialize()
         
     @property
@@ -567,4 +579,28 @@
         self._pages[self._currentPage].grabDefault()
 
+    def connected(self, fsType, descriptor):
+        """Called when the connection could be made to the simulator."""
+        self.nextPage()
+
+    def connectionFailed(self):
+        """Called when the connection could not be made to the simulator."""
+        self._initialize()
+
+    def disconnected(self):
+        """Called when we have disconnected from the simulator."""
+        self._initialize()
+
+    def _initialize(self):
+        """Initialize the wizard."""
+        self._fleet = None
+        self._fleetCallback = None
+        self._updatePlaneCallback = None
+        
+        self._loginResult = None
+        self._bookedFlight = None
+        self._departureGate = "-"
+
+        self.setCurrentPage(0)
+        
     def _getFleet(self, callback, force = False):
         """Get the fleet, if needed.
@@ -634,20 +670,5 @@
     def _connectSimulator(self):
         """Connect to the simulator."""
-        self._logger.reset()
-        self._flight = Flight(self.gui._logger, self.gui)
-
-        self._flight.aircraftType = self._bookedFlight.aircraftType
-        aircraft = self._flight.aircraft = Aircraft.create(self._flight)
-        self._flight.aircraft._checkers.append(self.gui)
-        
-        self._flight.cruiseAltitude = -1        
-        self._flight.zfw = -1
-
-        if self._simulator is None:
-            self._simulator = fs.createSimulator(const.SIM_MSFS9, self.gui)
-
-        self._flight.simulator = self._simulator 
-        self._simulator.connect(aircraft)
-        #self._simulator.startMonitoring()
+        self.gui.connectSimulator(self._bookedFlight.aircraftType)
     
 #-----------------------------------------------------------------------------
Index: src/mlx/gui/gui.py
===================================================================
--- src/mlx/gui/gui.py	(revision 51)
+++ src/mlx/gui/gui.py	(revision 59)
@@ -43,8 +43,10 @@
         self.config = config
         self._connecting = False
+        self._reconnecting = False
         self._connected = False
         self._logger = logger.Logger(output = self)
         self._flight = None
         self._simulator = None
+        self._monitoring = False
 
         self._stdioLock = threading.Lock()
@@ -127,4 +129,9 @@
                                       else gdk.WATCH)
 
+    @property
+    def simulator(self):
+        """Get the simulator used by us."""
+        return self._simulator
+        
     def run(self):
         """Run the GUI."""
@@ -140,6 +147,8 @@
         if self._flight is not None:
             simulator = self._flight.simulator
-            simulator.stopMonitoring()
-            simulator.disconnect()            
+            if self._monitoring:
+                simulator.stopMonitoring()
+                self._monitoring = False
+            simulator.disconnect()                        
 
     def connected(self, fsType, descriptor):
@@ -147,6 +156,46 @@
         self._connected = True
         self._logger.untimedMessage("Connected to the simulator %s" % (descriptor,))
-        gobject.idle_add(self._statusbar.updateConnection,
-                         self._connecting, self._connected)
+        gobject.idle_add(self._handleConnected, fsType, descriptor)
+
+    def _handleConnected(self, fsType, descriptor):
+        """Called when the connection to the simulator has succeeded."""
+        self._statusbar.updateConnection(self._connecting, self._connected)
+        self.endBusy()
+        if not self._reconnecting:
+            self._wizard.connected(fsType, descriptor)
+        self._reconnecting = False
+
+    def connectionFailed(self):
+        """Called when the connection failed."""
+        self._logger.untimedMessage("Connection to the simulator failed")
+        gobject.idle_add(self._connectionFailed)
+
+    def _connectionFailed(self):
+        """Called when the connection failed."""
+        self.endBusy()
+        self._statusbar.updateConnection(self._connecting, self._connected)
+
+        dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                   message_format =
+                                   "Cannot connect to the simulator.",
+                                   parent = self._mainWindow)
+        dialog.format_secondary_markup("Rectify the situation, and press <b>Try again</b> "
+                                       "to try the connection again, " 
+                                       "or <b>Cancel</b> to cancel the flight.")
+        
+        dialog.add_button("_Cancel", 0)
+        dialog.add_button("_Try again", 1)
+        dialog.set_default_response(1)
+        
+        result = dialog.run()
+        dialog.hide()
+        if result == 1:
+            self.beginBusy("Connecting to the simulator.")
+            self._simulator.reconnect()
+        else:
+            self._connecting = False
+            self._reconnecting = False
+            self._statusbar.updateConnection(self._connecting, self._connected)
+            self._wizard.connectionFailed()
         
     def disconnected(self):
@@ -154,6 +203,36 @@
         self._connected = False
         self._logger.untimedMessage("Disconnected from the simulator")
-        gobject.idle_add(self._statusbar.updateConnection,
-                         self._connecting, self._connected)
+
+        gobject.idle_add(self._disconnected)
+
+    def _disconnected(self):
+        """Called when we have disconnected from the simulator unexpectedly."""        
+        self._statusbar.updateConnection(self._connecting, self._connected)
+
+        dialog = gtk.MessageDialog(type = MESSAGETYPE_ERROR,
+                                   message_format =
+                                   "The connection to the simulator failed unexpectedly.",
+                                   parent = self._mainWindow)
+        dialog.format_secondary_markup("If the simulator has crashed, restart it "
+                                       "and restore your flight as much as possible "
+                                       "to the state it was in before the crash.\n"
+                                       "Then press <b>Reconnect</b> to reconnect.\n\n"
+                                       "If you want to cancel the flight, press <b>Cancel</b>.")
+
+        dialog.add_button("_Cancel", 0)
+        dialog.add_button("_Reconnect", 1)
+        dialog.set_default_response(1)
+
+        result = dialog.run()
+        dialog.hide()
+        if result == 1:
+            self.beginBusy("Connecting to the simulator.")
+            self._reconnecting = True
+            self._simulator.reconnect()
+        else:
+            self._connecting = False
+            self._reconnecting = False
+            self._statusbar.updateConnection(self._connecting, self._connected)
+            self._wizard.disconnected()
 
     def write(self, msg):
@@ -285,32 +364,44 @@
             self._stdioAfterNewLine = False
 
+    def connectSimulator(self, aircraftType):
+        """Connect to the simulator for the first time."""
+        self._logger.reset()
+
+        self._flight = flight.Flight(self._logger, self)
+        self._flight.aircraftType = aircraftType
+        self._flight.aircraft = acft.Aircraft.create(self._flight)
+        self._flight.aircraft._checkers.append(self)
+        
+        if self._simulator is None:
+            self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
+
+        self._flight.simulator = self._simulator
+
+        self.beginBusy("Connecting to the simulator...")
+        self._statusbar.updateConnection(self._connecting, self._connected)
+
+        self._connecting = True
+        self._simulator.connect(self._flight.aircraft)        
+
     def _connectToggled(self, button):
         """Callback for the connection button."""
         if self._connectButton.get_active():
-            self._logger.reset()
-            self._flight = flight.Flight(self._logger, self)
-
             acftListModel = self._acftList.get_model()
-            self._flight.aircraftType = \
-                acftListModel[self._acftList.get_active()][1]
-            self._flight.aircraft = acft.Aircraft.create(self._flight)
-            self._flight.aircraft._checkers.append(self)
-
+            self.connectSimulator(acftListModel[self._acftList.get_active()][1])
+            
             self._flight.cruiseAltitude = self._flSpinButton.get_value_as_int() * 100
 
             self._flight.zfw = self._zfwSpinButton.get_value_as_int()
-
-            if self._simulator is None:
-                self._simulator = fs.createSimulator(const.SIM_MSFS9, self)
-
-            self._flight.simulator = self._simulator
-
-            self._connecting = True
-            self._simulator.connect(self._flight.aircraft)
+            
             self._simulator.startMonitoring()
+            self._monitoring = True
         else:
             self.resetFlightStatus()
             self._connecting = False
+            self._connected = False
+
             self._simulator.stopMonitoring()
+            self._monitoring = False
+
             self._simulator.disconnect()
             self._flight = None
Index: src/mlx/gui/statusbar.py
===================================================================
--- src/mlx/gui/statusbar.py	(revision 49)
+++ src/mlx/gui/statusbar.py	(revision 59)
@@ -87,5 +87,5 @@
     
     def _drawConnState(self, connStateArea, eventOrContext):
-        """Draw the connection state."""
+        """Draw the connection state."""        
         context = eventOrContext if pygobject else connStateArea.window.cairo_create()
 
Index: src/mlx/pyuipc_sim.py
===================================================================
--- src/mlx/pyuipc_sim.py	(revision 57)
+++ src/mlx/pyuipc_sim.py	(revision 59)
@@ -637,7 +637,21 @@
 #------------------------------------------------------------------------------
 
+failOpen = False
+
+opened = False
+
+#------------------------------------------------------------------------------
+
 def open(request):
     """Open the connection."""
-    return True
+    global opened
+    if failOpen:
+        raise FSUIPCException(ERR_NOFS)
+    elif opened:
+        raise FSUIPCException(ERR_OPEN)
+    else:
+        time.sleep(0.5)
+        opened = True
+        return True
 
 #------------------------------------------------------------------------------
@@ -645,11 +659,18 @@
 def prepare_data(pattern, forRead = True):
     """Prepare the given pattern for reading and/or writing."""
-    return pattern
-
+    if opened:
+        return pattern
+    else:
+        raise FSUIPCException(ERR_OPEN)
+        
 #------------------------------------------------------------------------------
 
 def read(data):
     """Read the given data."""
-    return [values.read(offset) for (offset, type) in data]
+    print "opened", opened
+    if opened:
+        return [values.read(offset) for (offset, type) in data]
+    else:
+        raise FSUIPCException(ERR_OPEN)
             
 #------------------------------------------------------------------------------
@@ -657,6 +678,9 @@
 def write(data):
     """Write the given data."""
-    for (offset, type, value) in data:
-        values.write(offset, value)
+    if opened:
+        for (offset, type, value) in data:
+            values.write(offset, value)
+    else:
+        raise FSUIPCException(ERR_OPEN)
             
 #------------------------------------------------------------------------------
@@ -664,5 +688,6 @@
 def close():
     """Close the connection."""
-    pass
+    global opened
+    opened = False
 
 #------------------------------------------------------------------------------
@@ -673,4 +698,6 @@
 CALL_WRITE=2
 CALL_CLOSE=3
+CALL_FAILOPEN=4
+CALL_QUIT = 99
 
 RESULT_RETURNED=1
@@ -715,4 +742,12 @@
                     elif call==CALL_WRITE:
                         result = write(args[0])
+                    elif call==CALL_CLOSE:
+                        global opened
+                        opened = False
+                        result = None
+                    elif call==CALL_FAILOPEN:
+                        global failOpen
+                        failOpen = args[0]
+                        result = None
                     else:
                         break
@@ -753,4 +788,17 @@
         """Write the given data."""
         return self._call(CALL_WRITE, data)
+
+    def close(self):
+        """Close the connection currently opened in the simulator."""
+        return self._call(CALL_CLOSE, None)
+
+    def failOpen(self, really):
+        """Enable/disable open failure in the simulator."""
+        return self._call(CALL_FAILOPEN, really)
+
+    def quit(self):
+        """Quit from the simulator."""
+        data = cPickle.dumps((CALL_QUIT, None))
+        self._socket.send(struct.pack("I", len(data)) + data)        
 
     def _call(self, command, data):
@@ -1024,5 +1072,5 @@
         if line=="EOF":
             print
-            return True
+            return self.do_quit("")
         else:
             return super(CLI, self).default(line)
@@ -1102,6 +1150,37 @@
             return [key + "=" for key in self._valueHandlers if key.startswith(text)]
 
+    def do_close(self, args):
+        """Close an existing connection so that FS will fail."""
+        try:
+            self._client.close()
+            print "Connection closed"
+        except Exception, e:
+            print >> sys.stderr, "Failed to close the connection: " + str(e)        
+        
+    def do_failopen(self, args):
+        """Enable/disable the failing of opens."""
+        try:
+            value = self.str2bool(args)
+            self._client.failOpen(value)
+            print "Opening will%s fail" % ("" if value else " not",)
+        except Exception, e:
+            print >> sys.stderr, "Failed to set open failure: " + str(e)        
+
+    def help_failopen(self, usage = False):
+        """Help for the failopen close"""
+        if usage: print "Usage:",
+        print "failopen yes|no"
+
+    def complete_failopen(self, text, line, begidx, endidx):
+        if text:
+            if "yes".startswith(text): return ["yes"]
+            elif "no".startswith(text): return ["no"]
+            else: return []
+        else:
+            return ["yes", "no"]
+        
     def do_quit(self, args):
         """Handle the quit command."""
+        self._client.quit()
         return True
 
