package com.dgex.offspring.ui.messaging;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import nxt.Account;
import nxt.Alias;
import nxt.Constants;
import nxt.util.Convert;
import org.apache.log4j.Logger;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.e4.ui.services.IStylingEngine;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.dgex.offspring.config.ContactsService;
import com.dgex.offspring.nxtCore.service.INxtService;
import com.dgex.offspring.ui.InspectAccountDialog;
import com.dgex.offspring.ui.SendMessageWizard;
import com.dgex.offspring.user.service.IUser;
import com.dgex.offspring.user.service.IUserService;
public class MessagingControl extends Composite {
static Logger logger = Logger.getLogger(MessagingControl.class);
static String ID_KEY = "com.dgex.offspring.ui.controls.MessagingControl.ID_KEY";
static Image errorImage = FieldDecorationRegistry.getDefault()
.getFieldDecoration(FieldDecorationRegistry.DEC_ERROR).getImage();
static SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMM yy H:mm:ss");
private final INxtService nxt;
private final IStylingEngine engine;
private final IUserService userService;
private final UISynchronize sync;
private final Long accountId;
private Button replyButton;
private Text messageText;
private Composite recipientsComposite;
private Composite topComposite;
private Composite bottomComposite;
private boolean accountReadonly = true;
private Label statusLabel;
private MessagingTreeViewer treeViewer;
interface AccountLinkListener {
void remove(AccountLink link);
void click(AccountLink link);
void requestLayout(AccountLink link);
}
static class AccountLink {
private final String id;
private final AccountLinkListener listener;
private Control control = null;
public AccountLink(String id, AccountLinkListener listener) {
if (id == null)
throw new RuntimeException("Id cannot be null");
this.id = id.trim().toLowerCase();
this.listener = listener;
}
public void create(Composite parent) {
control = createControl(parent);
control.setData(ID_KEY, id);
control.pack();
// createMenu(control);
registerMouseEvents(control);
}
public String getId() {
return id;
}
public Control getControl() {
return control;
}
private Control createControl(Composite parent) {
Account account = getAccount();
if (account == null) {
Label label = new Label(parent, SWT.NONE);
label.setText(id);
logger.info("Lable text=" + id);
return label;
}
Link link = new Link(parent, SWT.NONE);
link.setText("<A>" + id + "</A>");
logger.info("Link text=<A>" + id + "</A>");
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
listener.click(AccountLink.this);
}
});
return link;
}
// private void createMenu(Control control) {
// Menu contextMenu = new Menu(control);
// control.setMenu(contextMenu);
// MenuItem menuItem = new MenuItem(contextMenu, SWT.PUSH);
// menuItem.setText("Remove");
// menuItem.addSelectionListener(new SelectionAdapter() {
//
// @Override
// public void widgetSelected(SelectionEvent e) {
// listener.remove(AccountLink.this);
// }
// });
// }
private void registerMouseEvents(final Control control) {
control.addMouseTrackListener(new MouseTrackListener() {
@Override
public void mouseHover(MouseEvent e) {
control.setFont(JFaceResources.getFontRegistry().getBold(""));
doLayout(control);
}
@Override
public void mouseExit(MouseEvent e) {
control.setFont(null);
doLayout(control);
}
@Override
public void mouseEnter(MouseEvent e) {
control.setFont(JFaceResources.getFontRegistry().getBold(""));
doLayout(control);
}
});
}
private void doLayout(Control control) {
listener.requestLayout(this);
}
public Account getAccount() {
Account account = getAccount(id);
if (account == null) {
Alias alias = Alias.getAlias(id);
if (alias != null) {
return getAccount(alias.getURI());
}
}
return account;
}
private Account getAccount(String accountId) {
try {
return Account.getAccount(Convert.parseUnsignedLong(accountId));
}
catch (NullPointerException e) {}
catch (NumberFormatException e) {}
return null;
}
}
private final AccountLinkListener accountLinkListener = new AccountLinkListener() {
@Override
public void remove(AccountLink link) {
// StringBuilder sb = new StringBuilder();
// for (Control control : recipientsComposite.getChildren()) {
// String id = (String)
// ((Composite)control).getChildren()[0].getData(ID_KEY);
// if (id.compareTo(link.getId()) != 0) {
// sb.append(id).append(" ");
// }
// }
// accountText.setText(sb.toString().trim());
}
@Override
public void click(AccountLink link) {
Account account = link.getAccount();
if (account != null) {
InspectAccountDialog.show(account.getId(), nxt, engine, userService,
sync,
ContactsService.getInstance());
}
}
@Override
public void requestLayout(AccountLink link) {
link.getControl().pack();
link.getControl().getParent().pack();
recipientsComposite.pack();
messageText.pack();
bottomComposite.layout(true);
}
};
public MessagingControl(Composite parent, int style, final Long accountId,
final INxtService nxt, IStylingEngine engine,
final IUserService userService,
UISynchronize sync) {
super(parent, style);
this.nxt = nxt;
this.engine = engine;
this.userService = userService;
this.sync = sync;
this.accountId = accountId;
IUser user = userService.findUser(accountId);
if (user != null) {
this.accountReadonly = user.getAccount().isReadOnly();
}
createControls();
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) treeViewer
.getSelection();
Object element = selection.getFirstElement();
if (element instanceof IMessageNode) {
IMessageNode node = (IMessageNode) element;
MessageWrapper message = node.getMessage();
/* remove the old controls */
while (recipientsComposite.getChildren().length > 0) {
recipientsComposite.getChildren()[0].dispose();
}
Long senderId = message.getSenderId();
Long receiverId = message.getReceipientId();
Label label = new Label(recipientsComposite, SWT.NONE);
label.setFont(JFaceResources.getFontRegistry().getBold(""));
Date date = new Date(((message.getTimestamp()) * 1000L)
+ (Constants.EPOCH_BEGINNING - 500L));
label.setText(formatToYesterdayOrToday(date,
new boolean[1]) + " ");
label = new Label(recipientsComposite, SWT.NONE);
label.setText("Sender: ");
// label.setFont(JFaceResources.getFontRegistry().getBold(""));
if (!senderId.equals(accountId)) {
AccountLink link = new AccountLink(
Convert.toUnsignedLong(senderId), accountLinkListener);
link.create(recipientsComposite);
}
else {
label = new Label(recipientsComposite, SWT.NONE);
label.setText("YOU ");
label.setFont(JFaceResources.getFontRegistry().getBold(""));
}
label = new Label(recipientsComposite, SWT.NONE);
label.setText(" Receiver: ");
// label.setFont(JFaceResources.getFontRegistry().getBold(""));
if (!receiverId.equals(accountId)) {
AccountLink link = new AccountLink(Convert
.toUnsignedLong(receiverId), accountLinkListener);
link.create(recipientsComposite);
}
else {
label = new Label(recipientsComposite, SWT.NONE);
label.setText("YOU ");
label.setFont(JFaceResources.getFontRegistry().getBold(""));
}
recipientsComposite.pack(true);
messageText.setText(message.getMessage());
bottomComposite.layout();
}
}
});
final Menu contextMenu = new Menu(treeViewer.getTree());
treeViewer.getTree().setMenu(contextMenu);
contextMenu.addMenuListener(new MenuListener() {
@Override
public void menuShown(MenuEvent e) {
while (contextMenu.getItemCount() > 0)
contextMenu.getItem(0).dispose();
IStructuredSelection selection = (IStructuredSelection) treeViewer
.getSelection();
Object element = selection.getFirstElement();
if (element instanceof IMessageNode) {
IMessageNode node = (IMessageNode) element;
MessageWrapper message = node.getMessage();
if (accountReadonly) {
createMenuItem(contextMenu, "Reply to Sender",
message.getSenderId(), message.getId(), message.isEncrypted());
createMenuItem(contextMenu, "Reply to Recipient",
message.getReceipientId(), message.getId(),
message.isEncrypted());
}
else {
if (accountId.equals(message.getSenderId())) {
createMenuItem(contextMenu, "Reply", message.getReceipientId(),
message.getId(), message.isEncrypted());
}
else {
createMenuItem(contextMenu, "Reply", message.getSenderId(),
message.getId(), message.isEncrypted());
}
}
}
}
@Override
public void menuHidden(MenuEvent e) {}
});
}
private void createMenuItem(Menu contextMenu, String label,
final Long receipientId, final Long referencedTransactionId,
final boolean useEncryption) {
MenuItem item = new MenuItem(contextMenu, SWT.PUSH);
item.setText(label);
item.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openReplyDialog(receipientId, referencedTransactionId, useEncryption);
refresh();
}
});
}
private void openReplyDialog(Long recipientId, Long transactionId,
boolean useEncryption) {
Shell shell = getShell();
if (shell != null) {
while (shell.getParent() != null) {
shell = shell.getParent().getShell();
}
}
WizardDialog dialog = new WizardDialog(shell, new SendMessageWizard(
userService, nxt, recipientId, transactionId, useEncryption));
dialog.open();
}
private void createControls() {
setLayout(new FillLayout());
SashForm form = new SashForm(this, SWT.VERTICAL);
form.setLayout(new FillLayout());
topComposite = new Composite(form, SWT.NONE);
topComposite.setLayout(new FillLayout());
bottomComposite = new Composite(form, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).spacing(5, 0).margins(0, 0)
.applyTo(bottomComposite);
treeViewer = new MessagingTreeViewer(topComposite, accountId, null, nxt,
engine, userService, sync);
recipientsComposite = new Composite(bottomComposite, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false)
.align(SWT.FILL, SWT.CENTER).applyTo(recipientsComposite);
// recipientsComposite.setBackground(Colors.getColor(Colors.YELLOW));
recipientsComposite.setLayout(new RowLayout());
replyButton = new Button(bottomComposite, SWT.PUSH);
replyButton.setText("Reply to this message");
GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER)
.exclude(accountReadonly)
.applyTo(replyButton);
replyButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
IStructuredSelection selection = (IStructuredSelection) treeViewer
.getSelection();
Object element = selection.getFirstElement();
if (element instanceof IMessageNode) {
IMessageNode node = (IMessageNode) element;
MessageWrapper message = node.getMessage();
Long transactionId = message.getId();
Long recipientId;
if (accountReadonly) {
recipientId = message.getSenderId();
}
else {
if (message.getSenderId().equals(accountId)) {
recipientId = message.getReceipientId();
}
else {
recipientId = message.getSenderId();
}
}
openReplyDialog(recipientId, transactionId, message.isEncrypted());
}
}
});
messageText = new Text(bottomComposite, SWT.MULTI | SWT.BORDER | SWT.WRAP
| SWT.V_SCROLL);
messageText.setEditable(false);
GridDataFactory.defaultsFor(messageText).align(SWT.FILL, SWT.FILL)
.grab(true, true).span(3, 1)
.applyTo(messageText);
form.setWeights(new int[] { 60, 30 });
}
public void refresh() {
treeViewer.setInput(accountId);
treeViewer.expandAll();
}
public static String formatToYesterdayOrToday(Date date, boolean recent[]) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
Calendar today = Calendar.getInstance();
Calendar yesterday = Calendar.getInstance();
yesterday.add(Calendar.DATE, -1);
DateFormat timeFormatter = new SimpleDateFormat("H:mm:ss");
if (calendar.get(Calendar.YEAR) == today.get(Calendar.YEAR)
&& calendar.get(Calendar.DAY_OF_YEAR) == today
.get(Calendar.DAY_OF_YEAR)) {
recent[0] = true;
return "Today " + timeFormatter.format(date);
}
else if (calendar.get(Calendar.YEAR) == yesterday.get(Calendar.YEAR)
&& calendar.get(Calendar.DAY_OF_YEAR) == yesterday
.get(Calendar.DAY_OF_YEAR)) {
recent[0] = true;
return "Yesterday " + timeFormatter.format(date);
}
recent[0] = false;
return dateFormat.format(date);
}
}