package com.dgex.offspring.ui;
import java.util.ArrayList;
import java.util.List;
import nxt.Account;
import nxt.Asset;
import nxt.Constants;
import nxt.NxtException.ValidationException;
import nxt.Transaction;
import nxt.util.Convert;
import org.apache.log4j.Logger;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import com.dgex.offspring.nxtCore.service.IAccount;
import com.dgex.offspring.nxtCore.service.INxtService;
import com.dgex.offspring.nxtCore.service.TransactionException;
import com.dgex.offspring.swt.wizard.GenericTransactionWizard;
import com.dgex.offspring.swt.wizard.IGenericTransaction;
import com.dgex.offspring.swt.wizard.IGenericTransactionField;
import com.dgex.offspring.user.service.IUser;
import com.dgex.offspring.user.service.IUserService;
public class TransferAssetWizard extends GenericTransactionWizard {
// In order to send an asset we need the following fields;
//
// String recipientValue = req.getParameter("recipient");
// String assetValue = req.getParameter("asset");
// String quantityValue = req.getParameter("quantity");
//
// Since a user can only send assets he actually owns the assetValue string is
// selected from a dropdown that lists all assets owned by an account
static Logger logger = Logger.getLogger(TransferAssetWizard.class);
final IGenericTransactionField fieldRecipient = new IGenericTransactionField() {
private Text textRecipient;
private Text textRecipientReadonly;
@Override
public String getLabel() {
return "Recipient";
}
@Override
public Object getValue() {
String recipientValue = textRecipient.getText().trim();
try {
return Convert.parseUnsignedLong(recipientValue);
}
catch (RuntimeException e) {
logger.error("Parse Recipient ID", e);
}
return null;
}
@Override
public Control createControl(Composite parent) {
textRecipient = new Text(parent, SWT.BORDER);
textRecipient.setText("");
textRecipient.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
requestVerification();
}
});
return textRecipient;
}
@Override
public Control createReadonlyControl(Composite parent) {
textRecipientReadonly = new Text(parent, SWT.BORDER);
textRecipientReadonly.setText("");
textRecipientReadonly.setEditable(false);
return textRecipientReadonly;
}
@Override
public boolean verify(String[] message) {
String recipientValue = textRecipient.getText().trim();
if ("0".equals(recipientValue)) {
message[0] = "Missing recipient";
return false;
}
try {
Convert.parseUnsignedLong(recipientValue);
}
catch (RuntimeException e) {
message[0] = "Incorrect recipient";
return false;
}
textRecipientReadonly.setText(recipientValue);
return true;
}
};
final IGenericTransactionField fieldAsset = new IGenericTransactionField() {
private final List<Asset> assets = new ArrayList<Asset>();
private Combo comboAsset;
private Combo comboAssetReadonly;
private IUser currentUser;
private final SelectionListener selectionListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
requestVerification();
}
};
@Override
public String getLabel() {
return "Asset";
}
@Override
public Object getValue() {
return assets.get(comboAsset.getSelectionIndex()); // Asset
}
private void populateAssets(Account account) {
comboAsset.removeAll();
assets.clear();
for (Long assetId : account.getAssetBalances().keySet()) {
Asset asset = Asset.getAsset(assetId);
comboAsset.add(createLabel(account, asset));
assets.add(asset);
}
}
private String createLabel(Account account, Asset asset) {
int balance = account.getAssetBalances().get(asset.getId());
return "Asset: " + asset.getName() + " Balance: " + balance;
}
@Override
public Control createControl(Composite parent) {
comboAsset = new Combo(parent, SWT.READ_ONLY);
currentUser = (IUser) fieldSender.getValue();
if (!currentUser.getAccount().isReadOnly()) {
populateAssets(currentUser.getAccount().getNative());
}
comboAsset.select(0);
comboAsset.addSelectionListener(selectionListener);
return comboAsset;
}
@Override
public Control createReadonlyControl(Composite parent) {
comboAssetReadonly = new Combo(parent, SWT.READ_ONLY);
// comboAssetReadonly.add("..");
// comboAssetReadonly.select(0);
return comboAssetReadonly;
}
@Override
public boolean verify(String[] message) {
/* Update readonly combo */
Account account = user.getAccount().getNative();
Asset asset = (Asset) getValue();
comboAssetReadonly.removeAll();
if (asset != null) {
comboAssetReadonly.add(createLabel(account, asset));
comboAssetReadonly.select(0);
}
/* There might have been a user change must update the list of assets */
IUser sender = (IUser) fieldSender.getValue();
if (!sender.equals(currentUser)) {
currentUser = sender;
comboAsset.removeAll();
if (!sender.getAccount().isReadOnly()) {
populateAssets(sender.getAccount().getNative());
}
comboAsset.removeSelectionListener(selectionListener);
comboAsset.select(0);
comboAsset.addSelectionListener(selectionListener);
}
return true;
}
};
final IGenericTransactionField fieldAmount = new IGenericTransactionField() {
private Text textAmount;
private Text textAmountReadonly;
@Override
public String getLabel() {
return "Amount";
}
@Override
public Object getValue() {
return Integer.parseInt(textAmount.getText().trim());
}
@Override
public Control createControl(Composite parent) {
textAmount = new Text(parent, SWT.BORDER);
textAmount.setText("0");
textAmount.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
requestVerification();
}
});
return textAmount;
}
@Override
public Control createReadonlyControl(Composite parent) {
textAmountReadonly = new Text(parent, SWT.BORDER);
textAmountReadonly.setEditable(false);
return textAmountReadonly;
}
@Override
public boolean verify(String[] message) {
String amountValue = textAmount.getText().trim();
try {
int amount = Integer.parseInt(amountValue);
if (amount <= 0 || amount >= Constants.MAX_ASSET_QUANTITY) {
message[0] = "Incorrect amount";
return false;
}
}
catch (NumberFormatException e) {
message[0] = "Amount must be numeric";
return false;
}
textAmountReadonly.setText(amountValue);
return true;
}
};
public TransferAssetWizard(final IUserService userService,
final INxtService nxt) {
super(userService);
setWindowTitle("Transfer Asset");
setTransaction(new IGenericTransaction() {
@Override
public String sendTransaction(String[] message) {
IAccount sender = user.getAccount();
Long recipient = (Long) fieldRecipient.getValue();
int amount = (Integer) fieldAmount.getValue();
Asset asset = (Asset) fieldAsset.getValue();
PromptFeeDeadline dialog = new PromptFeeDeadline(getShell());
if (dialog.open() != Window.OK) {
message[0] = "Invalid fee and deadline";
return null;
}
int fee = dialog.getFee();
short deadline = dialog.getDeadline();
try {
Transaction t = nxt.createTransferAssetTransaction(sender, recipient,
asset.getId(), amount, deadline, fee, null);
return t.getStringId();
}
catch (ValidationException e) {
message[0] = e.getMessage();
}
catch (TransactionException e) {
message[0] = e.getMessage();
}
return null;
}
@Override
public IGenericTransactionField[] getFields() {
return new IGenericTransactionField[] { fieldSender, fieldRecipient,
fieldAsset, fieldAmount };
}
@Override
public boolean verifySender(String message[]) {
if (user == null) {
message[0] = "Invalid sender";
return false;
}
if (user.getAccount().isReadOnly()) {
message[0] = "This is a readonly account";
return false;
}
Account account = user.getAccount().getNative();
Asset asset = (Asset) fieldAsset.getValue();
int amount = (Integer) fieldAmount.getValue();
if (asset != null) {
Integer assetBalance = account.getUnconfirmedAssetBalance(asset
.getId());
if (assetBalance == null || amount > assetBalance) {
message[0] = "Insufficient Asset Balance";
return false;
}
}
if (user.getAccount().getBalance() < 1) {
message[0] = "Insufficient Balance";
return false;
}
return true;
}
});
}
}