package net.frontlinesms.ui.handler.phones;
import java.util.Enumeration;
import net.frontlinesms.CommUtils;
import net.frontlinesms.FrontlineUtils;
import net.frontlinesms.messaging.FrontlineMessagingService;
import net.frontlinesms.messaging.sms.SmsServiceManager;
import net.frontlinesms.messaging.sms.modem.SmsModem;
import net.frontlinesms.ui.ThinletUiEventHandler;
import net.frontlinesms.ui.UiGeneratorController;
import net.frontlinesms.ui.i18n.InternationalisationUtils;
import net.frontlinesms.ui.i18n.TextResourceKeyOwner;
import org.apache.log4j.Logger;
import org.smslib.AbstractATHandler;
import org.smslib.handler.CATHandler;
import serial.CommPortIdentifier;
import serial.NoSuchPortException;
/**
* @author Morgan Belkadi <morgan@frontlinesms.com>
* @author Alex Anderson <alex@frontlinesms.com>
*/
@TextResourceKeyOwner
public class DeviceManualConfigDialogHandler implements ThinletUiEventHandler {
//> STATIC CONSTANTS
/** The fully-qualified name of the default {@link CATHandler} class. */
private static final String DEFAULT_CAT_HANDLER_CLASS_NAME = CATHandler.class.getName();
//> UI LAYOUT FILES
/** UI XML File Path: phone config dialog TODO what is this dialog for? */
private static final String UI_FILE_MODEM_MANUAL_CONFIG_DIALOG = "/ui/core/phones/dgModemManualConfig.xml";
//> UI COMPONENT NAMES
/** UI component: panel containing manual settings. */
private static final String COMPONENT_MANUAL_SETTINGS_PANEL = "pnManualSettings";
/** UI component: radio checkbox specifying that config should be detected rather than specified. */
private static final String COMPONENT_DETECT_CONFIG_CHECKBOX = "cbDetectConfig";
/** UI component: Textfield containing the PIN to use for the connection. */
private static final String COMPONENT_PIN_TEXTFIELD = "tfPin";
/** UI component: Combobox containing the name of the port to connect to. */
private static final String COMPONENT_PORT_NAME_COMBOBOX = "cbPortName";
/** UI component: Combobox containing the baud rate for manual connection */
private static final String COMPONENT_BAUD_RATE_COMBOBOX = "cbBaudRate";
/** UI component: Combobox containing the name of the CAT Handler to connect with. */
private static final String COMPONENT_CAT_HANDLER_COMBOBOX = "cbCatHandler";
//> I18N KEYS
/** I18n Text Key: TODO */
private static final String MESSAGE_INVALID_BAUD_RATE = "message.invalid.baud.rate";
/** I18n Text Key: TODO */
private static final String MESSAGE_PORT_NOT_FOUND = "message.port.not.found";
/** I18n Text Key: TODO */
private static final String MESSAGE_PORT_ALREADY_CONNECTED = "message.port.already.connected";
/** I18n Text Key: The requested port is already in use. */
private static final String I18N_PORT_IN_USE = "com.port.inuse";
//> INSTANCE PROPERTIES
/** Logger */
private Logger log = FrontlineUtils.getLogger(this.getClass());
private UiGeneratorController ui;
/** The manager of {@link FrontlineMessagingService}s */
private final SmsServiceManager phoneManager;
/** The dialog that this class handles events for */
private Object dialogComponent;
/** The device that we are trying to connect to. */
private SmsModem device;
/**
* @param ui
* @param device an instance of {@link SmsModem}, or <code>null</code> if none is specified. FIXME i think this should just be a {@link String} specifying the port
*/
public DeviceManualConfigDialogHandler(UiGeneratorController ui, SmsModem device) {
this.ui = ui;
this.phoneManager = ui.getPhoneManager();
assert(device == null || device instanceof SmsModem) : "This class should only be created for handling connections to an SMS Modem.";
this.device = device;
}
/**
* Initialize the statistics dialog
*/
private void initDialog() {
log.trace("INIT DEVICE MANUAL CONFIG DIALOG");
this.dialogComponent = ui.loadComponentFromFile(UI_FILE_MODEM_MANUAL_CONFIG_DIALOG, this);
Object portList = find(COMPONENT_PORT_NAME_COMBOBOX);
Enumeration<CommPortIdentifier> commPortEnumeration = CommUtils.getPortIdentifiers();
while (commPortEnumeration.hasMoreElements()) {
CommPortIdentifier commPortIdentifier = commPortEnumeration.nextElement();
ui.add(portList, ui.createComboboxChoice(commPortIdentifier.getName(), null));
}
Object handlerList = find(COMPONENT_CAT_HANDLER_COMBOBOX);
int trimLength = DEFAULT_CAT_HANDLER_CLASS_NAME.length() + 1;
for (Class<? extends AbstractATHandler> handler : AbstractATHandler.getHandlers()) {
String handlerName = handler.getName();
if(handlerName.equals(DEFAULT_CAT_HANDLER_CLASS_NAME)) handlerName = "<default>";
else handlerName = handlerName.substring(trimLength);
ui.add(handlerList, ui.createComboboxChoice(handlerName, handler));
}
if (device instanceof SmsModem) {
SmsModem modem = (SmsModem) device;
ui.setText(find(COMPONENT_PORT_NAME_COMBOBOX), modem.getPort());
ui.setText(find(COMPONENT_BAUD_RATE_COMBOBOX), String.valueOf(modem.getBaudRate()));
}
ui.setSelected(find(COMPONENT_DETECT_CONFIG_CHECKBOX), true);
setDetectManual(false);
log.trace("EXIT");
}
//> PUBLIC ACCESSORS
public Object getDialog() {
initDialog();
return this.dialogComponent;
}
//> UI EVENT METHODS
/** Event method fired when the radio button selection for manual vs automatic detection is changed. */
public void setDetectManual(String detectManual) {
assert (detectManual.equals("true") || detectManual.equals("false")) : "detectManual value must be 'true' or 'false'";
setDetectManual(detectManual.equals("true"));
}
/** Event method fired when the radio button selection for manual vs automatic detection is changed. */
private void setDetectManual(boolean detectManual) {
// Enable/disable the manual settings boxes depending on the supplied setting
ui.setEnabledRecursively(find(COMPONENT_MANUAL_SETTINGS_PANEL), detectManual);
}
/**
* Event: "connect" button clicked.
* Validate the form, and if it is OK, initiate the connection.
*/
public void doConnect() {
boolean detectConfig = ui.isSelected(find(COMPONENT_DETECT_CONFIG_CHECKBOX));
// check the port is free
String requestedPortName = ui.getText(find(COMPONENT_PORT_NAME_COMBOBOX));
if(phoneManager.hasPhoneConnected(requestedPortName)) {
ui.alert(InternationalisationUtils.getI18nString(MESSAGE_PORT_ALREADY_CONNECTED, requestedPortName));
} else {
String pin = ui.getText(find(COMPONENT_PIN_TEXTFIELD)).trim();
if(pin.length() == 0) pin = null;
try {
boolean connectingOk;
if(detectConfig) {
connectingOk = phoneManager.requestConnect(requestedPortName, pin);
} else {
String baudRateAsString = ui.getText(find(COMPONENT_BAUD_RATE_COMBOBOX));
String preferredCATHandler = ui.getText(find(COMPONENT_CAT_HANDLER_COMBOBOX));
try {
connectingOk = phoneManager.requestConnect(requestedPortName,
pin,
Integer.parseInt(baudRateAsString),
preferredCATHandler);
} catch (NumberFormatException e) {
// The specified baud is not a valid number
ui.alert(InternationalisationUtils.getI18nString(MESSAGE_INVALID_BAUD_RATE, baudRateAsString));
connectingOk = false;
}
}
if(connectingOk) {
removeDialog();
} else {
ui.alert(InternationalisationUtils.getI18nString(I18N_PORT_IN_USE));
}
} catch (NoSuchPortException e) {
ui.alert(InternationalisationUtils.getI18nString(MESSAGE_PORT_NOT_FOUND, requestedPortName));
}
}
}
/** @see UiGeneratorController#removeDialog(Object) */
public void removeDialog() {
this.ui.removeDialog(this.dialogComponent);
}
public void showHelpPage(String page) {
ui.showHelpPage(page);
}
//> UI HELPER METHODS
/** @return UI component with the supplied name, or <code>null</code> if none could be found */
private Object find(String componentName) {
return ui.find(this.dialogComponent, componentName);
}
}