package com.dgex.offspring.ui;
import java.text.DecimalFormat;
import nxt.Asset;
import nxt.Constants;
import nxt.NxtException.ValidationException;
import nxt.Transaction;
import nxt.util.Convert;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
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.graphics.GC;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
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.IUserService;
public class PlaceBidOrderWizard extends GenericTransactionWizard {
static String THIRD_COLUMN = "000000000000";
final IGenericTransactionField fieldAsset = new IGenericTransactionField() {
private Text textAsset;
private Text textAssetReadonly;
public Label labelAssetName;
private Label labelAssetNameReadonly;
static final String EMPTY_NAME = " "; // 15 characters
@Override
public String getLabel() {
return "Asset";
}
@Override
public Object getValue() {
String id_as_string = textAsset.getText().trim();
Long id = id_as_string.isEmpty() ? null : Convert
.parseUnsignedLong(id_as_string);
if (id != null) {
return Asset.getAsset(id);
}
return null;
}
@Override
public Control createControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0)
.margins(0, 0).applyTo(composite);
textAsset = new Text(composite, SWT.BORDER);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(textAsset);
String id = presetAssetId != null ? Convert.toUnsignedLong(presetAssetId)
: "";
textAsset.setText(id);
textAsset.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
requestVerification();
}
});
labelAssetName = new Label(composite, SWT.NONE);
GC gc = new GC(labelAssetName);
GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER)
.hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT)
.applyTo(labelAssetName);
gc.dispose();
labelAssetName.setText(EMPTY_NAME);
return composite;
}
@Override
public Control createReadonlyControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0)
.margins(0, 0).applyTo(composite);
textAssetReadonly = new Text(composite, SWT.BORDER);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(textAssetReadonly);
textAssetReadonly.setText("");
textAssetReadonly.setEditable(false);
labelAssetNameReadonly = new Label(composite, SWT.NONE);
GC gc = new GC(labelAssetNameReadonly);
GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER)
.hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT)
.applyTo(labelAssetNameReadonly);
gc.dispose();
labelAssetNameReadonly.setText("");
return composite;
}
@Override
public boolean verify(String[] message) {
String id_as_string = textAsset.getText().trim();
Long id = id_as_string.isEmpty() ? null : Convert
.parseUnsignedLong(id_as_string);
if (id == null) {
labelAssetName.setText(EMPTY_NAME);
message[0] = "Invalid id";
return false;
}
Asset asset = Asset.getAsset(id);
if (asset == null) {
labelAssetName.setText(EMPTY_NAME);
message[0] = "Asset does not exist";
return false;
}
labelAssetName.setText(asset.getName());
textAssetReadonly.setText(id_as_string);
labelAssetNameReadonly.setText(asset.getName());
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 Label labelPriceTotal;
private Label labelPriceTotalReadonly;
private final DecimalFormat formatDouble = new DecimalFormat("#.##");
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 (long) -1;
}
};
@Override
public Control createControl(Composite parent) {
String price;
if (presetAssetId != null && presetPrice > 0) {
Double p = new Long(presetPrice).doubleValue() / 100;
p = (double) Math.round(p * 100) / 100;
price = Double.toString(p);
}
else {
price = "0.00";
}
Composite composite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0)
.margins(0, 0).applyTo(composite);
textPrice = new Text(composite, SWT.BORDER);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(textPrice);
textPrice.setText(price);
textPrice.addModifyListener(modificationListener);
labelPriceTotal = new Label(composite, SWT.NONE);
GC gc = new GC(labelPriceTotal);
GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER)
.hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT)
.applyTo(labelPriceTotal);
gc.dispose();
labelPriceTotal.setText("0.0");
return composite;
// ------------------
// 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) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).spacing(10, 0)
.margins(0, 0).applyTo(composite);
textPriceReadonly = new Text(composite, SWT.BORDER);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.grab(true, false).applyTo(textPriceReadonly);
textPriceReadonly.setText("");
labelPriceTotalReadonly = new Label(composite, SWT.NONE);
GC gc = new GC(labelPriceTotalReadonly);
GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER)
.hint(gc.textExtent(THIRD_COLUMN).x, SWT.DEFAULT)
.applyTo(labelPriceTotalReadonly);
gc.dispose();
labelPriceTotalReadonly.setText("0.0");
return composite;
// textPriceReadonly = new Text(parent, SWT.BORDER);
// textPriceReadonly.setEditable(false);
// return textPriceReadonly;
}
@Override
public boolean verify(String[] message) {
labelPriceTotalReadonly.setText("");
labelPriceTotal.setText("");
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;
}
/* calculate the total */
int quantity = (int) fieldQuantity.getValue();
if (quantity > 0) {
Double price = (double) (priceInCents * quantity); // price in cents
price = price / 100L;
String txt = Constants.MAX_BALANCE >= price ? formatDouble
.format(price) : "MAX";
labelPriceTotalReadonly.setText(txt);
labelPriceTotal.setText(txt);
}
textPriceReadonly.setText(text);
return true;
}
};
// final IGenericTransactionField fieldTotal = new IGenericTransactionField()
// {
//
// private Label labelTotal;
// private Label labelTotalReadonly;
//
// @Override
// public String getLabel() {
// return "Total";
// }
//
// @Override
// public Object getValue() {
// return null;
// }
//
// @Override
// public Control createControl(Composite parent) {
// labelTotal = new Label(parent, SWT.NONE);
// if (presetAssetId != null && presetPrice > 0) {
// Double p = new Long(presetPrice).doubleValue() / 100;
// p = p * presetQuantity;
// p = (double) Math.round(p * 100) / 100;
// labelTotal.setText(Double.toString(p));
// }
// else {
// labelTotal.setText("0");
// }
// return labelTotal;
// }
//
// @Override
// public Control createReadonlyControl(Composite parent) {
// labelTotalReadonly = new Label(parent, SWT.NONE);
// labelTotalReadonly.setText(labelTotal.getText());
// return labelTotalReadonly;
// }
//
// @Override
// public boolean verify(String[] message) {
// long price = (long) fieldPrice.getValue(); // price in cents
// int quantity = (int) fieldQuantity.getValue();
// String text = "";
// if (price != -1 && quantity != -1) {
// Double p = new Long(price).doubleValue() / 100;
// p = p * presetQuantity;
// p = (double) Math.round(p * 100) / 100;
// text = Double.toString(p);
// }
// labelTotal.setText(text);
// labelTotalReadonly.setText(text);
// return true;
// }
//
// };
private Long presetAssetId;
private int presetQuantity;
private long presetPrice; // in cents per asset
public PlaceBidOrderWizard(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 Buy 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.createPlaceBidOrderTransaction(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 /* , fieldTotal */};
}
@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;
}
int quantity = (int) fieldQuantity.getValue();
long price = (long) fieldPrice.getValue();
if (quantity != -1 && price != -1) {
long totalPriceInCents = quantity * price;
long totalPrice = (totalPriceInCents / 100L) + 1;
if (totalPrice > user.getAccount().getBalance()) {
message[0] = "Insufficient balance";
return false;
}
}
return true;
}
});
}
}