poe.trade.assist.Main.java Source code

Java tutorial

Introduction

Here is the source code for poe.trade.assist.Main.java

Source

/*
 * Copyright (C) 2015 thirdy
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package poe.trade.assist;

import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.media.AudioClip;
import javafx.stage.Stage;
import poe.trade.assist.Search.SearchPersist;
import poe.trade.assist.scraper.SearchPageScraper.SearchResultItem;
import poe.trade.assist.service.AutoSearchService;
import poe.trade.assist.util.Dialogs;

public class Main extends Application {
    //   http://poe.trade/search/iwarikikikoiat
    private Logger logger = Logger.getLogger("poe.assist");
    FileHandler fh;

    private static final String DEFAULT_SEARCH_CSV_FILE = "https://docs.google.com/spreadsheets/d/10mb4jxFuux8u0lqeoR8ydE1Gm3YKpe2IT7tsNuN8pKw/edit?usp=sharing";

    private static final String LOCAL_SEARCH_FILE_NAME = "search.csv";
    private SearchPane searchPane;
    private ResultPane resultPane;
    final TextField searchFileTextField = new TextField(DEFAULT_SEARCH_CSV_FILE);
    private Config config;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        //      try {
        //         fh = new FileHandler("D:\\MxDownload\\POE\\poe.trade.assist\\assist.log");
        //      } catch (IOException e) {
        //         e.printStackTrace();
        //      }
        //      logger.addHandler(fh);
        //      SimpleFormatter formatter = new SimpleFormatter();
        //      fh.setFormatter(formatter);
        //      logger.info("Init application.");

        BorderPane root = new BorderPane();

        config = Config.load();
        config.get(Config.SEARCH_FILE).ifPresent(searchFileTextField::setText);

        searchFileTextField.setPromptText("Search CSV File URL or blank");
        searchFileTextField.setTooltip(new Tooltip(
                "Any url to a valid poe.trade.assist CSV search file. Can be googlespreadsheet URL. If left blank, will load search.csv file instead"));
        searchFileTextField.setMinWidth(330);
        HBox.setHgrow(searchFileTextField, Priority.ALWAYS);

        List<Search> searchList = loadSearchListFromFile();

        AutoSearchService autoSearchService = new AutoSearchService(
                Boolean.parseBoolean(config.get(Config.AUTO_ENABLE).get()),
                Float.parseFloat(config.get(Config.SEARCH_MINUTES).get()));
        searchPane = new SearchPane(searchList);
        resultPane = new ResultPane(searchFileTextField, this);

        autoSearchService.searchesProperty().bind(searchPane.dataProperty());

        EventHandler<ActionEvent> reloadAction = e -> {
            System.out.println("Loading search file: " + searchFileTextField.getText());
            List<Search> newList = loadSearchListFromFile();
            searchPane.dataProperty().clear();
            searchPane.dataProperty().addAll(newList);
            autoSearchService.restart();
            if (searchPane.dataProperty().size() > 0)
                searchPane.searchTable.getSelectionModel().select(0);
        };

        searchFileTextField.setOnAction(reloadAction);
        resultPane.loadButton.setOnAction(reloadAction);
        resultPane.defaultButton.setOnAction(e -> {
            searchFileTextField.setText(DEFAULT_SEARCH_CSV_FILE);
            resultPane.loadButton.fire();
        });

        resultPane.runNowButton.setOnAction(e -> autoSearchService.restart());
        //        autoSearchService.minsToSleepProperty().bind(resultPane.noOfMinsTextField.textProperty());
        setupResultPaneBinding(searchPane, resultPane, autoSearchService);
        if (searchList.size() > 0)
            searchPane.searchTable.getSelectionModel().select(0);

        stage.setOnCloseRequest(we -> {
            saveSearchList(searchPane);
            config.setProperty(Config.SEARCH_FILE, searchFileTextField.getText());
            config.setProperty(Config.SOUND_FILE, resultPane.soundButton.getUserData().toString());
            config.save();
        });

        config.get(Config.SOUND_FILE).ifPresent(resultPane.soundButton::setUserData);

        autoSearchService.restart();

        //        HBox container = new HBox(5, searchPane, resultPane);
        SplitPane container = new SplitPane(searchPane, resultPane);
        container.setDividerPositions(0.1);
        HBox.setHgrow(searchPane, Priority.ALWAYS);
        HBox.setHgrow(resultPane, Priority.ALWAYS);
        container.setMaxWidth(Double.MAX_VALUE);
        //        root.getChildren().addAll(container);
        root.setCenter(container);
        Scene scene = new Scene(root);
        stage.getIcons().add(new Image("/48px-Durian.png"));
        stage.titleProperty().bind(new SimpleStringProperty("poe.trade.assist v5 (Durian) - ")
                .concat(autoSearchService.messageProperty()));
        //        stage.setWidth(1200);
        //        stage.setHeight(550);
        stage.setMaximized(true);
        stage.setScene(scene);
        stage.show();
        searchPane.searchTable.requestFocus();
    }

    private void saveSearchList(SearchPane searchPane) {
        List<Search> list = new ArrayList<>(searchPane.searchTable.getMasterItems());
        if (list != null) {
            //         Gson gson = new Gson();
            List<String[]> persistList = list.stream().map(e -> e.toSearchPersist()).map(e -> e.toCSVArray())
                    .collect(toList());
            if (!persistList.isEmpty()) {
                File file = getSearchFile();
                try (BufferedWriter br = new BufferedWriter(new FileWriter(file))) {
                    CSVPrinter json = CSVFormat.RFC4180.withHeader("Name", "Tags", "URL", "Auto", "Sort").print(br);
                    json.printRecords(persistList);
                    json.flush();
                    //         String json = gson.toJson(persistList);
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    Dialogs.showError(e1);
                    e1.printStackTrace();
                }
            }

            //         saveSearchesToFile(json);
        }
    }

    private List<Search> loadSearchListFromFile() {
        List<Search> list = Arrays.asList(
                new Search("Lakishu's Blade 3L", "http://poe.trade/search/nokagatasasaha", "uniques,melee", false,
                        "price_in_chaos"),
                new Search("Tabula 5c", "http://poe.trade/search/adeyubetedamit", "watch,uniques", true,
                        "price_in_chaos"));
        // 1ex aegis http://poe.trade/search/atamiomimetami
        // kaom's heart http://poe.trade/search/kuwahamigaruri

        List<CSVRecord> csv = loadCSVRaw();

        list = csv.stream().map(e -> new SearchPersist(e.get("Name"), e.get("Tags"), e.get("URL"),
                Boolean.valueOf(e.get("Auto")), e.get("Sort")).toSearch()).collect(toList());

        //      if (StringUtils.isNotBlank(csv)) {
        //         Gson gson = new Gson();
        //         Type listType = new TypeToken<ArrayList<SearchPersist>>() { }.getType();
        //         List<SearchPersist> persistList = gson.fromJson(csv, listType);
        //         list = persistList.stream().map(e -> e.toSearch()).collect(toList());
        //      }

        return list;
    }

    private List<CSVRecord> loadCSVRaw() {
        List<CSVRecord> records = null;
        try {
            String searchFileFromTextField = StringUtils.trimToEmpty(searchFileTextField.getText());
            if (searchFileFromTextField.isEmpty()
                    || searchFileFromTextField.equalsIgnoreCase(LOCAL_SEARCH_FILE_NAME)) {
                File file = getSearchFile();
                try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                    CSVParser csvParser = CSVFormat.RFC4180.withHeader().parse(br);
                    records = csvParser.getRecords();
                }
            } else {
                String url = searchFileFromTextField;
                if (url.contains("google") && url.contains("/edit")) {
                    // handle google spreadsheet url that is not an export url
                    // https://docs.google.com/spreadsheets/d/1V8r0mIn5njpmVYwFWpqnptAMI6udrIaqhCby1i79UGw/edit#gid=0
                    url = StringUtils.substringBeforeLast(url, "/edit");
                    url += "/export?gid=0&format=csv";
                }
                try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) {
                    CSVParser csvParser = CSVFormat.RFC4180.withHeader().parse(br);
                    records = csvParser.getRecords();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            Dialogs.showError(e);
        }
        return records;
    }

    //   private void saveSearchesToFile(String csv) {
    //      File file = getSearchFile();
    //      try {
    //         FileUtils.writeStringToFile(file, csv);
    //      } catch (IOException e) {
    //         throw new RuntimeException(e);
    //      }
    //   }

    private File getSearchFile() {
        File file = new File(LOCAL_SEARCH_FILE_NAME);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return file;
    }

    private void setupResultPaneBinding(SearchPane searchPane, ResultPane resultPane,
            AutoSearchService autoSearchService) {
        searchPane.searchTable.getSelectionModel().selectedItemProperty().addListener((ob, o, n) -> {
            if (n != null) {
                List<SearchResultItem> list = n.getResultList();
                if (n.getAutoSearch() && list != null) {
                    resultPane.setSearch(n);
                } else if (!n.getAutoSearch()) {
                    manualTaskRun(n);
                }
            }
        });
        autoSearchService.setCallback(noOfItemsFound -> {
            //         refreshResultColumn();
            Search search = searchPane.searchTable.getSelectionModel().getSelectedItem();
            if (search != null && search.getResultList() != null && search.getAutoSearch()) {
                Platform.runLater(() -> resultPane.setSearch(search));
            }
            if (noOfItemsFound > 0) {
                String soundPath = resultPane.soundButton.getUserData().toString();
                File file = new File(soundPath);
                if (file.exists()) {
                    String url;
                    try {
                        url = file.toURI().toURL().toExternalForm();
                        AudioClip sound = new AudioClip(url);
                        sound.play();
                    } catch (Exception e) {
                        e.printStackTrace();
                        Dialogs.showError(e);
                    }
                }
            }
        });
    }

    //   public void refreshResultColumn() {
    // workaround http://stackoverflow.com/questions/11065140/javafx-2-1-tableview-refresh-items
    // yeah java sucks on some parts
    //      Platform.runLater(() -> {
    //         searchPane.searchTable.getCo.setVisible(false);
    //         searchPane.getResultColumn().setVisible(true);
    //      });
    //   }

    public void manualTaskRun(Search search) {
        String url = search.getUrl();
        if (isNotBlank(url)) {
            Task<Search> task = new Task<Search>() {
                @Override
                protected Search call() throws Exception {
                    String html = AutoSearchService.doDownload(search.getUrl(), search.getSort());
                    search.setHtml(html);
                    search.parseHtml();
                    return search;
                }
            };
            resultPane.progressIndicator.visibleProperty().unbind();
            resultPane.progressIndicator.visibleProperty().bind(task.runningProperty());
            task.setOnSucceeded(e -> {
                resultPane.setSearch(task.getValue());
                //            refreshResultColumn();
            });
            task.setOnFailed(e -> {
                Dialogs.showError(task.getException());
                //            refreshResultColumn();
            });
            new Thread(task).start();
        } else {
            resultPane.setSearch(search);
        }
    }

}