package org.nightlabs.jfire.pbx.ui.call;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.jdo.FetchPlan;
import javax.jdo.JDOHelper;
import javax.security.auth.login.LoginException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.nightlabs.base.ui.job.Job;
import org.nightlabs.base.ui.util.RCPUtil;
import org.nightlabs.eclipse.extension.AbstractEPProcessor;
import org.nightlabs.jdo.NLJDOHelper;
import org.nightlabs.jfire.base.login.ui.Login;
import org.nightlabs.jfire.pbx.Call;
import org.nightlabs.jfire.pbx.NoPhoneSystemAssignedException;
import org.nightlabs.jfire.pbx.PhoneNumberDataFieldCall;
import org.nightlabs.jfire.pbx.PhoneSystem;
import org.nightlabs.jfire.pbx.PhoneSystemException;
import org.nightlabs.jfire.pbx.dao.PhoneSystemDAO;
import org.nightlabs.jfire.pbx.ui.call.selectnumber.SelectPhoneNumberDialog;
import org.nightlabs.jfire.pbx.ui.resource.Messages;
import org.nightlabs.jfire.prop.DataField;
import org.nightlabs.jfire.prop.PropertySet;
import org.nightlabs.jfire.prop.StructLocal;
import org.nightlabs.jfire.prop.dao.PropertySetDAO;
import org.nightlabs.jfire.prop.dao.StructLocalDAO;
import org.nightlabs.jfire.prop.datafield.PhoneNumberDataField;
import org.nightlabs.jfire.prop.id.DataFieldID;
import org.nightlabs.jfire.prop.id.PropertySetID;
import org.nightlabs.jfire.workstation.id.WorkstationID;
import org.nightlabs.progress.ProgressMonitor;
import org.nightlabs.progress.SubProgressMonitor;
import org.nightlabs.util.Util;
public class CallHandlerRegistry extends AbstractEPProcessor
{
private static volatile CallHandlerRegistry sharedInstance;
public static CallHandlerRegistry sharedInstance() {
if (sharedInstance == null) {
synchronized(CallHandlerRegistry.class) {
if (sharedInstance == null) {
sharedInstance = new CallHandlerRegistry();
sharedInstance.process();
}
}
}
return sharedInstance;
}
protected CallHandlerRegistry() { }
@Override
public String getExtensionPointID() {
return "org.nightlabs.jfire.pbx.ui.callHandler"; //$NON-NLS-1$
}
private Map<String, IConfigurationElement> phoneSystemClass2element = new HashMap<String, IConfigurationElement>();
@Override
public void processElement(IExtension extension, IConfigurationElement element) throws Exception
{
String phoneSystemClass = element.getAttribute(CallHandler.ATTRIBUTE_PHONE_SYSTEM_CLASS);
phoneSystemClass2element.put(phoneSystemClass, element);
}
public void call(final PropertySetID personID)
{
Job job = new Job(Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.callJob.name")) { //$NON-NLS-1$
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
call(personID, monitor);
return Status.OK_STATUS;
}
};
job.setPriority(Job.INTERACTIVE);
job.setUser(true);
job.schedule();
}
public void call(PropertySetID personID, ProgressMonitor monitor) throws PhoneSystemException
{
if (Display.getCurrent() != null)
throw new IllegalStateException("Thread mismatch! This method must not be called on an SWT UI thread!"); //$NON-NLS-1$
monitor.beginTask(Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.callJob.name"), 100); //$NON-NLS-1$
try {
final PhoneSystem phoneSystem = PhoneSystemDAO.sharedInstance().getPhoneSystem(
(WorkstationID)null,
new String[] {
FetchPlan.DEFAULT, PhoneSystem.FETCH_GROUP_NAME, PhoneSystem.FETCH_GROUP_CALLABLE_STRUCT_FIELDS
},
1,
new SubProgressMonitor(monitor, 50)
);
if (phoneSystem == null) {
WorkstationID workstationID = null;
Login login;
try {
login = Login.getLogin();
} catch (LoginException e) {
throw new RuntimeException(e);
}
if (login.getWorkstationID() != null)
workstationID = WorkstationID.create(login.getOrganisationID(), login.getWorkstationID());
throw new NoPhoneSystemAssignedException(workstationID);
}
if (phoneSystem.getCallableStructFields().isEmpty()) {
Display.getDefault().syncExec(new Runnable() { // important to use syncExec because otherwise the shell might be closed before the dialog is opened.
@Override
public void run() {
MessageDialog.openError(
RCPUtil.getActiveShell(),
Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.errorDialog[phoneSystemLacksCallableNumber].title"), //$NON-NLS-1$
String.format(
Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.errorDialog[phoneSystemLacksCallableNumber].text"), //$NON-NLS-1$
phoneSystem.getName().getText()
)
);
}
});
return;
}
// load person, collect phone numbers and (if more than one) ask the user which one to call.
final PropertySet p = PropertySetDAO.sharedInstance().getPropertySet(
personID, new String[] { FetchPlan.DEFAULT, PropertySet.FETCH_GROUP_FULL_DATA }, NLJDOHelper.MAX_FETCH_DEPTH_NO_LIMIT,
new SubProgressMonitor(monitor, 30)
);
final PropertySet person = Util.cloneSerializable(p);
StructLocal structLocal = StructLocalDAO.sharedInstance().getStructLocal(person.getStructLocalObjectID(), new SubProgressMonitor(monitor, 10));
person.inflate(structLocal);
final List<PhoneNumberDataField> phoneNumberDataFields = new LinkedList<PhoneNumberDataField>();
for (DataField dataField : person.getDataFields()) {
if (dataField.isEmpty())
continue;
if (dataField instanceof PhoneNumberDataField && phoneSystem.getCallableStructFields().contains(dataField.getStructField()))
phoneNumberDataFields.add((PhoneNumberDataField) dataField);
}
if (phoneNumberDataFields.isEmpty()) {
Display.getDefault().syncExec(new Runnable() { // important to use syncExec because otherwise the shell might be closed before the dialog is opened.
@Override
public void run() {
MessageDialog.openError(
RCPUtil.getActiveShell(),
Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.errorDialog[noPhoneNumber].title"), //$NON-NLS-1$
String.format(Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.errorDialog[noPhoneNumber].text"), person.getDisplayName()) //$NON-NLS-1$
);
}
});
return;
}
Collections.sort(phoneNumberDataFields, new Comparator<PhoneNumberDataField>() {
@Override
public int compare(PhoneNumberDataField o1, PhoneNumberDataField o2) {
return o1.getPropRelativePK().compareTo(o2.getPropRelativePK());
}
});
PhoneNumberDataField phoneNumberDataField = null;
if (phoneNumberDataFields.size() > 1) {
// We show a nice dialog asking for the phone number to dial.
// When the user selected a phone number, we assign the field phoneNumberDataField appropriately.
final PhoneNumberDataField[] tmp = new PhoneNumberDataField[1];
Display.getDefault().syncExec(new Runnable() { // important to use syncExec because otherwise the shell might be closed before the dialog is opened.
@Override
public void run() {
SelectPhoneNumberDialog dialog = new SelectPhoneNumberDialog(RCPUtil.getActiveShell(), person, phoneNumberDataFields);
dialog.open();
tmp[0] = dialog.getSelectedPhoneNumberDataField();
}
});
phoneNumberDataField = tmp[0];
}
else
phoneNumberDataField = phoneNumberDataFields.get(0);
if (phoneNumberDataField != null) {
DataFieldID phoneNumberDataFieldID = (DataFieldID) JDOHelper.getObjectId(phoneNumberDataField);
Call call = new PhoneNumberDataFieldCall(phoneNumberDataFieldID);
call(phoneSystem, call, new SubProgressMonitor(monitor, 40));
}
} finally {
monitor.done();
}
}
public void call(final Call call)
{
Job job = new Job(Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.callJob.name")) { //$NON-NLS-1$
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
PhoneSystem phoneSystem = PhoneSystemDAO.sharedInstance().getPhoneSystem((WorkstationID)null, null, 1, new SubProgressMonitor(monitor, 50));
if (phoneSystem == null) {
WorkstationID workstationID = null;
Login login;
try {
login = Login.getLogin();
} catch (LoginException e) {
throw new RuntimeException(e);
}
if (login.getWorkstationID() != null)
workstationID = WorkstationID.create(login.getOrganisationID(), login.getWorkstationID());
throw new NoPhoneSystemAssignedException(workstationID);
}
call(phoneSystem, call, monitor);
return Status.OK_STATUS;
}
};
job.setPriority(Job.INTERACTIVE);
job.setUser(true);
job.schedule();
}
public void call(PhoneSystem phoneSystem, Call call, ProgressMonitor monitor) throws PhoneSystemException
{
monitor.beginTask(Messages.getString("org.nightlabs.jfire.pbx.ui.call.CallHandlerRegistry.callJob.name"), 100); //$NON-NLS-1$
try {
IConfigurationElement configurationElement = null;
Class<? extends PhoneSystem> clazz = phoneSystem.getClass();
while (clazz != null) {
configurationElement = phoneSystemClass2element.get(clazz.getName());
if (configurationElement != null)
break;
if (PhoneSystem.class.isAssignableFrom(clazz.getSuperclass())) {
@SuppressWarnings("unchecked")
Class<? extends PhoneSystem> c = (Class<? extends PhoneSystem>) clazz.getSuperclass();
clazz = c;
}
else
clazz = null;
}
if (configurationElement == null)
throw new NoCallHandlerException("There is no call handler registered for this phone system class: " + phoneSystem.getClass().getName()); //$NON-NLS-1$
CallHandler callHandler;
try {
callHandler = (CallHandler) configurationElement.createExecutableExtension(CallHandler.ATTRIBUTE_CLASS);
} catch (CoreException e) {
throw new RuntimeException(e);
}
callHandler.call(call, new SubProgressMonitor(monitor, 50));
} finally {
monitor.done();
}
}
}