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 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 PlaceAskOrderWizard extends GenericTransactionWizard {
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() {
int index = comboAsset.getSelectionIndex();
return index >= 0 ? assets.get(comboAsset.getSelectionIndex()) : null; // Asset
}
private void populateAssets(Account account) {
comboAsset.removeAll();
assets.clear();
if (account != null) {
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());
}
int index = 0;
if (presetAssetId != null) {
Asset asset = Asset.getAsset(presetAssetId);
if (asset != null) {
index = assets.indexOf(asset);
index = index == -1 ? 0 : index;
}
}
comboAsset.select(index);
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 fieldQuantity = new IGenericTransactionField() {
private Text textQuantity;
private Text textQuantityReadonly;
@Override
public String getLabel() {
return "Quantity";
}
@Override
public Object getValue() {
try {
return Integer.parseInt(textQuantity.getText().trim());
}
catch (NumberFormatException e) {
return -1;
}
};
@Override
public Control createControl(Composite parent) {
textQuantity = new Text(parent, SWT.BORDER);
textQuantity.setText(Integer.toString(presetQuantity));
textQuantity.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
requestVerification();
}
});
return textQuantity;
}
@Override
public Control createReadonlyControl(Composite parent) {
textQuantityReadonly = new Text(parent, SWT.BORDER);
textQuantityReadonly.setEditable(false);
return textQuantityReadonly;
}
@Override
public boolean verify(String[] message) {
String text = textQuantity.getText().trim();
int quantity;
try {
quantity = Integer.parseInt(text);
}
catch (NumberFormatException nfe) {
message[0] = "Value must be numeric";
return false;
}
if (quantity < 1) {
message[0] = "Value must be greater than 1";
return false;
}
Asset asset = (Asset) fieldAsset.getValue();
if (asset != null) {
if (quantity > asset.getQuantity()) {
message[0] = "There where only " + asset.getQuantity()
+ " assets issued";
return false;
}
}
textQuantityReadonly.setText(text);
return true;
}
};
/* Price is expressed in NXT sends! User enters price in NXT with precision */
final IGenericTransactionField fieldPrice = new IGenericTransactionField() {
private Text textPrice;
private Text textPriceReadonly;
private boolean ignore = false;
private final ModifyListener modificationListener = new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
ignore = true;
requestVerification();
ignore = false;
}
};
@Override
public String getLabel() {
return "Price";
}
@Override
public Object getValue() {
try {
double p = Double.parseDouble(textPrice.getText().trim());
p = (double) Math.round(p * 100) / 100; // round to two decimals
return (long) (p * 100); // price in cents
}
catch (NumberFormatException e) {
return -1;
}
};
@Override
public Control createControl(Composite parent) {
textPrice = new Text(parent, SWT.BORDER);
if (presetAssetId != null && presetPrice > 0) {
Double p = new Long(presetPrice).doubleValue() / 100;
p = (double) Math.round(p * 100) / 100;
textPrice.setText(Double.toString(p));
}
else {
textPrice.setText("0");
}
textPrice.addModifyListener(modificationListener);
return textPrice;
}
@Override
public Control createReadonlyControl(Composite parent) {
textPriceReadonly = new Text(parent, SWT.BORDER);
textPriceReadonly.setEditable(false);
return textPriceReadonly;
}
@Override
public boolean verify(String[] message) {
String text = textPrice.getText().trim();
long priceInCents; // in NXT cents
try {
Double p = Double.parseDouble(text);
// round the double to two places after comma
p = (double) Math.round(p * 100) / 100;
// correct the user input to remove the to high precision
if (ignore == false) {
textPrice.removeModifyListener(modificationListener);
textPrice.setText(Double.toString(p));
textPrice.addModifyListener(modificationListener);
}
priceInCents = (long) (p * 100);
}
catch (NumberFormatException e) {
message[0] = "Value must be numeric";
return false;
}
if (priceInCents < 1) {
message[0] = "Value must be greater than 0.01";
return false;
}
if (priceInCents > Constants.MAX_BALANCE * 100L) {
message[0] = "Value must be less than " + Constants.MAX_BALANCE;
return false;
}
textPriceReadonly.setText(text);
return true;
}
};
private Long presetAssetId;
private int presetQuantity;
private long presetPrice; // in cents per asset
public PlaceAskOrderWizard(final IUserService userService,
final INxtService nxt, Long assetId, int quantity, long price) {
super(userService);
this.presetAssetId = assetId;
this.presetQuantity = quantity;
this.presetPrice = price;
setWindowTitle("Place Sell Order");
setTransaction(new IGenericTransaction() {
@Override
public String sendTransaction(String[] message) {
IAccount sender = user.getAccount();
Asset asset = (Asset) fieldAsset.getValue();
int quantity = (int) fieldQuantity.getValue();
long price = (long) fieldPrice.getValue(); // price is in cents
PromptFeeDeadline dialog = new PromptFeeDeadline(getShell());
dialog.setMinimumFee(1);
dialog.setFee(1);
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.createPlaceAskOrderTransaction(sender,
asset.getId(), quantity, price, 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, fieldAsset,
fieldQuantity, fieldPrice };
}
@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 = (int) fieldQuantity.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;
}
});
}
}