package net.thirdy.blackmarket.controls;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.controlsfx.control.GridCell;
import org.elasticsearch.common.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.jexiletools.es.model.Currencies;
import io.jexiletools.es.model.Mod;
import io.jexiletools.es.model.Price;
import io.jexiletools.es.model.json.ExileToolsHit;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.Tooltip;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import net.thirdy.blackmarket.Main;
import net.thirdy.blackmarket.fxcontrols.SmallIcon;
import net.thirdy.blackmarket.util.ImageCache;
import net.thirdy.blackmarket.util.LangContants;
public class ItemGridCell extends GridCell<ExileToolsHit> {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
private final List<Label> explicitModsLbls;
private final VBox modsPane = new VBox();
private final ItemGridCellPropertiesPane propertiesGridPane = new ItemGridCellPropertiesPane();
private final Hyperlink itemName = new Hyperlink("Item Name Here");
private final HBox itemNameGraphics = new HBox(1);
private final Label implicitMod = new Label("Implicit Mod Here");
private final Separator implicitModSeparator = new Separator(Orientation.HORIZONTAL);
private final Separator itemNameSeparator = new Separator(Orientation.HORIZONTAL);
private final Hyperlink wtbBtn = new Hyperlink("Want to buy");
private final Label priceLbl = new Label("");
private final TextFlow playerInfo = new TextFlow();
private final HBox bottomPane = new HBox(3);
private final BorderPane borderPane = new BorderPane();
StackPane stackPane = new StackPane();
double scaledWidth = 170 ;
double scaledHeight = 189 ;
public ItemGridCell() {
getStyleClass().add("image-grid-cell"); //$NON-NLS-1$
stackPane.getStyleClass().add("itemGridCellStackPane");
propertiesGridPane.setId("propertiesGridPane");
playerInfo.setId("playerInfo");
propertiesGridPane.setVgap(0.1);
explicitModsLbls = Arrays.asList(
new Label(), new Label(), new Label(), new Label(), new Label(), new Label(), new Label(),
new Label(), new Label(), new Label(), new Label(), new Label(), new Label(), new Label()
);
explicitModsLbls.stream()
.forEach(l -> {
l.getStyleClass().add("explcit-mod");
l.setWrapText(true);
});
implicitMod.getStyleClass().add("implicit-mod");
implicitMod.setWrapText(true);
itemName.getStyleClass().add("item-name");
itemName.setWrapText(true);
itemName.setGraphic(itemNameGraphics);
itemName.setContentDisplay(ContentDisplay.LEFT);
priceLbl.setTextFill(Color.WHITE);
priceLbl.setContentDisplay(ContentDisplay.RIGHT);
priceLbl.minWidth(40);
HBox.setHgrow(priceLbl, Priority.ALWAYS);
wtbBtn.setOnAction(e -> wtbHandler());
wtbBtn.setStyle("-fx-font-size: 9pt;");
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.SOMETIMES);
bottomPane.getChildren().addAll(priceLbl, playerInfo, spacer, wtbBtn);
borderPane.setBottom(bottomPane);
GridPane gridCenterPane = setupCenterGridPane();
gridCenterPane.setGridLinesVisible(Main.DEVELOPMENT_MODE);
GridPane.setHalignment(modsPane, HPos.LEFT);
gridCenterPane.add(modsPane, 0, 0);
GridPane.setHalignment(propertiesGridPane, HPos.RIGHT);
gridCenterPane.add(propertiesGridPane, 1, 0);
borderPane.setCenter(gridCenterPane);
borderPane.setPadding(new Insets(5, 0, 5, 5));
}
private void wtbHandler() {
getItem().incrWtbCtr();
String wtb = getItem().toWTB();
copyToClipboard(wtb);
setupEffects(getItem());
setupWtbLabel(getItem());
}
private void copyToClipboard(String s) {
StringSelection stringSelection = new StringSelection(s);
Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
clpbrd.setContents(stringSelection, null);
}
private GridPane setupCenterGridPane() {
GridPane gridpane = new GridPane();
// gridpane.setPadding(new Insets(5));
gridpane.setHgap(2);
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(80);
ColumnConstraints column2 = new ColumnConstraints();
column2.setPercentWidth(20);
column1.setHgrow(Priority.ALWAYS);
column2.setHgrow(Priority.ALWAYS);
gridpane.getColumnConstraints().addAll(column1, column2);
return gridpane;
}
/**
* {@inheritDoc}
*/
@Override
protected void updateItem(ExileToolsHit item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == ExileToolsHit.EMPTY) {
setGraphic(null);
} else {
try {
setupItemUI(item);
} catch (Exception e) {
e.printStackTrace();
Dialogs.showExceptionDialog(e);
}
setGraphic(stackPane);
}
}
private void setupItemUI(ExileToolsHit item) {
stackPane.getChildren().clear();
ImageView imageView = new ImageView();
imageView.setPreserveRatio(true);
imageView.setSmooth(true);
// imageView.setCache(true); // makes the image blurry
imageView.setOpacity(0.5);
// Setup image
Image image = ImageCache.getInstance().get(item.getInfo().getIcon());
imageView.setImage(image);
if (image.getHeight() > scaledHeight) {
imageView.setFitWidth(94);
imageView.setFitHeight(scaledHeight);
} else {
imageView.setScaleX(0.6025641025641026);
imageView.setScaleY(0.6025641025641026);
}
// Setup labels
setupWtbLabel(item);
clearModLabels();
setupPrice(item);
setupItemName(item);
setupPlayerInfo(item);
item.getImplicitMod().ifPresent(m -> implicitMod.setText(m.toDisplay()));
populateModLabels(item);
updatePropertiesPane(item);
modsPane.getChildren().clear();
modsPane.getChildren().add(itemName);
modsPane.getChildren().add(itemNameSeparator);
item.getImplicitMod().ifPresent(m -> {
modsPane.getChildren().add(implicitMod);
modsPane.getChildren().add(implicitModSeparator);
});
modsPane.getChildren().addAll(
explicitModsLbls.stream().filter(l -> StringUtils.isNotBlank(l.getText())).collect(Collectors.toList()));
setupModsPseudo(item);
setupEffects(item);
stackPane.getChildren().addAll(imageView, borderPane);
}
private void setupEffects(ExileToolsHit item) {
stackPane.setEffect(null);
if (item.wtbCtr() > 0) {
int depth = 20; // Setting the uniform variable for the glow width and height
DropShadow borderGlow = new DropShadow();
borderGlow.setOffsetY(0f);
borderGlow.setOffsetX(0f);
borderGlow.setColor(Color.GREY);
borderGlow.setWidth(depth);
borderGlow.setHeight(depth);
stackPane.setEffect(borderGlow);
}
}
private void setupWtbLabel(ExileToolsHit item) {
String ctrStr = item.wtbCtr() > 0 ? " (" + item.wtbCtr() + ")" : LangContants.STRING_EMPTY;
String str = StringUtils.trimToNull(item.getShop().getSellerIGN()) != null ?
"Want to buy" + ctrStr :
"Copy shop url";
wtbBtn.setText(str);
}
private void setupModsPseudo(ExileToolsHit item) {
String resTxt = String.format("[pseudo res] %d %d %d %d %d",
item.getPseudoEleRes().orElse(0),
item.getPseudoFire().orElse(0),
item.getPseudoCold().orElse(0),
item.getPseudoLightning().orElse(0),
item.getPseudoChaos().orElse(0)
);
String attrTxt = String.format("[pseudo attr] %d %d %d %d",
item.getPseudoAttr().orElse(0),
item.getPseudoStr().orElse(0),
item.getPseudoDex().orElse(0),
item.getPseudoInt().orElse(0)
);
String lifeTxt = String.format("[pseudo life] %d",
item.getPseudoAttr().orElse(0)
);
if (resTxt.length() > 22) {
Label resLabel = new Label(resTxt);
resLabel.getStyleClass().add("pseudo-mod");
modsPane.getChildren().add(resLabel);
}
if (attrTxt.length() > 21) {
Label attrLabel = new Label(attrTxt);
attrLabel.getStyleClass().add("pseudo-mod");
modsPane.getChildren().add(attrLabel);
}
if (lifeTxt.length() > 15) {
Label lifeLabel = new Label(lifeTxt);
lifeLabel.getStyleClass().addAll("pseudo-mod");
modsPane.getChildren().add(lifeLabel);
}
}
private void updatePropertiesPane(ExileToolsHit item) {
propertiesGridPane.getChildren().clear();
Optional<String> socks = Optional.ofNullable(item.getSockets())
.map(s -> s.getAllSockets());
if(socks.isPresent()) propertiesGridPane.add(socks.get());
else propertiesGridPane.add("", "");
item.getStackSize().ifPresent(d -> propertiesGridPane.add("Stack:", d));
item.getQuality().ifPresent(d -> propertiesGridPane.add("Q:", d));
item.getTotalDPS().ifPresent(d -> propertiesGridPane.add("DPS:", d));
item.getPhysicalDPS().ifPresent(d -> propertiesGridPane.add("pDPS:", d));
item.getPhysicalDamage().ifPresent(d -> propertiesGridPane.add("Phys:", d));
item.getElementalDPS().ifPresent(d -> propertiesGridPane.add("eDPS:", d) );
item.getElementalDamage().ifPresent(d -> propertiesGridPane.add("Elem:", d));
item.getAPS().ifPresent(d -> propertiesGridPane.add("APS:", d));
// item.getCriticalStrikeChance().ifPresent(d -> propertiesGridPane.add("Crit:", d) );
item.getArmour().ifPresent(d -> propertiesGridPane.add("Ar:", d));
item.getEvasionRating().ifPresent(d -> propertiesGridPane.add("Ev:", d));
item.getEnergyShield().ifPresent(d -> propertiesGridPane.add("Es:", d));
item.getChanceToBlock().ifPresent(d -> propertiesGridPane.add("Blk:", d));
item.getRLvl().ifPresent(d -> propertiesGridPane.add("RLvl:", d));
item.getRStr().ifPresent(d -> propertiesGridPane.add("RStr:", d));
item.getRDex().ifPresent(d -> propertiesGridPane.add("RDex:", d));
item.getRInt().ifPresent(d -> propertiesGridPane.add("RInt:", d));
}
private void setupPrice(ExileToolsHit item) {
priceLbl.setText("");
priceLbl.setGraphic(null);
Optional<Price> price = item.getShop().getPrice();
price.ifPresent(p -> {
String amt = new DecimalFormat("#.##").format(p.getAmount());
priceLbl.setText(amt + "x");
priceLbl.setGraphic(new SmallIcon(p.getCurrency()));
});
}
private void setupPlayerInfo(ExileToolsHit item) {
playerInfo.getChildren().clear();
Optional<String> sellerIGN = Optional.ofNullable(StringUtils.trimToNull(item.getShop().getSellerIGN()));
Optional<String> sellerAccount = Optional.ofNullable(StringUtils.trimToNull(item.getShop().getSellerAccount()));
String shopUrl = "https://www.pathofexile.com/forum/view-thread/" + item.getShop().getThreadid();
if (sellerIGN.isPresent()) {
Text ignText = new Text("IGN:");
ignText.setFill(Color.WHITE);
String ign = sellerIGN.get();
ign = truncateIgn(ign);
Hyperlink link = new Hyperlink(ign);
link.setTextFill(Color.WHITE);
item.isOnline().ifPresent(o -> link.getStyleClass().add("ign-online"));
if (item.getLadderHit().isPresent()) {
link.setOnAction(e -> LadderHitsDialog.show(item));
item.lastOnline().ifPresent(d -> link.setTooltip(new Tooltip("Last Online: " + d.toString())));
} else {
link.setOnAction(e -> copyToClipboard(shopUrl));
}
playerInfo.getChildren().addAll(
ignText, link);
} else if (sellerAccount.isPresent()) {
Text sellerAccountText = new Text("Acct:");
sellerAccountText.setFill(Color.WHITE);
Hyperlink link = new Hyperlink(sellerAccount.get());
link.setTextFill(Color.WHITE);
link.setOnAction(e -> copyToClipboard(shopUrl));
playerInfo.getChildren().addAll(
sellerAccountText, link);
}
// if (item.lastOnline().isPresent()) {
// Date date = item.lastOnline().get();
// SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM d h:mm a z");
// sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// Label lastOnline = new Label(" " + sdf.format(date));
// lastOnline.getStyleClass().add("last-online");
// playerInfo.getChildren().add(lastOnline);
// }
}
private String truncateIgn(String ign) {
// sometimes we get a value like this:
// i_am_ready_to_die/internecivus_lanius/Catarina_is_my_sister
// https://www.pathofexile.com/forum/view-thread/1435290
if (ign.matches(".+/.+")) {
ign = ign.split("/")[0];
}
return ign;
}
private void setupItemName(ExileToolsHit item) {
itemName.setOnAction(e -> ItemDialog.show(item));
itemName.setText(item.getInfo().getFullName());
itemName.setTextFill(Color.web(item.getAttributes().getRarityAsEnum().webColor()));
itemNameGraphics.getChildren().clear();
if (item.getAttributes().getCorrupted()) {
itemNameGraphics.getChildren().add(new SmallIcon(Currencies.vaal));
}
if (item.getAttributes().getMirrored()) {
itemNameGraphics.getChildren().add(new SmallIcon(Currencies.mirror));
}
}
private void clearModLabels() {
explicitModsLbls.stream()
.forEach(l -> l.setText(""));
}
private void populateModLabels(ExileToolsHit item) {
List<Mod> explicitMods = item.getExplicitOrCraftedMods();
IntStream.range(0, explicitMods.size())
.forEachOrdered(i -> {
String m = explicitMods.get(i).toDisplay();
Label l = explicitModsLbls.get(i);
if (explicitMods.get(i).isCrafted()) {
l.getStyleClass().add("mod-crafted");
} else {
l.getStyleClass().remove("mod-crafted");
}
if (m.endsWith("% to Fire Resistance")) {
l.getStyleClass().add("explcit-mod-fireres");
} else if (m.endsWith("% to Cold Resistance")) {
l.getStyleClass().add("explcit-mod-coldres");
} else if (m.endsWith("% to Lightning Resistance")) {
l.getStyleClass().add("explcit-mod-lightningres");
} else {
l.getStyleClass().removeAll("explcit-mod-fireres", "explcit-mod-coldres", "explcit-mod-lightningres");
}
l.setText(m);
});
}
}