OSDN Git Service

30ba16c4e8aff0573ca6e7d39f7efed41e5e00eb
[delesterandomselector/DelesteRandomSelector.git] / src / com / ranfa / main / DelesteRandomSelector.java
1 package com.ranfa.main;
2
3 import java.awt.BorderLayout;
4 import java.awt.CardLayout;
5 import java.awt.Desktop;
6 import java.awt.EventQueue;
7 import java.awt.Font;
8 import java.io.IOException;
9 import java.net.URI;
10 import java.net.URISyntaxException;
11 import java.nio.file.Files;
12 import java.nio.file.Paths;
13 import java.text.Normalizer;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Random;
19 import java.util.concurrent.CompletableFuture;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.function.BiConsumer;
23 import java.util.stream.Collectors;
24
25 import javax.swing.DefaultComboBoxModel;
26 import javax.swing.JButton;
27 import javax.swing.JCheckBox;
28 import javax.swing.JComboBox;
29 import javax.swing.JFrame;
30 import javax.swing.JLabel;
31 import javax.swing.JOptionPane;
32 import javax.swing.JPanel;
33 import javax.swing.JScrollPane;
34 import javax.swing.JSpinner;
35 import javax.swing.JTabbedPane;
36 import javax.swing.JTextArea;
37 import javax.swing.border.EmptyBorder;
38
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.jgoodies.forms.layout.ColumnSpec;
43 import com.jgoodies.forms.layout.FormLayout;
44 import com.jgoodies.forms.layout.FormSpecs;
45 import com.jgoodies.forms.layout.RowSpec;
46 import com.ranfa.lib.CheckVersion;
47 import com.ranfa.lib.Easter;
48 import com.ranfa.lib.EstimateAlbumTypeCycle;
49 import com.ranfa.lib.ManualUpdateThreadImpl;
50 import com.ranfa.lib.Scraping;
51 import com.ranfa.lib.SettingJSONProperty;
52 import com.ranfa.lib.Settings;
53 import com.ranfa.lib.Song;
54 import com.ranfa.lib.TwitterIntegration;
55 import com.ranfa.lib.Version;
56 import com.ranfa.lib.concurrent.CountedThreadFactory;
57 import com.ranfa.lib.songinfo.FetchFromAPI;
58
59 @Version(major = 3, minor = 1, patch = 0)
60 public class DelesteRandomSelector extends JFrame {
61
62     private static ArrayList<Song> selectedSongsList = new ArrayList<>();
63
64     private JPanel contentPane;
65     private SettingJSONProperty property = new SettingJSONProperty();
66     private String[] integratorArray;
67     private boolean integratorBool = false;
68     private CompletableFuture<Void> softwareUpdateFuture = null;
69     private CompletableFuture<Void> albumTypeEstimateFuture = null;
70     private String albumType = Messages.MSGAlbumTypeBeingCalculated.toString();
71     private Logger logger = LoggerFactory.getLogger(DelesteRandomSelector.class);
72     private ManualUpdateThreadImpl impl;
73     private List<Song> toolIntegrateList;
74     private FetchFromAPI fetchData;
75     private List<Map<String, String>> listToolMapData;
76     private CompletableFuture<List<Map<String, String>>> listToolMapDataFuture;
77     private Easter easter;
78     private JPanel panelMain;
79     private JPanel panelNorthMain;
80     private JLabel labelTitle;
81     private JLabel labelVersion;
82     private JPanel panelWestMain;
83     private JLabel labelDifficulty;
84     private JComboBox<String[]> comboDifficultySelect;
85     private JComboBox<String[]> comboAttribute;
86     private JLabel labelLevel;
87     private JSpinner spinnerLevel;
88     private JCheckBox checkLessLv;
89     private JCheckBox checkMoreLv;
90     private JLabel labelLvCaution;
91     private JPanel panelEastMain;
92     private JButton btnImport;
93     private JButton btnConfig;
94     private JButton btnStart;
95     private JButton btnManualUpdate;
96     private JButton btnTwitterIntegration;
97     private JButton btnExit;
98     private JPanel panelCenterMain;
99     private JScrollPane scrollPane;
100     private JTextArea textArea;
101     private JTabbedPane tabbedPane;
102     private JPanel panelTool;
103     private JPanel panelNorthTool;
104     private JLabel labelSubToolTitle;
105     private JLabel labelVersionTool;
106     private JPanel panelCenterTool;
107     private JLabel lblNewLabel;
108     private JLabel labelSongNameToolTitle;
109     private JLabel labelSongNameToolTip;
110     private JLabel labelAttributeToolTitle;
111     private JLabel labelAttributeToolTip;
112     private JLabel labelDifficultyToolTitle;
113     private JLabel labelDifficultyToolTip;
114     private JLabel labelLevelToolTitle;
115     private JLabel labelLevelToolTip;
116     private JLabel labelNotesToolTitle;
117     private JLabel labelNotesToolTip;
118     private JButton btnPrevSongTool;
119     private JButton btnNextSongTool;
120     private JLabel labelSlashTool;
121     private JLabel labelCurrentSongOrderTool;
122     private JLabel labelSongLimitTool;
123     private JLabel labelLyricToolTitle;
124     private JLabel labelLyricToolTip;
125     private JLabel labelComposerToolTitle;
126     private JLabel labelArrangeToolTitle;
127     private JLabel labelComposerToolTip;
128     private JLabel labelArrangeToolTip;
129     private JLabel labelMemberToolTitle;
130     private JLabel labelMemberToolTip;
131     private JButton btnMoreInfoTool;
132     
133     BiConsumer<ArrayList<Song>, ArrayList<Song>> updateConsumer = (list1, list2) -> {
134             this.logger.info("Checking database updates...");
135             if(list1.size() > list2.size()) {
136                 long time = System.currentTimeMillis();
137                 this.logger.info("{} Update detected.", (list1.size() - list2.size()));
138                 Scraping.writeToJson(list1);
139                 this.logger.info("Update completed in {} ms", (System.currentTimeMillis() - time));
140                 this.logger.info("Updated database size: {}", list1.size());
141             } else {
142                 this.logger.info("database is up-to-date.");
143             }
144         };
145         Runnable setEnabled = () -> {
146             try {
147                 Thread.sleep(3 * 1000L);
148             } catch (InterruptedException e1) {
149                 this.logger.error("Thread has been interrupted during waiting cooldown.", e1);
150             }
151             this.btnImport.setEnabled(true);
152             this.btnImport.setText(Messages.MSGNarrowingDownSongs.toString());
153         };
154
155     /**
156      * Launch the application.
157      */
158     public static void main(String[] args) {
159         EventQueue.invokeLater(() -> {
160             try {
161                 DelesteRandomSelector frame = new DelesteRandomSelector();
162                 frame.setVisible(true);
163             } catch (Exception e) {
164                 e.printStackTrace();
165             }
166
167         });
168     }
169
170     /**
171      * log file prefix:
172      *  this.getClass() + ":[LEVEL]: " +
173      */
174
175     /**
176      * Create the frame.
177      */
178     public DelesteRandomSelector() {
179     ExecutorService es = Executors.newCachedThreadPool(new CountedThreadFactory(() -> "DRS", "AsyncEventInquerier", false));
180         this.contentPane = new JPanel();
181         boolean isFirst = !Scraping.databaseExists();
182         // database check phase
183         CompletableFuture.runAsync(() -> {
184                 if(isFirst) {
185                     JOptionPane.showMessageDialog(this, Messages.MSGDatabaseNotExist.toString());
186                     if(!Scraping.writeToJson(Scraping.getWholeData())) {
187                         JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
188                         throw new NullPointerException("FATAL: cannot continue!");
189                     }
190                 }
191         }, es).whenCompleteAsync((ret, ex) -> {
192                 if(ex != null) {
193                         logger.error("Exception was thrown during concurrent process", ex);
194                         if(ex instanceof NullPointerException) {
195                                 throw new RuntimeException(ex);
196                         }
197                         throw new IllegalStateException(ex);
198                 }
199         }, es);
200         CompletableFuture<ArrayList<Song>> getFromJsonFuture = CompletableFuture.supplyAsync(() -> Scraping.getFromJson(), es);
201         CompletableFuture<ArrayList<Song>> getWholeDataFuture = CompletableFuture.supplyAsync(() -> Scraping.getWholeData(), es);
202         // setting check phase
203         CompletableFuture.runAsync(() -> {
204                 if(!Settings.fileExists() && !Settings.writeDownJSON()) {
205                     JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
206                     throw new NullPointerException("FATAL: cannot continue!");
207                 }
208         }, es).whenCompleteAsync((ret, ex) -> {
209                 if(ex != null) {
210                         logger.error("Exception was thrown during concurrent process", ex);
211                         if(ex instanceof NullPointerException) {
212                                 throw new RuntimeException(ex);
213                         }
214                         throw new IllegalStateException(ex);
215                 }
216                 this.logger.debug("Loading settings...");
217                 this.property.setCheckLibraryUpdates(Settings.needToCheckLibraryUpdates());
218                 this.property.setCheckVersion(Settings.needToCheckVersion());
219                 this.property.setWindowWidth(Settings.getWindowWidth());
220                 this.property.setWindowHeight(Settings.getWindowHeight());
221                 this.property.setSongLimit(Settings.getSongsLimit());
222                 this.property.setSaveScoreLog(Settings.saveScoreLog());
223                 this.logger.debug("Load settings done.");
224                 this.logger.debug("Version check: {}", this.property.isCheckVersion());
225                 this.logger.debug("Library update check: {}", this.property.isCheckLibraryUpdates());
226                 this.logger.debug("Window Width: {}", this.property.getWindowWidth());
227                 this.logger.debug("Window Height: {}", this.property.getWindowHeight());
228                 this.logger.debug("Song Limit: {}", this.property.getSongLimit());
229                 this.logger.debug("SaveScoreLog: {}", this.property.isSaveScoreLog());
230                 if(this.property.isCheckVersion()) {
231                     this.softwareUpdateFuture = CompletableFuture.runAsync(() -> CheckVersion.needToBeUpdated(), es);
232                 }
233                 if(this.property.isCheckLibraryUpdates()) {
234                     CompletableFuture<Void> updatedFuture = getWholeDataFuture.thenAcceptBothAsync(getFromJsonFuture, updateConsumer, es);
235                     updatedFuture.thenRunAsync(setEnabled, es);
236                 }
237         }, es);
238         CompletableFuture.runAsync(() -> {
239                 EstimateAlbumTypeCycle.Initialization();
240                 if(Files.exists(Paths.get("generated/albumCycle.json"))) {
241                     this.albumType = EstimateAlbumTypeCycle.getCurrentCycle();
242                 }
243         }, es).whenCompleteAsync((ret, ex) -> {
244                 if(ex != null) {
245                         logger.error("Exception was thrown during concurrent process", ex);
246                         throw new IllegalStateException(ex);
247                 }
248         }, es);
249         getWholeDataFuture.thenAcceptAsync(list -> this.logger.info("Scraping data size:" + list.size()), es);
250         getFromJsonFuture.thenAcceptAsync(list -> this.logger.info("Currently database size:" + list.size()), es);
251         // easter phase
252         CompletableFuture.runAsync(() -> {
253                 this.easter = new Easter();
254                 this.setTitle(this.easter.getTodaysBirth());
255         }, es);
256         this.logger.debug("Version: {}", CheckVersion.getVersion());
257         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
258         // this.setBounds(100, 100, this.property.getWindowWidth(), this.property.getWindowHeight());
259         this.setBounds(100, 100, 960, 540);
260         this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
261         this.setContentPane(this.contentPane);
262         contentPane.setLayout(new CardLayout(0, 0));
263         
264         panelMain = new JPanel();
265         panelMain.setLayout(new BorderLayout(0, 0));
266         
267         panelNorthMain = new JPanel();
268         panelMain.add(panelNorthMain, BorderLayout.NORTH);
269         panelNorthMain.setLayout(new FormLayout(new ColumnSpec[] {
270                         ColumnSpec.decode("829px"),
271                         FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
272                         ColumnSpec.decode("center:94px"),},
273                 new RowSpec[] {
274                         RowSpec.decode("20px"),}));
275         
276         labelTitle = new JLabel(Messages.MSGTitle.toString());
277         labelTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 16));
278         panelNorthMain.add(labelTitle, "1, 1, center, top");
279         
280         labelVersion = new JLabel(CheckVersion.getVersion());
281         labelVersion.setFont(new Font("SansSerif", Font.BOLD, 12));
282         panelNorthMain.add(labelVersion, "3, 1, center, center");
283         
284         panelWestMain = new JPanel();
285         panelMain.add(panelWestMain, BorderLayout.WEST);
286         panelWestMain.setLayout(new FormLayout(new ColumnSpec[] {
287                         FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
288                         ColumnSpec.decode("120px"),},
289                 new RowSpec[] {
290                         FormSpecs.LINE_GAP_ROWSPEC,
291                         RowSpec.decode("25px"),
292                         FormSpecs.RELATED_GAP_ROWSPEC,
293                         FormSpecs.DEFAULT_ROWSPEC,
294                         FormSpecs.RELATED_GAP_ROWSPEC,
295                         FormSpecs.DEFAULT_ROWSPEC,
296                         FormSpecs.RELATED_GAP_ROWSPEC,
297                         FormSpecs.DEFAULT_ROWSPEC,
298                         FormSpecs.RELATED_GAP_ROWSPEC,
299                         FormSpecs.DEFAULT_ROWSPEC,
300                         FormSpecs.RELATED_GAP_ROWSPEC,
301                         FormSpecs.DEFAULT_ROWSPEC,
302                         FormSpecs.RELATED_GAP_ROWSPEC,
303                         FormSpecs.DEFAULT_ROWSPEC,
304                         FormSpecs.RELATED_GAP_ROWSPEC,
305                         RowSpec.decode("max(41dlu;default)"),}));
306         
307         labelDifficulty = new JLabel(Messages.MSGSelectDifficulty.toString());
308         labelDifficulty.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
309         panelWestMain.add(labelDifficulty, "2, 2, center, center");
310         
311         comboDifficultySelect = new JComboBox<>();
312         comboDifficultySelect.setModel(new DefaultComboBoxModel(new String[] {Messages.MSGNonSelected.toString(), "DEBUT", "REGULAR", "PRO", "MASTER", "MASTER+", "ⓁMASTER+", "LIGHT", "TRICK", "PIANO", "FORTE", "WITCH"}));
313         comboDifficultySelect.setFont(new Font("Dialog", Font.BOLD, 12));
314         panelWestMain.add(comboDifficultySelect, "2, 4, fill, fill");
315         
316         comboAttribute = new JComboBox<>();
317         comboAttribute.setModel(new DefaultComboBoxModel(new String[] {Messages.MSGNonSelected.toString(), "全タイプ", "キュート", "クール", "パッション"}));
318         comboAttribute.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
319         panelWestMain.add(comboAttribute, "2, 6, fill, top");
320         
321         labelLevel = new JLabel(Messages.MSGSongLevel.toString());
322         labelLevel.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
323         panelWestMain.add(labelLevel, "2, 8, center, center");
324         
325         spinnerLevel = new JSpinner();
326         panelWestMain.add(spinnerLevel, "2, 10, fill, center");
327         
328         checkLessLv = new JCheckBox(Messages.MSGBelowSpecificLevel.toString());
329         checkLessLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
330         panelWestMain.add(checkLessLv, "2, 12, left, top");
331         
332         checkMoreLv = new JCheckBox(Messages.MSGOverSpecificLevel.toString());
333         checkMoreLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
334         panelWestMain.add(checkMoreLv, "2, 14, left, top");
335         
336         labelLvCaution = new JLabel(Messages.MSGLevelCheckboxInfo.toString());
337         labelLvCaution.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
338         panelWestMain.add(labelLvCaution, "2, 16, left, center");
339         
340         panelEastMain = new JPanel();
341         panelMain.add(panelEastMain, BorderLayout.EAST);
342         panelEastMain.setLayout(new FormLayout(new ColumnSpec[] {
343                         FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
344                         ColumnSpec.decode("100px"),},
345                 new RowSpec[] {
346                         FormSpecs.LINE_GAP_ROWSPEC,
347                         RowSpec.decode("77px"),
348                         FormSpecs.RELATED_GAP_ROWSPEC,
349                         FormSpecs.DEFAULT_ROWSPEC,
350                         FormSpecs.RELATED_GAP_ROWSPEC,
351                         FormSpecs.DEFAULT_ROWSPEC,
352                         FormSpecs.RELATED_GAP_ROWSPEC,
353                         FormSpecs.DEFAULT_ROWSPEC,
354                         FormSpecs.RELATED_GAP_ROWSPEC,
355                         RowSpec.decode("max(36dlu;default)"),
356                         FormSpecs.RELATED_GAP_ROWSPEC,
357                         FormSpecs.DEFAULT_ROWSPEC,}));
358         
359         btnImport = new JButton(Messages.MSGUpdatingDatabase.toString());
360         btnImport.addActionListener(e -> {
361                 CompletableFuture.runAsync(() -> {
362                         if(impl != null) {
363                                 if(!impl.getFlag()) {
364                                         JOptionPane.showMessageDialog(null, Messages.MSGManualUpdateNotCompleteYet.toString());
365                                 }
366                         }
367                         ArrayList<Song> fromJson = Scraping.getFromJson();
368                         ArrayList<Song> specificlevelList = Scraping.getSpecificLevelSongs(fromJson, (Integer)DelesteRandomSelector.this.spinnerLevel.getValue(), DelesteRandomSelector.this.checkLessLv.isSelected(), DelesteRandomSelector.this.checkMoreLv.isSelected());
369                         ArrayList<Song> specificDifficultyList = Scraping.getSpecificDifficultySongs(specificlevelList, DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().toString());
370                         ArrayList<Song> specificAttributeList = Scraping.getSpecificAttributeSongs(specificDifficultyList, DelesteRandomSelector.this.comboAttribute.getSelectedItem().toString());
371                         ArrayList<Song> specificTypeList = Scraping.getSpecificAlbumTypeSongs(specificAttributeList, EstimateAlbumTypeCycle.getCurrentCycle());
372                         if(!selectedSongsList.isEmpty()) {
373                                 selectedSongsList.clear();
374                         }
375                         selectedSongsList.addAll((DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS)) ? specificTypeList : specificAttributeList);
376                         DelesteRandomSelector.this.logger.info("Songs are selected.We are Ready to go.");
377                         JOptionPane.showMessageDialog(null, Messages.MSGCompleteNarrowDown.toString());
378                 }, es).whenCompleteAsync((ret, ex) -> {
379                         if(ex != null) {
380                                 logger.error("Exception was thrown during concurrent process", ex);
381                                 throw new IllegalStateException(ex);
382                         }
383                 }, es);
384         });
385         btnImport.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
386         btnImport.setEnabled(false);
387         panelEastMain.add(btnImport, "2, 2, fill, fill");
388         
389         btnConfig = new JButton(Messages.MSGConfigurations.toString());
390         btnConfig.addActionListener(e -> {
391                 CompletableFuture.runAsync(() -> {
392                         ProcessBuilder builder = new ProcessBuilder("java", "-jar", "Configurations.jar");
393                         try {
394                                 builder.start();
395                         } catch (IOException e1) {
396                                 logger.error("Cannot start external jar file. maybe are you running this with mac or linux?", e);
397                         }
398                 }).whenCompleteAsync((ret, ex) -> {
399                         if(ex != null) {
400                                 logger.error("Exception was thrown during concurrent process", ex);
401                                 throw new RuntimeException(ex);
402                         }
403                 });
404         });
405         panelEastMain.add(btnConfig, "2, 6, fill, fill");
406         
407         btnStart = new JButton(Messages.MSGCalcStart.toString());
408         btnStart.addActionListener(e -> {
409                 CompletableFuture.runAsync(() -> {
410                         Random random = new Random(System.currentTimeMillis());
411                         toolIntegrateList = new ArrayList<>();
412                         StringBuilder paneBuilder = new StringBuilder();
413                         DelesteRandomSelector.this.integratorArray = new String[DelesteRandomSelector.this.property.getSongLimit()];
414                         for(int i = 0; i < DelesteRandomSelector.this.property.getSongLimit(); i++) {
415                                 int randomInt = random.nextInt(selectedSongsList.size());
416                                 String typeString = DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS) ? EstimateAlbumTypeCycle.getCurrentCycle() : "";
417                                 paneBuilder.append(i + 1)
418                                         .append(Messages.MSGNumberOfSongs.toString())
419                                         .append(" ")
420                                         .append(selectedSongsList.get(randomInt).getAttribute())
421                                         .append("[")
422                                         .append(selectedSongsList.get(randomInt).getDifficulty())
423                                         .append("]「")
424                                         .append(selectedSongsList.get(randomInt).getName())
425                                         .append("」!(Lv:")
426                                         .append(selectedSongsList.get(randomInt).getLevel())
427                                         .append(" ")
428                                         .append(typeString)
429                                         .append(")\n\n");
430                                 this.integratorArray[i] = selectedSongsList.get(randomInt).getName() + "(Lv" + selectedSongsList.get(randomInt).getLevel() + ")\n";
431                                 toolIntegrateList.add(selectedSongsList.get(randomInt));
432                         }
433                                 paneBuilder.append(Messages.MSGThisPhrase.toString())
434                                         .append(this.property.getSongLimit())
435                                         .append(Messages.MSGPlayPhrase.toString());
436                         DelesteRandomSelector.this.textArea.setText(paneBuilder.toString());
437                         DelesteRandomSelector.this.integratorBool = true;
438                         DelesteRandomSelector.this.logger.info("show up completed.");
439                         labelCurrentSongOrderTool.setText("null");
440                         listToolMapDataFuture = CompletableFuture.supplyAsync(() -> {
441                                 List<String> data = toolIntegrateList.stream()
442                                                 .map(s -> s.getName())
443                                                 .collect(Collectors.toList());
444                                 fetchData = new FetchFromAPI(data.toArray(new String[0]));
445                                 return fetchData.getInformation();
446                         }, es);
447                         logger.debug("api fetch inquery published");
448                 }, es).whenCompleteAsync((ret, ex) -> {
449                         if(ex != null) {
450                                 logger.error("Exception was thrown during concurrent process", ex);
451                         }
452                 }, es);
453         });
454         btnStart.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
455         panelEastMain.add(btnStart, "2, 4, fill, fill");
456         
457         btnManualUpdate = new JButton(Messages.MSGManualUpdate.toString());
458         btnManualUpdate.addActionListener(e -> {
459                 impl = new ManualUpdateThreadImpl();
460                 CompletableFuture.runAsync(impl, es).whenCompleteAsync((t, u) -> {
461                         if(u != null) {
462                                 logger.warn("Exception while processing update manually.", e);
463                                 JOptionPane.showMessageDialog(null, "There was a problem during processing library update manually.\nIf this appears repeatedly, please contact developer with your app log.");
464                         }
465                 }, es);
466         });
467         panelEastMain.add(btnManualUpdate, "2, 8, fill, fill");
468         
469         btnTwitterIntegration = new JButton(Messages.MSGTwitterIntegration.toString());
470         btnTwitterIntegration.addActionListener(e -> {
471                 CompletableFuture.runAsync(() -> {
472                         boolean authorizationStatus = TwitterIntegration.authorization();
473                         String updatedStatus = Messages.MSGUsingThisAppPhrase.toString();
474                         int lengthLimit = updatedStatus.length();
475                         boolean isBroken = false;
476                         if(!DelesteRandomSelector.this.integratorBool) {
477                                 JOptionPane.showMessageDialog(null, Messages.MSGNotPlayYet.toString());
478                                 return;
479                         }
480                         for (String element : DelesteRandomSelector.this.integratorArray) {
481                                 updatedStatus = updatedStatus + element;
482                                 lengthLimit += element.length();
483                                 if(lengthLimit > 69) {
484                                         isBroken = true;
485                                         break;
486                                 }
487                         }
488                         if(isBroken) {
489                                 updatedStatus = updatedStatus + Messages.MSGTwitterPlayOtherwisePhrase.toString() + "\n#DelesteRandomSelector #デレステ ";
490                         } else {
491                                 updatedStatus = updatedStatus + Messages.MSGTwitterPlayOnlyPhrase.toString() + "\n#DelesteRandomSelector #デレステ ";
492                         }
493                         DelesteRandomSelector.this.logger.info("status message constructed.");
494                         lengthLimit = updatedStatus.length();
495                         if(authorizationStatus) {
496                                 int option = JOptionPane.showConfirmDialog(null, Messages.MSGTwitterIntegrationConfirm.toString() + updatedStatus + Messages.MSGStringLength.toString() + lengthLimit);
497                                 DelesteRandomSelector.this.logger.info("user seletced: " + option);
498                                 switch(option) {
499                                 case JOptionPane.OK_OPTION:
500                                         TwitterIntegration.PostTwitter(updatedStatus);
501                                         DelesteRandomSelector.this.logger.info("Success to update the status.");
502                                         JOptionPane.showMessageDialog(null, Messages.MSGCompletePost.toString());
503                                         break;
504                                 case JOptionPane.NO_OPTION:
505                                         DelesteRandomSelector.this.logger.info("There is no will to post.");
506                                         break;
507                                 case JOptionPane.CANCEL_OPTION:
508                                         DelesteRandomSelector.this.logger.info("The Operation was canceled by user.");
509                                         break;
510                                 default:
511                                         break;
512                                 }
513                         } else {
514                                 DelesteRandomSelector.this.logger.info("seems to reject the permission.it should need try again.");
515                         }
516                 }, es).whenCompleteAsync((ret, ex) -> {
517                         if(ex != null) {
518                                 logger.error("Exception was thrown during concurrent process");
519                         }
520                 }, es);
521         });
522         btnTwitterIntegration.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 11));
523         panelEastMain.add(btnTwitterIntegration, "2, 10, fill, fill");
524         
525         btnExit = new JButton(Messages.MSGTerminate.toString());
526         btnExit.addActionListener(e -> {
527                 if(DelesteRandomSelector.this.softwareUpdateFuture.isDone() || DelesteRandomSelector.this.albumTypeEstimateFuture.isDone() || !this.impl.getFlag()) {
528                         DelesteRandomSelector.this.logger.info("Requested Exit by Button.");
529                         logger.info("Shut down thread pool.");
530                         es.shutdown();
531                         System.exit(0);
532                 } else {
533                         JOptionPane.showMessageDialog(null, Messages.MSGInternalYpdateNotDoneYet.toString());
534                 }
535         });
536         btnExit.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
537         panelEastMain.add(btnExit, "2, 12, fill, fill");
538         
539         panelCenterMain = new JPanel();
540         panelMain.add(panelCenterMain, BorderLayout.CENTER);
541         panelCenterMain.setLayout(new BorderLayout(0, 0));
542         
543         scrollPane = new JScrollPane();
544         panelCenterMain.add(scrollPane);
545         
546         textArea = new JTextArea();
547         textArea.setText(Messages.MSGNarrowDownProcedure.toString() + property.getSongLimit() + Messages.MSGCurrentAlbumType.toString() + albumType);
548         textArea.setEditable(false);
549         scrollPane.setViewportView(textArea);
550         
551         tabbedPane = new JTabbedPane(JTabbedPane.TOP);
552         tabbedPane.addChangeListener(e -> {
553                 CompletableFuture.runAsync(() -> {
554                         String currentTabName = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
555                         if(currentTabName.equals("SubTools") && labelCurrentSongOrderTool.getText().equals("null")) {
556                                 logger.info("Detected switching tool tab");
557                                 listToolMapData = listToolMapDataFuture.join();
558                                 Song firstSong = toolIntegrateList.get(0);
559                                 Map<String, String> fetchMap = new HashMap<>();
560                                 for(Map<String, String> tmpMap : listToolMapData) {
561                                         String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
562                                         String normalizeLocalName = Normalizer.normalize(firstSong.getName(), Normalizer.Form.NFKD);
563                                         if(normalizeApiName.equals(normalizeLocalName)) {
564                                                 fetchMap = tmpMap;
565                                                 break;
566                                         }
567                                 }
568                                 labelSongNameToolTip.setText(firstSong.getName());
569                                 labelAttributeToolTip.setText(firstSong.getAttribute());
570                                 labelDifficultyToolTip.setText(firstSong.getDifficulty());
571                                 labelLevelToolTip.setText(String.valueOf(firstSong.getLevel()));
572                                 labelNotesToolTip.setText(String.valueOf(firstSong.getNotes()));
573                                 labelCurrentSongOrderTool.setText("1");
574                                 labelLyricToolTip.setText(fetchMap.get("lyric"));
575                                 labelComposerToolTip.setText(fetchMap.get("composer"));
576                                 labelArrangeToolTip.setText(fetchMap.get("arrange"));
577                                 labelMemberToolTip.setText(fetchMap.get("member"));
578                         }
579                 }, es).whenCompleteAsync((ret, ex) -> {
580                         if(ex != null) {
581                                 logger.error("Exception was thrown during concurrent process", ex);
582                         }
583                 }, es);
584         });
585         tabbedPane.addTab("Main", null, panelMain, null);
586         contentPane.add(tabbedPane, "name_307238585319500");
587         
588         panelTool = new JPanel();
589         tabbedPane.addTab("SubTools", null, panelTool, null);
590         panelTool.setLayout(new BorderLayout(0, 0));
591         
592         panelNorthTool = new JPanel();
593         panelTool.add(panelNorthTool, BorderLayout.NORTH);
594         panelNorthTool.setLayout(new FormLayout(new ColumnSpec[] {
595                         ColumnSpec.decode("center:max(524dlu;default)"),
596                         FormSpecs.RELATED_GAP_COLSPEC,
597                         ColumnSpec.decode("max(30dlu;default)"),},
598                 new RowSpec[] {
599                         RowSpec.decode("max(16dlu;default)"),}));
600         
601         labelSubToolTitle = new JLabel("補助ツール");
602         labelSubToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 16));
603         panelNorthTool.add(labelSubToolTitle, "1, 1");
604         
605         labelVersionTool = new JLabel(CheckVersion.getVersion());
606         labelVersionTool.setFont(new Font("SansSerif", Font.BOLD, 12));
607         panelNorthTool.add(labelVersionTool, "3, 1");
608         
609         panelCenterTool = new JPanel();
610         panelTool.add(panelCenterTool, BorderLayout.CENTER);
611         panelCenterTool.setLayout(new FormLayout(new ColumnSpec[] {
612                         FormSpecs.RELATED_GAP_COLSPEC,
613                         ColumnSpec.decode("max(40dlu;default)"),
614                         FormSpecs.RELATED_GAP_COLSPEC,
615                         ColumnSpec.decode("10dlu"),
616                         FormSpecs.RELATED_GAP_COLSPEC,
617                         ColumnSpec.decode("10dlu"),
618                         FormSpecs.RELATED_GAP_COLSPEC,
619                         ColumnSpec.decode("max(10dlu;default)"),
620                         FormSpecs.RELATED_GAP_COLSPEC,
621                         ColumnSpec.decode("max(90dlu;default)"),
622                         FormSpecs.RELATED_GAP_COLSPEC,
623                         FormSpecs.DEFAULT_COLSPEC,
624                         FormSpecs.RELATED_GAP_COLSPEC,
625                         FormSpecs.DEFAULT_COLSPEC,
626                         FormSpecs.RELATED_GAP_COLSPEC,
627                         FormSpecs.DEFAULT_COLSPEC,
628                         FormSpecs.RELATED_GAP_COLSPEC,
629                         ColumnSpec.decode("max(90dlu;default)"),
630                         FormSpecs.RELATED_GAP_COLSPEC,
631                         FormSpecs.DEFAULT_COLSPEC,
632                         FormSpecs.RELATED_GAP_COLSPEC,
633                         FormSpecs.DEFAULT_COLSPEC,
634                         FormSpecs.RELATED_GAP_COLSPEC,
635                         FormSpecs.DEFAULT_COLSPEC,
636                         FormSpecs.RELATED_GAP_COLSPEC,
637                         ColumnSpec.decode("max(90dlu;default)"),},
638                 new RowSpec[] {
639                         FormSpecs.RELATED_GAP_ROWSPEC,
640                         FormSpecs.DEFAULT_ROWSPEC,
641                         FormSpecs.RELATED_GAP_ROWSPEC,
642                         FormSpecs.DEFAULT_ROWSPEC,
643                         FormSpecs.RELATED_GAP_ROWSPEC,
644                         FormSpecs.DEFAULT_ROWSPEC,
645                         FormSpecs.RELATED_GAP_ROWSPEC,
646                         FormSpecs.DEFAULT_ROWSPEC,
647                         FormSpecs.RELATED_GAP_ROWSPEC,
648                         FormSpecs.DEFAULT_ROWSPEC,
649                         FormSpecs.RELATED_GAP_ROWSPEC,
650                         FormSpecs.DEFAULT_ROWSPEC,
651                         FormSpecs.RELATED_GAP_ROWSPEC,
652                         FormSpecs.DEFAULT_ROWSPEC,
653                         FormSpecs.RELATED_GAP_ROWSPEC,
654                         FormSpecs.DEFAULT_ROWSPEC,
655                         FormSpecs.RELATED_GAP_ROWSPEC,
656                         FormSpecs.DEFAULT_ROWSPEC,
657                         FormSpecs.RELATED_GAP_ROWSPEC,
658                         FormSpecs.DEFAULT_ROWSPEC,
659                         FormSpecs.RELATED_GAP_ROWSPEC,
660                         FormSpecs.DEFAULT_ROWSPEC,
661                         FormSpecs.RELATED_GAP_ROWSPEC,
662                         FormSpecs.DEFAULT_ROWSPEC,
663                         FormSpecs.RELATED_GAP_ROWSPEC,
664                         FormSpecs.DEFAULT_ROWSPEC,
665                         FormSpecs.RELATED_GAP_ROWSPEC,
666                         FormSpecs.DEFAULT_ROWSPEC,
667                         FormSpecs.RELATED_GAP_ROWSPEC,
668                         FormSpecs.DEFAULT_ROWSPEC,
669                         FormSpecs.RELATED_GAP_ROWSPEC,
670                         FormSpecs.DEFAULT_ROWSPEC,
671                         FormSpecs.RELATED_GAP_ROWSPEC,
672                         FormSpecs.DEFAULT_ROWSPEC,
673                         FormSpecs.RELATED_GAP_ROWSPEC,
674                         FormSpecs.DEFAULT_ROWSPEC,}));
675         
676         lblNewLabel = new JLabel("今回プレイした楽曲");
677         lblNewLabel.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
678         panelCenterTool.add(lblNewLabel, "2, 2, center, default");
679         
680         labelSongNameToolTitle = new JLabel("Song Name");
681         labelSongNameToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
682         panelCenterTool.add(labelSongNameToolTitle, "2, 6, center, default");
683         
684         labelSongNameToolTip = new JLabel("Please wait...");
685         labelSongNameToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
686         panelCenterTool.add(labelSongNameToolTip, "10, 6, center, default");
687         
688         labelMemberToolTitle = new JLabel("Member");
689         labelMemberToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
690         panelCenterTool.add(labelMemberToolTitle, "18, 6, center, default");
691         
692         labelMemberToolTip = new JLabel("Please wait...");
693         labelMemberToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
694         panelCenterTool.add(labelMemberToolTip, "26, 6, center, default");
695         
696         labelAttributeToolTitle = new JLabel("Song Attribute");
697         labelAttributeToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
698         panelCenterTool.add(labelAttributeToolTitle, "2, 10, center, default");
699         
700         labelAttributeToolTip = new JLabel("Please wait...");
701         labelAttributeToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
702         panelCenterTool.add(labelAttributeToolTip, "10, 10, center, default");
703         
704         labelDifficultyToolTitle = new JLabel("Difficulty");
705         labelDifficultyToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
706         panelCenterTool.add(labelDifficultyToolTitle, "2, 14, center, default");
707         
708         labelDifficultyToolTip = new JLabel("Please wait...");
709         labelDifficultyToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
710         panelCenterTool.add(labelDifficultyToolTip, "10, 14, center, default");
711         
712         labelLevelToolTitle = new JLabel("Song Level");
713         labelLevelToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
714         panelCenterTool.add(labelLevelToolTitle, "2, 18, center, default");
715         
716         labelLevelToolTip = new JLabel("Please wait...");
717         labelLevelToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
718         panelCenterTool.add(labelLevelToolTip, "10, 18, center, default");
719         
720         labelNotesToolTitle = new JLabel("Notes");
721         labelNotesToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
722         panelCenterTool.add(labelNotesToolTitle, "2, 22, center, default");
723         
724         labelNotesToolTip = new JLabel("Please wait...");
725         labelNotesToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
726         panelCenterTool.add(labelNotesToolTip, "10, 22, center, default");
727         
728         btnPrevSongTool = new JButton("prev");
729         btnPrevSongTool.addActionListener(e -> {
730                 CompletableFuture.runAsync(() -> {
731                         int currentIndex = Integer.parseInt(labelCurrentSongOrderTool.getText()) - 1;
732                         if(currentIndex != 0) {
733                                 Song prevSong = toolIntegrateList.get(currentIndex - 1);
734                                 logger.info("currently : {} Next: {}", currentIndex + 1, currentIndex);
735                                 logger.info("prevSong: {}", prevSong);
736                                 Map<String, String> fetchMap = new HashMap<>();
737                                 for(Map<String, String> tmpMap : listToolMapData) {
738                                         String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
739                                         String normalizeLocalName = Normalizer.normalize(prevSong.getName(), Normalizer.Form.NFKD);
740                                         if(normalizeApiName.equals(normalizeLocalName)) {
741                                                 fetchMap = tmpMap;
742                                                 break;
743                                         }
744                                 }
745                                 labelSongNameToolTip.setText(prevSong.getName());
746                                 labelAttributeToolTip.setText(prevSong.getAttribute());
747                                 labelDifficultyToolTip.setText(prevSong.getDifficulty());
748                                 labelLevelToolTip.setText(String.valueOf(prevSong.getLevel()));
749                                 labelNotesToolTip.setText(String.valueOf(prevSong.getNotes()));
750                                 labelCurrentSongOrderTool.setText(String.valueOf(currentIndex));
751                                 labelLyricToolTip.setText(fetchMap.get("lyric"));
752                                 labelComposerToolTip.setText(fetchMap.get("composer"));
753                                 labelArrangeToolTip.setText(fetchMap.get("arrange"));
754                                 labelMemberToolTip.setText(fetchMap.get("member"));
755                         }
756                 }, es).whenCompleteAsync((ret, ex) -> {
757                         if(ex != null) {
758                                 logger.error("Exception was thrown during concurrent process", ex);
759                         }
760                 }, es);
761         });
762         
763         labelLyricToolTitle = new JLabel("Lyrics By");
764         labelLyricToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
765         panelCenterTool.add(labelLyricToolTitle, "2, 26, center, default");
766         
767         labelLyricToolTip = new JLabel("Please wait...");
768         labelLyricToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
769         panelCenterTool.add(labelLyricToolTip, "10, 26, center, default");
770         
771         labelComposerToolTitle = new JLabel("Composed By");
772         labelComposerToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
773         panelCenterTool.add(labelComposerToolTitle, "2, 30, center, default");
774         
775         labelComposerToolTip = new JLabel("Please wait...");
776         labelComposerToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
777         panelCenterTool.add(labelComposerToolTip, "10, 30, center, default");
778         
779         labelArrangeToolTitle = new JLabel("Arranged By");
780         labelArrangeToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
781         panelCenterTool.add(labelArrangeToolTitle, "2, 34, center, default");
782         
783         labelArrangeToolTip = new JLabel("Please wait...");
784         labelArrangeToolTip.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
785         panelCenterTool.add(labelArrangeToolTip, "10, 34, center, default");
786         btnPrevSongTool.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
787         panelCenterTool.add(btnPrevSongTool, "2, 36");
788         
789         btnNextSongTool = new JButton("next");
790         btnNextSongTool.addActionListener(e -> {
791                 CompletableFuture.runAsync(() -> {
792                         int currentIndex = Integer.parseInt(labelCurrentSongOrderTool.getText()) - 1;
793                         if(currentIndex != property.getSongLimit() - 1) {
794                                 Song nextSong = toolIntegrateList.get(currentIndex + 1);
795                                 logger.info("currently : {} Next: {}", currentIndex + 1, currentIndex + 2);
796                                 logger.info("nextSong: {}", nextSong);
797                                 Map<String, String> fetchMap = new HashMap<>();
798                                 for(Map<String, String> tmpMap : listToolMapData) {
799                                         String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
800                                         String normalizeLocalName = Normalizer.normalize(nextSong.getName(), Normalizer.Form.NFKD);
801                                         if(normalizeApiName.equals(normalizeLocalName)) {
802                                                 fetchMap = tmpMap;
803                                                 break;
804                                         }
805                                 }
806                                 labelSongNameToolTip.setText(nextSong.getName());
807                                 labelAttributeToolTip.setText(nextSong.getAttribute());
808                                 labelDifficultyToolTip.setText(nextSong.getDifficulty());
809                                 labelLevelToolTip.setText(String.valueOf(nextSong.getLevel()));
810                                 labelNotesToolTip.setText(String.valueOf(nextSong.getNotes()));
811                                 labelCurrentSongOrderTool.setText(String.valueOf(currentIndex + 2));
812                                 labelLyricToolTip.setText(fetchMap.get("lyric"));
813                                 labelComposerToolTip.setText(fetchMap.get("composer"));
814                                 labelArrangeToolTip.setText(fetchMap.get("arrange"));
815                                 labelMemberToolTip.setText(fetchMap.get("member"));
816                         }
817                 }, es).whenCompleteAsync((ret, ex) -> {
818                         if(ex != null) {
819                                 logger.error("Exception was thrown during concurrent process", ex);
820                         }
821                 });
822         });
823         
824         labelCurrentSongOrderTool = new JLabel("null");
825         panelCenterTool.add(labelCurrentSongOrderTool, "4, 36");
826         
827         labelSlashTool = new JLabel("/");
828         panelCenterTool.add(labelSlashTool, "6, 36");
829         
830         labelSongLimitTool = new JLabel(String.valueOf(this.property.getSongLimit()));
831         panelCenterTool.add(labelSongLimitTool, "8, 36");
832         btnNextSongTool.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
833         panelCenterTool.add(btnNextSongTool, "10, 36");
834         
835         btnMoreInfoTool = new JButton("More Information");
836         btnMoreInfoTool.addActionListener(e -> {
837                 CompletableFuture.runAsync(() -> {
838                         int currentIndex = Integer.parseInt(labelCurrentSongOrderTool.getText()) - 1;
839                         Song currentSong = toolIntegrateList.get(currentIndex);
840                         Map<String, String> fetchMap = new HashMap<>();
841                         for(Map<String, String> tmpMap : listToolMapData) {
842                                 String normalizeApiName = Normalizer.normalize(tmpMap.get("songname").toString(), Normalizer.Form.NFKD);
843                                 String normalizeLocalName = Normalizer.normalize(currentSong.getName(), Normalizer.Form.NFKD);
844                                 if(normalizeApiName.equals(normalizeLocalName)) {
845                                         fetchMap = tmpMap;
846                                         break;
847                                 }
848                         }
849                         Desktop desk = Desktop.getDesktop();
850                         String api = fetchMap.get("link");
851                         URI uri;
852                         try {
853                                 uri = new URI(api);
854                                 logger.info("Opening default browser with : {}", uri);
855                                 desk.browse(uri);
856                         } catch (URISyntaxException | IOException e1) {
857                                 JOptionPane.showMessageDialog(null, "このメッセージは仮です。Exception : " + e1.getClass().getSimpleName());
858                                 logger.error("Exception while opening default browser.", e1);
859                         }
860                 }, es).whenCompleteAsync((ret, ex) -> {
861                         if(ex != null) {
862                                 logger.warn("Exception was thrown during action events.", ex);
863                         }
864                 }, es);
865         });
866         btnMoreInfoTool.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 12));
867         panelCenterTool.add(btnMoreInfoTool, "18, 36");
868         if(isFirst || !this.property.isCheckLibraryUpdates()) {
869             setEnabled.run();
870         }
871     }
872 }