/*
*
*/
package smartcontroller;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import org.controlsfx.control.PopOver;
import org.controlsfx.control.PopOver.ArrowLocation;
import org.controlsfx.control.textfield.TextFields;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.controls.JFXToggleButton;
import application.Main;
import application.librarymode.Library;
import application.tools.InfoTool;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Bounds;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import smartcontroller.media.Audio;
import smartcontroller.media.Media;
/**
* WARNING! I WAS DRUNK WHEN WRITING THIS CLASS ;) , REALLY! FUCKED UP
* XOAXOAOXOAO
*
* This class is used as a search Box for SmartController.
*
* @author GOXR3PLUS
*/
public class SmartControllerSearcher extends HBox {
/** The search field. */
TextField searchField = TextFields.createClearableTextField();
/** The controller. */
// Variables
SmartController controller;
/** The service. */
SearchService service = new SearchService();
boolean saveSettingBeforeSearch = true;
/**
* Constructor.
*
* @param control
* the control
*/
public SmartControllerSearcher(SmartController control) {
controller = control;
//Super
setAlignment(Pos.CENTER);
getChildren().add(searchField);
getStyleClass().add("search-box");
// searchField
searchField.setMinWidth(100);
searchField.setPrefWidth(400);
searchField.setMaxWidth(Integer.MAX_VALUE);
searchField.setPromptText("Search.....");
searchField.textProperty().addListener((observable , newValue , oldValue) -> {
//Check if the controller is free
if (!controller.isFree(false))
return;
if (searchField.getText().isEmpty()) {
saveSettingBeforeSearch = true;
//Reset the page number to the default before search
if (service.getPaneNumberBeforeSearch() <= controller.maximumList())
controller.getCurrentPage().set(service.getPaneNumberBeforeSearch());
//continue
controller.getNavigationHBox().setDisable(false);
controller.loadService.startService(false, false);
} else if (Main.settingsWindow.getPlayListsSettingsController().getInstantSearch().isSelected()) {
saveSettingsBeforeSearch();
service.search();
}
});
searchField.setOnKeyReleased(key -> {
if (key.getCode() == KeyCode.ESCAPE)
searchField.clear();
});
searchField.editableProperty().bind(service.runningProperty().not());
//searchField.disableProperty().bind(Main.advancedSearch.showingProperty())
searchField.setOnAction(ac -> {
if (controller.isFree(false)) {
saveSettingsBeforeSearch();
service.search();
}
});
//Override the default context menu
searchField.setContextMenu(new ContextMenu());
}
/**
* //Save the Settings before the first search -> [ ScrollBar position and
* current page of the SmartController ]
*/
private void saveSettingsBeforeSearch() {
//lock it so no override happens during the search
if (!saveSettingBeforeSearch)
return;
service.pageBeforeSearch = controller.getCurrentPage().get();
controller.getVerticalScrollBar().ifPresent(scrollBar -> controller.setVerticalScrollValueWithoutSearch(scrollBar.getValue()));
saveSettingBeforeSearch = false;
}
/**
* Returns true if the Search service is currently activated(if reset button
* is still visible).
*
* @return <b> True </b> if searchField is empty
*/
public boolean isActive() {
return !searchField.getText().isEmpty();
}
/**
* The Class SearchService.
*/
class SearchService extends Service<Void> {
/** The word. */
private String word;
/** The counter. */
int counter = 0;
/** The page before search. */
int pageBeforeSearch = 0;
/**
* Constructor.
*/
public SearchService() {
setOnSucceeded(s -> done());
setOnFailed(f -> {
controller.getNavigationHBox().setDisable(false);
done();
});
}
/**
* You can start the search Service by calling this method.
*/
public void search() {
// advanced search?
// if (Main.advancedSearch.isShowing())
// word = Main.advancedSearch.getTextForSearching();
// else
word = searchField.getText();
controller.getRegion().visibleProperty().bind(runningProperty());
controller.getIndicator().progressProperty().bind(progressProperty());
controller.getCancelButton().setText("Searching...");
controller.getInformationTextArea().setText("\n Searching ....");
controller.getNavigationHBox().setDisable(true);
//Clear the list
controller.getItemsObservableList().clear();
reset();
start();
}
/**
* When the Service is done.
*/
private void done() {
controller.updateList();
controller.unbind();
}
/**
* Returns the page that the SmartController was before the Search.
*
* @return the pane number before search
*/
private int getPaneNumberBeforeSearch() {
return pageBeforeSearch;
}
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
/**
* [[SuppressWarningsSpartan]]
*/
@Override
protected Void call() throws Exception {
// Counter
counter = 0;
// if (word.isEmpty())
// word = "";
// Given Work
System.out.println("Searching for word:[" + word + "]");
String query = "";
//--------------SEARCH WINDOW SPECIAL SEARCH----------------------------
if (controller.getGenre() == Genre.SEARCHWINDOW) {
//Let's create the UNION
ArrayList<String> queryArray = new ArrayList<>();
ObservableList<Library> observableList = Main.libraryMode.teamViewer.getViewer().getItemsObservableList();
controller.setTotalInDataBase(observableList.stream().mapToInt(Library::getTotalEntries).sum());
//Check if any PlayLists exist
if (observableList.isEmpty()) {
return null;
}
queryArray.add("SELECT * FROM (");
//For Each
Main.libraryMode.teamViewer.getViewer().getItemsObservableList().forEach(lib -> {
if (lib.getPosition() != observableList.size() - 1)
queryArray.add(" SELECT * FROM '" + lib.getDataBaseTableName() + "' UNION ALL ");
else
queryArray.add(" SELECT * FROM '" + lib.getDataBaseTableName() + "' ");
});
//Choose the correct query based on the settings of the user
if (Main.settingsWindow.getPlayListsSettingsController().getFileSearchGroup().getToggles().get(0).isSelected())
queryArray.add(" ) WHERE PATH LIKE '%" + word + "%' GROUP BY PATH LIMIT " + controller.getMaximumPerPage() + " ");
else
queryArray.add(" ) WHERE replace(path, rtrim(path, replace(path,'" + File.separator + "','')),'') LIKE '%" + word
+ "%' GROUP BY PATH LIMIT " + controller.getMaximumPerPage() + " ");
query = String.join("", queryArray);
//System.out.println(query)
}
//--------------NORMAL PLAYLISTS SEARCH----------------------------
else {
query = "SELECT * FROM '" + controller.getDataBaseTableName() + "' ";
//Choose the correct query based on the settings of the user
if (Main.settingsWindow.getPlayListsSettingsController().getFileSearchGroup().getToggles().get(0).isSelected())
query = query + " WHERE PATH LIKE '%" + word + "%' LIMIT " + controller.getMaximumPerPage();
else
query = query + " WHERE replace(path, rtrim(path, replace(path, '" + File.separator + "', '')), '') LIKE '%" + word
+ "%' LIMIT " + controller.getMaximumPerPage();
}
//System.out.println(query);
//Continue
try (ResultSet resultSet = Main.dbManager.getConnection().createStatement().executeQuery(query)) {
//try (ResultSet resultSet = Main.dbManager.connection1.createStatement().executeQuery(query)) {
//Fetch the items from the database
Platform.runLater(() -> controller.getCancelButton().setText("Validating..."));
List<Media> array = new ArrayList<>();
for (Audio song = null; resultSet.next();) {
//song = new Audio(resultSet.getString("PATH"), 5, 5, "f", "s", controller.genre);
song = new Audio(resultSet.getString("PATH"), resultSet.getDouble("STARS"), resultSet.getInt("TIMESPLAYED"),
resultSet.getString("DATE"), resultSet.getString("HOUR"), controller.getGenre());
array.add(song);
// updateProgress(++counter, controller.getMaximumPerPage());
}
//Add the the items to the observable list
CountDownLatch countDown = new CountDownLatch(1);
Platform.runLater(() -> {
controller.getItemsObservableList().addAll(array);
countDown.countDown();
});
countDown.await();
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
}
return null;
}
};
}
}
/**
* This class contains more advanced search features.
*
* @author GOXR3PLUS
*/
public static class AdvancedSearch extends BorderPane {
/** The search field. */
@FXML
private JFXTextField searchField;
/** The search on fly. */
@FXML
private JFXToggleButton searchOnFly;
/** The case sensitive. */
@FXML
private JFXCheckBox caseSensitive;
/** The bottom V box. */
@FXML
private VBox bottomVBox;
/** The pop over. */
private PopOver popOver = new PopOver();
/** The controller. */
SmartController controller;
/**
* Constructor.
*/
public AdvancedSearch() {
// Load the f x m l file
FXMLLoader loader = new FXMLLoader(getClass().getResource(InfoTool.FXMLS + "SearchSettings.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
/**
* Called as soon as .fxml has been initialized
*/
@FXML
private void initialize() {
// TagsBar
// TagsBar tagsBar = new TagsBar();
// tagsBar.setMaxWidth(InfoTool.getScreenWidth() / 2.5);
// tagsBar.getEntries().addAll(RadioStationsController.musicGenres);
// bottomVBox.getChildren().add(tagsBar);
// PopOver
popOver.setContentNode(this);
popOver.getScene().getStylesheets().add(getClass().getResource(InfoTool.STYLES + InfoTool.APPLICATIONCSS).toExternalForm());
popOver.setDetachable(false);
popOver.setAutoHide(true);
popOver.setArrowLocation(ArrowLocation.TOP_CENTER);
popOver.setOnHidden(h -> controller.searchService.searchField.textProperty().unbind());
// this
setOnMouseEntered(m -> requestFocus());
searchField.setContextMenu(new ContextMenu());
}
/**
* Search on fly selected.
*
* @return true, if successful
*/
public boolean searchOnFlySelected() {
return searchOnFly.isSelected();
}
/**
* Shows the Advanced Search with the given parameters.
*
* @param node
* the node
* @param controller
* the controller
*/
public void show(Node node , SmartController controller) {
searchField.editableProperty().bind(controller.searchService.service.runningProperty().not());
this.controller = controller;
searchField.setText(this.controller.searchService.searchField.getText());
this.controller.searchService.searchField.textProperty().bind(searchField.textProperty());
// Find the correct arrow location
double width = popOver.getWidth();
double height = popOver.getHeight();
Bounds bounds = controller.searchService.searchField.localToScreen(controller.searchService.searchField.getBoundsInLocal());
boolean fitOnTop = bounds.getMinY() - height > 0; // top?
boolean fitOnLeft = bounds.getMinX() - width > 0; // left?
boolean fitOnRight = bounds.getMaxX() + width < InfoTool.getScreenWidth();// right?
boolean fitOnBottom = bounds.getMaxY() + height < InfoTool.getScreenHeight(); // bottom?
if (fitOnTop)
popOver.setArrowLocation(ArrowLocation.BOTTOM_CENTER);
else if (fitOnBottom)
popOver.setArrowLocation(ArrowLocation.TOP_CENTER);
else if (fitOnLeft)
popOver.setArrowLocation(ArrowLocation.RIGHT_CENTER);
else if (fitOnRight)
popOver.setArrowLocation(ArrowLocation.LEFT_CENTER);
popOver.show(node);
searchField.requestFocus();
}
/**
* Checks if is showing.
*
* @return true, if is showing
*/
public boolean isShowing() {
return popOver.isShowing();
}
/**
* Showing property.
*
* @return the read only boolean property
*/
public ReadOnlyBooleanProperty showingProperty() {
return popOver.showingProperty();
}
/**
* Gets the text for searching.
*
* @return the text for searching
*/
public String getTextForSearching() {
return searchField.getText();
}
/**
* Hide.
*/
public void hide() {
popOver.hide();
}
}
}