class WwStripExchanger:
    def __init__(self, gui):
        self.updater = SxUpdater(gui)
        self.update_ticker = Ticker(self.updater.start, parent=gui)
        self.gui = gui
        self.running = False

    def start(self):
        self.update_ticker.start(SX_update_interval)
        self.running = True

    def stopAndWait(self):
        if self.isRunning(
        ):  # CHECK: do we need to wait for any running SXsender threads as well?
            self.update_ticker.stop()
            self.updater.wait()
            self.running = False
        self.updater.ATCs_on_last_run.clear()
        self.updater.current_contact_claims.clear()

    def isRunning(self):
        return self.running

    def connectedATCs(self):
        return self.updater.ATCs_on_last_run[:]

    def isConnected(self, atc_callsign):
        return any(atc.callsign == atc_callsign
                   for atc in self.updater.ATCs_on_last_run)

    def claimingContact(self, callsign):
        return self.updater.current_contact_claims.get(callsign, None)

    def handOver(self, strip, atc_id):
        '''
		returns cleanly if transfer is properly initiated (contact linked),
		otherwise: HandoverBlocked (handover aborted)
		'''
        acft = strip.linkedAircraft()
        if acft == None:
            raise HandoverBlocked(
                'Unlinked strips cannot be sent through the OpenRadar system.')
        else:
            SXsender(self.gui, strip, acft.identifier, handover=atc_id).start()
class RadioBox(QWidget, Ui_radioBox):
	def __init__(self, parent, external, port):
		'''
		external is a host (possibly localhost) for external FGCom instance, or None for internal (child process)
		'''
		QWidget.__init__(self, parent)
		self.setupUi(self)
		client_address = some(external, 'localhost'), port
		self.settings = FgcomSettings(socket(AF_INET, SOCK_DGRAM), client_address)
		self.controller = Ticker(self.settings.send, parent=self)
		self.frequency_combo.addFrequencies([(frq, descr) for frq, descr, t in env.frequencies])
		self.frequency_combo.addFrequencies(frequencies_always_proposed)
		if external == None: # child process
			self.onOff_button.setToolTip('Internal FGCom instance using local port %d' % port)
			ad = world_navpoint_db.findClosest(env.radarPos(), types=[Navpoint.AD]).code if env.airport_data == None else settings.location_code
			self.instance = InternalFgcomInstance(port, ['--airport=%s' % ad], self)
			self.instance.started.connect(self.processHasStarted)
			self.instance.finished.connect(self.processHasStopped)
			self.onOff_button.toggled.connect(self.switchFGCom)
		else: # creating box for external instance
			self.instance = None
			self.onOff_button.setToolTip('External FGCom instance on %s:%d' % client_address)
			self.onOff_button.setChecked(True) # keep checked (tested for RDF)
			self.onOff_button.setEnabled(False)
			self.PTT_button.setEnabled(True)
			self.controller.start(fgcom_controller_ticker_interval)
		self.PTT_button.pressed.connect(lambda: self.PTT(True))
		self.PTT_button.released.connect(lambda: self.PTT(False))
		self.softVolume_tickBox.clicked.connect(self.setVolume)
		self.frequency_combo.frequencyChanged.connect(self.setFrequency)
		self.updateRDF()
		self.RDF_tickBox.toggled.connect(self.updateRDF)
		self.onOff_button.toggled.connect(self.updateRDF)
		signals.localSettingsChanged.connect(self.updateRDF)
	
	def isInternal(self):
		return self.instance != None
	
	def clientAddress(self):
		return self.settings.address
	
	def getReadyForRemoval(self):
		if self.isInternal():
			self.switchFGCom(False)
			self.instance.waitForFinished(1000)
		else:
			self.controller.stop()
		try:
			del settings.MP_RDF_frequencies[self.settings.address[1]]
		except KeyError:
			pass
	
	def setVolume(self):
		if settings.FGCom_radios_muted:
			self.settings.vol = 0
		elif self.softVolume_tickBox.isChecked():
			self.settings.vol = soft_sound_level
		else:
			self.settings.vol = loud_sound_level
		self.settings.send()
		
	def setFrequency(self, frq):
		self.PTT(False)
		self.settings.frq = frq
		self.updateRDF()
		self.settings.send()
	
	def PTT(self, toggle):
		self.settings.ptt = toggle
		self.PTT_button.setChecked(toggle and self.PTT_button.isEnabled())
		# NOTE: line below is unreliable on mouse+kbd mix, but not a serious problem.
		settings.transmitting_radio = toggle # accounts for direct mouse PTT press
		self.settings.send()
	
	def updateRDF(self):
		frq_select_available = settings.radio_direction_finding and settings.session_manager.session_type == SessionType.FLIGHTGEAR_MP
		self.RDF_tickBox.setEnabled(frq_select_available)
		box_key = self.settings.address[1]
		if frq_select_available and self.RDF_tickBox.isChecked():
			settings.MP_RDF_frequencies[box_key] = self.settings.frq
		else:
			try:
				del settings.MP_RDF_frequencies[box_key]
			except KeyError:
				pass
	
	
	## Controlling FGCom process
	
	def switchFGCom(self, on_off):
		if self.isInternal():
			self.removeBox_button.setEnabled(not on_off)
		if on_off: # Start FGCom
			self.instance.start()
		else: # Stop FGCom
			self.PTT(False)
			self.instance.kill()
	
	def processHasStarted(self):
		self.PTT_button.setEnabled(True)
		self.controller.start(fgcom_controller_ticker_interval)
	
	def processHasStopped(self, exit_code, status):
		self.controller.stop()
		self.PTT_button.setEnabled(False)
		self.PTT_button.setChecked(False)
		self.onOff_button.setChecked(False)