<commit_before>package logbook.internal.gui;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import logbook.bean.BattleLog;
import logbook.bean.BattleTypes.CombinedType;
import logbook.bean.BattleTypes.IFormation;
import logbook.bean.BattleTypes.IMidnightBattle;
import logbook.bean.MapStartNext;
import logbook.bean.Ship;
import logbook.bean.SlotItem;
import logbook.internal.BattleLogs;
import logbook.internal.BattleLogs.SimpleBattleLog;
import logbook.internal.BattleLogs.Unit;
import logbook.internal.LoggerHolder;

/**
 * 戦闘ログのUIコントローラー
 *
 */
public class BattleLogController extends WindowController {

    /** 統計 */
    @FXML
    private TreeTableView<BattleLogCollect> collect;

    /** 集計 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> unit;

    /** 出撃  */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> start;

    /** 勝利  */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> win;

    /** S勝利 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> s;

    /** A勝利 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> a;

    /** B勝利 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> b;

    /** C敗北 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> c;

    /** D敗北 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> d;

    /** 詳細 */
    @FXML
    private TableView<BattleLogDetail> detail;

    /** 日付 */
    @FXML
    private TableColumn<BattleLogDetail, String> date;

    /** 海域 */
    @FXML
    private TableColumn<BattleLogDetail, String> area;

    /** マス */
    @FXML
    private TableColumn<BattleLogDetail, String> cell;

    /** ボス */
    @FXML
    private TableColumn<BattleLogDetail, String> boss;

    /** 評価 */
    @FXML
    private TableColumn<BattleLogDetail, String> rank;

    /** 艦隊行動 */
    @FXML
    private TableColumn<BattleLogDetail, String> intercept;

    /** 味方陣形 */
    @FXML
    private TableColumn<BattleLogDetail, String> fformation;

    /** 敵陣形 */
    @FXML
    private TableColumn<BattleLogDetail, String> eformation;

    /** 制空権 */
    @FXML
    private TableColumn<BattleLogDetail, String> dispseiku;

    /** 味方触接 */
    @FXML
    private TableColumn<BattleLogDetail, String> ftouch;

    /** 敵触接 */
    @FXML
    private TableColumn<BattleLogDetail, String> etouch;

    /** 敵艦隊 */
    @FXML
    private TableColumn<BattleLogDetail, String> efleet;

    /** ドロップ艦種 */
    @FXML
    private TableColumn<BattleLogDetail, String> dropType;

    /** ドロップ艦娘 */
    @FXML
    private TableColumn<BattleLogDetail, String> dropShip;

    /** 戦闘ログ */
    private Map<Unit, List<SimpleBattleLog>> logMap;

    /** 詳細 */
    private ObservableList<BattleLogDetail> details = FXCollections.observableArrayList();

    @FXML
    void initialize() {
        try {
            TableTool.setVisible(this.detail, this.getClass().toString() + "#" + "detail");

            // 統計
            this.collect.setShowRoot(false);
            this.collect.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

            this.unit.setCellValueFactory(new TreeItemPropertyValueFactory<>("unit"));
            this.start.setCellValueFactory(new TreeItemPropertyValueFactory<>("start"));
            this.win.setCellValueFactory(new TreeItemPropertyValueFactory<>("win"));
            this.s.setCellValueFactory(new TreeItemPropertyValueFactory<>("s"));
            this.a.setCellValueFactory(new TreeItemPropertyValueFactory<>("a"));
            this.b.setCellValueFactory(new TreeItemPropertyValueFactory<>("b"));
            this.c.setCellValueFactory(new TreeItemPropertyValueFactory<>("c"));
            this.d.setCellValueFactory(new TreeItemPropertyValueFactory<>("d"));

            // 選択された時のリスナーを設定
            this.collect.getSelectionModel()
                    .selectedItemProperty()
                    .addListener(this::detail);

            // 詳細
            this.detail.setRowFactory(tv -> {
                TableRow<BattleLogDetail> r = new TableRow<>();
                r.setOnMouseClicked(e -> {
                    if (e.getClickCount() == 2 && (!r.isEmpty())) {
                        BattleLogDetail d = r.getItem();
                        BattleLog log = BattleLogs.read(d.getDate());
                        if (log != null) {
                            try {
                                MapStartNext last = log.getNext().get(log.getNext().size() - 1);
                                CombinedType combinedType = log.getCombinedType();
                                Map<Integer, List<Ship>> deckMap = log.getDeckMap();
                                Map<Integer, SlotItem> itemMap = log.getItemMap();
                                IFormation battle = log.getBattle();
                                IMidnightBattle midnight = log.getMidnight();
                                Set<Integer> escape = log.getEscape();

                                InternalFXMLLoader.showWindow("logbook/gui/battle_detail.fxml", this.getWindow(),
                                        "戦闘ログ", c -> {
                                            ((BattleDetail) c).setData(last, combinedType, deckMap, escape, itemMap,
                                                    battle, midnight);
                                        }, null);
                            } catch (Exception ex) {
                                LoggerHolder.get().error("詳細の表示に失敗しました", ex);
                            }
                        }
                    }
                });
                return r;
            });
            this.detail.setItems(this.details);
            this.detail.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
            this.detail.setOnKeyPressed(TableTool::defaultOnKeyPressedHandler);

            this.date.setCellValueFactory(new PropertyValueFactory<>("date"));
            this.area.setCellValueFactory(new PropertyValueFactory<>("area"));
            this.cell.setCellValueFactory(new PropertyValueFactory<>("cell"));
            this.boss.setCellValueFactory(new PropertyValueFactory<>("boss"));
            this.rank.setCellValueFactory(new PropertyValueFactory<>("rank"));
            this.intercept.setCellValueFactory(new PropertyValueFactory<>("intercept"));
            this.fformation.setCellValueFactory(new PropertyValueFactory<>("fformation"));
            this.eformation.setCellValueFactory(new PropertyValueFactory<>("eformation"));
            this.dispseiku.setCellValueFactory(new PropertyValueFactory<>("dispseiku"));
            this.ftouch.setCellValueFactory(new PropertyValueFactory<>("ftouch"));
            this.etouch.setCellValueFactory(new PropertyValueFactory<>("etouch"));
            this.efleet.setCellValueFactory(new PropertyValueFactory<>("efleet"));
            this.dropType.setCellValueFactory(new PropertyValueFactory<>("dropType"));
            this.dropShip.setCellValueFactory(new PropertyValueFactory<>("dropShip"));

            // 統計
            this.setCollect();
        } catch (Exception e) {
            LoggerHolder.get().error("FXMLの初期化に失敗しました", e);
        }
    }

    private void setCollect() {
        // ルート要素(非表示)
        TreeItem<BattleLogCollect> root = new TreeItem<BattleLogCollect>(new BattleLogCollect());
        this.collect.setRoot(root);

        // 集計単位がキーのマップ
        this.logMap = BattleLogs.readSimpleLog();
        for (Unit unit : Unit.values()) {
            List<SimpleBattleLog> list = this.logMap.get(unit);

            // 単位のルート
            BattleLogCollect unitRootValue = BattleLogs.collect(list, null, false);
            unitRootValue.setUnit(unit.getName());
            unitRootValue.setCollectUnit(unit);

            TreeItem<BattleLogCollect> unitRoot = new TreeItem<BattleLogCollect>(unitRootValue);
            unitRoot.setExpanded(true);

            // ボス
            BattleLogCollect bossValue = BattleLogs.collect(list, null, true);
            bossValue.setUnit("ボス");
            bossValue.setCollectUnit(unit);
            bossValue.setBoss(true);

            TreeItem<BattleLogCollect> boss = new TreeItem<BattleLogCollect>(bossValue);
            unitRoot.getChildren().add(boss);

            // 海域の名前
            List<String> areaNames = list.stream()
                    .map(SimpleBattleLog::getArea)
                    .distinct()
                    .sorted(Comparator.naturalOrder())
                    .collect(Collectors.toList());
            for (String area : areaNames) {
                // 海域毎の集計
                BattleLogCollect areaValue = BattleLogs.collect(list, area, false);
                areaValue.setUnit(area);
                areaValue.setCollectUnit(unit);
                areaValue.setArea(area);

                TreeItem<BattleLogCollect> areaRoot = new TreeItem<BattleLogCollect>(areaValue);

                // 海域ボス
                BattleLogCollect areaBossValue = BattleLogs.collect(list, area, true);
                areaBossValue.setUnit("ボス");
                areaBossValue.setCollectUnit(unit);
                areaBossValue.setArea(area);
                areaBossValue.setBoss(true);

                TreeItem<BattleLogCollect> areaBoss = new TreeItem<BattleLogCollect>(areaBossValue);
                areaRoot.getChildren().add(areaBoss);

                unitRoot.getChildren().add(areaRoot);
            }

            root.getChildren().add(unitRoot);
        }
    }

    /**
     * ログを更新
     */
    @FXML
    void reloadAction(ActionEvent event) {
        this.setCollect();
    }

    /**
     * クリップボードにコピー
     */
    @FXML
    void copyDetail() {
        TableTool.selectionCopy(this.detail);
    }

    /**
     * すべてを選択
     */<commit_msg>リファクタリング<commit_after>package logbook.internal.gui;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import logbook.bean.BattleLog;
import logbook.bean.BattleTypes.CombinedType;
import logbook.bean.BattleTypes.IFormation;
import logbook.bean.BattleTypes.IMidnightBattle;
import logbook.bean.MapStartNext;
import logbook.bean.Ship;
import logbook.bean.SlotItem;
import logbook.internal.BattleLogs;
import logbook.internal.BattleLogs.SimpleBattleLog;
import logbook.internal.BattleLogs.Unit;
import logbook.internal.LoggerHolder;

/**
 * 戦闘ログのUIコントローラー
 *
 */
public class BattleLogController extends WindowController {

    /** 統計 */
    @FXML
    private TreeTableView<BattleLogCollect> collect;

    /** 集計 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> unit;

    /** 出撃  */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> start;

    /** 勝利  */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> win;

    /** S勝利 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> s;

    /** A勝利 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> a;

    /** B勝利 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> b;

    /** C敗北 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> c;

    /** D敗北 */
    @FXML
    private TreeTableColumn<BattleLogCollect, String> d;

    /** 詳細 */
    @FXML
    private TableView<BattleLogDetail> detail;

    /** 日付 */
    @FXML
    private TableColumn<BattleLogDetail, String> date;

    /** 海域 */
    @FXML
    private TableColumn<BattleLogDetail, String> area;

    /** マス */
    @FXML
    private TableColumn<BattleLogDetail, String> cell;

    /** ボス */
    @FXML
    private TableColumn<BattleLogDetail, String> boss;

    /** 評価 */
    @FXML
    private TableColumn<BattleLogDetail, String> rank;

    /** 艦隊行動 */
    @FXML
    private TableColumn<BattleLogDetail, String> intercept;

    /** 味方陣形 */
    @FXML
    private TableColumn<BattleLogDetail, String> fformation;

    /** 敵陣形 */
    @FXML
    private TableColumn<BattleLogDetail, String> eformation;

    /** 制空権 */
    @FXML
    private TableColumn<BattleLogDetail, String> dispseiku;

    /** 味方触接 */
    @FXML
    private TableColumn<BattleLogDetail, String> ftouch;

    /** 敵触接 */
    @FXML
    private TableColumn<BattleLogDetail, String> etouch;

    /** 敵艦隊 */
    @FXML
    private TableColumn<BattleLogDetail, String> efleet;

    /** ドロップ艦種 */
    @FXML
    private TableColumn<BattleLogDetail, String> dropType;

    /** ドロップ艦娘 */
    @FXML
    private TableColumn<BattleLogDetail, String> dropShip;

    /** 戦闘ログ */
    private Map<Unit, List<SimpleBattleLog>> logMap;

    /** 詳細 */
    private ObservableList<BattleLogDetail> details = FXCollections.observableArrayList();

    @FXML
    void initialize() {
        try {
            TableTool.setVisible(this.detail, this.getClass().toString() + "#" + "detail");

            // 統計
            this.collect.setShowRoot(false);
            this.collect.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

            this.unit.setCellValueFactory(new TreeItemPropertyValueFactory<>("unit"));
            this.start.setCellValueFactory(new TreeItemPropertyValueFactory<>("start"));
            this.win.setCellValueFactory(new TreeItemPropertyValueFactory<>("win"));
            this.s.setCellValueFactory(new TreeItemPropertyValueFactory<>("s"));
            this.a.setCellValueFactory(new TreeItemPropertyValueFactory<>("a"));
            this.b.setCellValueFactory(new TreeItemPropertyValueFactory<>("b"));
            this.c.setCellValueFactory(new TreeItemPropertyValueFactory<>("c"));
            this.d.setCellValueFactory(new TreeItemPropertyValueFactory<>("d"));

            // 選択された時のリスナーを設定
            this.collect.getSelectionModel()
                    .selectedItemProperty()
                    .addListener(this::detail);

            // 詳細
            this.detail.setRowFactory(tv -> {
                TableRow<BattleLogDetail> r = new TableRow<>();
                r.setOnMouseClicked(e -> {
                    if (e.getClickCount() == 2 && (!r.isEmpty())) {
                        BattleLogDetail d = r.getItem();
                        BattleLog log = BattleLogs.read(d.getDate());
                        if (log != null) {
                            try {
                                MapStartNext last = log.getNext().get(log.getNext().size() - 1);
                                CombinedType combinedType = log.getCombinedType();
                                Map<Integer, List<Ship>> deckMap = log.getDeckMap();
                                Map<Integer, SlotItem> itemMap = log.getItemMap();
                                IFormation battle = log.getBattle();
                                IMidnightBattle midnight = log.getMidnight();
                                Set<Integer> escape = log.getEscape();

                                InternalFXMLLoader.showWindow("logbook/gui/battle_detail.fxml", this.getWindow(),
                                        "戦闘ログ", c -> {
                                            ((BattleDetail) c).setData(last, combinedType, deckMap, escape, itemMap,
                                                    battle, midnight);
                                        }, null);
                            } catch (Exception ex) {
                                LoggerHolder.get().error("詳細の表示に失敗しました", ex);
                            }
                        }
                    }
                });
                return r;
            });
            this.detail.setItems(this.details);
            this.detail.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
            this.detail.setOnKeyPressed(TableTool::defaultOnKeyPressedHandler);

            this.date.setCellValueFactory(new PropertyValueFactory<>("date"));
            this.area.setCellValueFactory(new PropertyValueFactory<>("area"));
            this.cell.setCellValueFactory(new PropertyValueFactory<>("cell"));
            this.boss.setCellValueFactory(new PropertyValueFactory<>("boss"));
            this.rank.setCellValueFactory(new PropertyValueFactory<>("rank"));
            this.intercept.setCellValueFactory(new PropertyValueFactory<>("intercept"));
            this.fformation.setCellValueFactory(new PropertyValueFactory<>("fformation"));
            this.eformation.setCellValueFactory(new PropertyValueFactory<>("eformation"));
            this.dispseiku.setCellValueFactory(new PropertyValueFactory<>("dispseiku"));
            this.ftouch.setCellValueFactory(new PropertyValueFactory<>("ftouch"));
            this.etouch.setCellValueFactory(new PropertyValueFactory<>("etouch"));
            this.efleet.setCellValueFactory(new PropertyValueFactory<>("efleet"));
            this.dropType.setCellValueFactory(new PropertyValueFactory<>("dropType"));
            this.dropShip.setCellValueFactory(new PropertyValueFactory<>("dropShip"));

            // 統計
            // ルート要素(非表示)
            TreeItem<BattleLogCollect> root = new TreeItem<BattleLogCollect>(new BattleLogCollect());
            this.collect.setRoot(root);

            this.setCollect();
        } catch (Exception e) {
            LoggerHolder.get().error("FXMLの初期化に失敗しました", e);
        }
    }

    /**
     * ログをセット
     */
    private void setCollect() {
        // 集計単位がキーのマップ
        this.logMap = BattleLogs.readSimpleLog();
        for (Unit unit : Unit.values()) {
            List<SimpleBattleLog> list = this.logMap.get(unit);

            // 単位のルート
            BattleLogCollect unitRootValue = BattleLogs.collect(list, null, false);
            unitRootValue.setUnit(unit.getName());
            unitRootValue.setCollectUnit(unit);

            TreeItem<BattleLogCollect> unitRoot = new TreeItem<BattleLogCollect>(unitRootValue);
            unitRoot.setExpanded(true);

            // ボス
            BattleLogCollect bossValue = BattleLogs.collect(list, null, true);
            bossValue.setUnit("ボス");
            bossValue.setCollectUnit(unit);
            bossValue.setBoss(true);

            TreeItem<BattleLogCollect> boss = new TreeItem<BattleLogCollect>(bossValue);
            unitRoot.getChildren().add(boss);

            // 海域の名前
            List<String> areaNames = list.stream()
                    .map(SimpleBattleLog::getArea)
                    .distinct()
                    .sorted(Comparator.naturalOrder())
                    .collect(Collectors.toList());
            for (String area : areaNames) {
                // 海域毎の集計
                BattleLogCollect areaValue = BattleLogs.collect(list, area, false);
                areaValue.setUnit(area);
                areaValue.setCollectUnit(unit);
                areaValue.setArea(area);

                TreeItem<BattleLogCollect> areaRoot = new TreeItem<BattleLogCollect>(areaValue);

                // 海域ボス
                BattleLogCollect areaBossValue = BattleLogs.collect(list, area, true);
                areaBossValue.setUnit("ボス");
                areaBossValue.setCollectUnit(unit);
                areaBossValue.setArea(area);
                areaBossValue.setBoss(true);

                TreeItem<BattleLogCollect> areaBoss = new TreeItem<BattleLogCollect>(areaBossValue);
                areaRoot.getChildren().add(areaBoss);

                unitRoot.getChildren().add(areaRoot);
            }

            this.collect.getRoot().getChildren().add(unitRoot);
        }
    }

    /**
     * ログの更新
     */
    @FXML
    void reloadAction(ActionEvent event) {
        // 中身をクリア
        this.collect.getRoot().getChildren().clear();

        this.setCollect();
    }

    /**
     * クリップボードにコピー
     */
    @FXML
    void copyDetail() {
        TableTool.selectionCopy(this.detail);
    }

    /**
     * すべてを選択
     */
{'fraction_non_alphanumeric': 0.11270355204266261, 'fraction_numerical': 0.00019045805161413198, 'mean_word_length': 2.221813161527842, 'pattern_counts': {'":': 0, '<': 137, '<?xml version=': 0, '>': 143, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3832605', 'n_tokens_mistral': 6136, 'n_tokens_neox': 6131, 'n_words': 915}