/*
*
*/
package smartcontroller.media;
import java.io.File;
import java.nio.file.Paths;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import application.Main;
import application.librarymode.Library;
import application.tools.ActionTool;
import application.tools.InfoTool;
import application.tools.NotificationType;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Dragboard;
import javafx.util.Duration;
import smartcontroller.Genre;
import smartcontroller.SmartController;
import xplayer.model.AudioType;
/**
* This class is used as super class for Audio and Video classes.
*
* @author GOXR3PLUS
*/
public abstract class Media {
/** The title. */
protected SimpleStringProperty title;
/** The media type. */
private SimpleObjectProperty<ImageView> mediaType;
/** The has been played. */
private SimpleObjectProperty<ImageView> hasBeenPlayed;
/** The duration edited. */
private SimpleStringProperty durationEdited;
/** The duration. */
private SimpleIntegerProperty duration;
/** The times played. */
private SimpleIntegerProperty timesPlayed;
/** The stars. */
private SimpleDoubleProperty stars;
/** The hour imported. */
private SimpleStringProperty hourImported;
/** The date imported. */
private SimpleStringProperty dateImported;
/** The date that the File was created. */
private SimpleStringProperty dateFileCreated;
/** The date that the File was last modified. */
private SimpleStringProperty dateFileModified;
/** The drive. */
private SimpleStringProperty drive;
/** The file path. */
private SimpleStringProperty filePath;
/** The file name. */
private SimpleStringProperty fileName;
/** The file type. */
private SimpleStringProperty fileType;
/** The file type. */
private SimpleStringProperty fileSize;
/** Does the File exists */
private SimpleBooleanProperty fileExists;
// ---------END OF
// PROPERTIES----------------------------------------------------------------------------------
/** The image to be displayed if the Media is Song + NO ERRORS */
public static final Image songImage = InfoTool.getImageFromResourcesFolder("song.png");
/** The image to be displayed if the Media is Song + MISSING */
public static final Image songMissingImage = InfoTool.getImageFromResourcesFolder("songMissing.png");
/** The image to be displayed if the Media is Song + CORRUPTED */
public static final Image songCorruptedImage = InfoTool.getImageFromResourcesFolder("songCorrupted.png");
/** The video image. */
public static final Image videoImage = InfoTool.getImageFromResourcesFolder("video.png");
/** The genre. */
protected Genre genre;
/**
* Constructor.
*
* @param path
* The path of the File
* @param stars
* The quality of the Media
* @param timesPlayed
* The times the Media has been played
* @param dateImported
* The date the Media was imported <b> if null given then the
* imported time will be the current date </b>
* @param hourImported
* The hour the Media was imported <b> if null given then the
* imported hour will be the current time </b>
* @param genre
* The genre of the Media <b> see the Genre class for more </b>
*/
public Media(String path, double stars, int timesPlayed, String dateImported, String hourImported, Genre genre) {
// ....initialize
mediaType = new SimpleObjectProperty<>(new ImageView(InfoTool.isAudioSupported(path) ? songImage : videoImage));
hasBeenPlayed = new SimpleObjectProperty<>(new ImageView());
this.title = new SimpleStringProperty(InfoTool.getFileTitle(path));
this.drive = new SimpleStringProperty(Paths.get(path).getRoot() + "");
this.filePath = new SimpleStringProperty(path);
this.fileName = new SimpleStringProperty(InfoTool.getFileName(path));
this.fileType = new SimpleStringProperty(InfoTool.getFileExtension(path));
this.fileSize = new SimpleStringProperty();
this.stars = new SimpleDoubleProperty(stars);
this.timesPlayed = new SimpleIntegerProperty(timesPlayed);
this.duration = new SimpleIntegerProperty();
//this.duration.addListener((observable, oldValue, newValue) -> fixTheInformations(true))
this.durationEdited = new SimpleStringProperty("");
// Hour Created|Imported
this.hourImported = new SimpleStringProperty(hourImported != null ? hourImported : InfoTool.getLocalTime());
// Date Created|Imported
this.dateImported = new SimpleStringProperty(dateImported != null ? dateImported : InfoTool.getCurrentDate());
//Date File Created + Date File Modified
dateFileCreated = new SimpleStringProperty();
dateFileModified = new SimpleStringProperty();
// File exists
fileExists = new SimpleBooleanProperty(this, "FileExists", true);
fileExists.addListener((observable , oldValue , newValue) -> fixTheInformations(true));
// Media Genre
this.genre = genre;
// Find the correct image
fixTheInformations(true);
}
//!!!!!!!!!!!!!!!!!!THIS METHOD NEEDS FIXING!!!!!!!!!!!!!!!!!
/**
* When a files appears or dissapears it's information like size , image etc
* must be fixed to represent it's current status
*/
private void fixTheInformations(boolean doUpdate) {
if (!doUpdate)
return;
//System.out.println("Doing Update ->" + this.fileName.get())
//I need to add code for video files etc
//Check the fileSize
this.fileSize.set(InfoTool.getFileSizeEdited(new File(filePath.get())));
//dateFileCreated
dateFileCreated.set(InfoTool.getFileCreationDate(filePath.get()));
//dateFileModified
dateFileModified.set(InfoTool.getFileLastModifiedDate(filePath.get()));
//It is Audio?
if (!InfoTool.isAudioSupported(filePath.get()))
return;
//Duration
duration.set(InfoTool.durationInSeconds(filePath.get(), AudioType.FILE));
//DurationEdited
int localDuration = this.duration.get();
durationEdited.set(!fileExists.get() ? "file missing"
: localDuration == -1 ? "corrupted" : localDuration == 0 ? "error" : InfoTool.getTimeEditedOnHours(localDuration));
//Image
if (!fileExists.get()) //File is missing ?
mediaType.get().setImage(songMissingImage);
else if (this.duration.get() != -1) // Not corrupted
mediaType.get().setImage(songImage);
else if (this.duration.get() == -1) //Corrupted
mediaType.get().setImage(songCorruptedImage);
}
// --------Property
// Methods-----------------------------------------------------------------------------------
/**
* Media type property.
*
* @return the simple object property
*/
public SimpleObjectProperty<ImageView> mediaTypeProperty() {
return mediaType;
}
/**
* Checks for been played property.
*
* @return the simple object property
*/
public SimpleObjectProperty<ImageView> hasBeenPlayedProperty() {
return hasBeenPlayed;
}
/**
* Title property.
*
* @return the simple string property
*/
public SimpleStringProperty titleProperty() {
return title;
}
/**
* Duration edited property.
*
* @return the simple string property
*/
public SimpleStringProperty durationEditedProperty() {
return durationEdited;
}
/**
* Duration property.
*
* @return the simple integer property
*/
public SimpleIntegerProperty durationProperty() {
return duration;
}
/**
* Times played property.
*
* @return the simple integer property
*/
public SimpleIntegerProperty timesPlayedProperty() {
return timesPlayed;
}
/**
* Stars property.
*
* @return the simple double property
*/
public SimpleDoubleProperty starsProperty() {
return stars;
}
/**
* Hour imported property.
*
* @return the simple string property
*/
public SimpleStringProperty hourImportedProperty() {
return hourImported;
}
/**
* Date imported property.
*
* @return the simple string property
*/
public SimpleStringProperty dateImportedProperty() {
return dateImported;
}
/**
* Date File Created property.
*
* @return Date File Created property.
*/
public SimpleStringProperty dateFileCreatedProperty() {
return dateFileCreated;
}
/**
* Date File last modified property.
*
* @return The Date File last modified property.
*/
public SimpleStringProperty dateFileModified() {
return dateFileModified;
}
/**
* Drive property.
*
* @return the simple string property
*/
public SimpleStringProperty driveProperty() {
return drive;
}
/**
* File path property.
*
* @return the simple string property
*/
public SimpleStringProperty filePathProperty() {
return filePath;
}
/**
* File name property.
*
* @return the simple string property
*/
public SimpleStringProperty fileNameProperty() {
return fileName;
}
/**
* File Size property.
*
* @return the simple string property
*/
public SimpleStringProperty fileSizeProperty() {
return fileSize;
}
/**
* File type property.
*
* @return the simple string property
*/
public SimpleStringProperty fileTypeProperty() {
return fileType;
}
/**
* File type property.
*
* @return the simple string property
*/
public SimpleBooleanProperty fileExistsProperty() {
return fileExists;
}
// --------ORDINARY
// METHODS----------------------------------------------------------------------
/**
* Delete the Media from (play list)/library or (+storage medium).
*
* @param permanent
* <br>
* true->storage medium + (play list)/library<br>
* false->only from (play list)/library
* @param doQuestion
* <br>
* true->asks for permission</b> <br>
* false->not asking for permission<br>
* @param commit
* <br>
* true-> will do commit<br>
* false->will not do commit
* @param c
* the controller
* @param deleteStatement
* The prepared Statement which will delete the items from the SQL
* DataBase
*/
public void delete(boolean permanent , boolean doQuestion , boolean commit , SmartController c , PreparedStatement deleteStatement) {
if (c.isFree(true)) {
boolean hasBeenDeleted = false;
// Do question?
if (!doQuestion)
hasBeenDeleted = removeItem(permanent, c);
else if (ActionTool.doDeleteQuestion(permanent, fileName.get(), 1,Main.window))
hasBeenDeleted = removeItem(permanent, c);
if (hasBeenDeleted && deleteStatement != null) {
// Delete from database
try {
deleteStatement.setString(1, getFilePath());
deleteStatement.executeUpdate();
// Commit?
if (commit)
Main.dbManager.commit();
} catch (SQLException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
}
}
}
/**
* Removes this specific Media.
*
* @param permanent
* <br>
* true->storage medium + (play list)/library<br>
* false->only from (play list)/library
* @param controller
* the controller
* @return true, if successful
*/
private boolean removeItem(boolean permanent , SmartController controller) {
// Delete from storage medium?
if (permanent && !ActionTool.deleteFile(new File(getFilePath())))
return false;
// --totalInDataBase
controller.setTotalInDataBase(controller.getTotalInDataBase() - 1);
return true;
}
/**
* Rename the Media File.
*
* @param controller
* the controller
* @param node
* The node based on which the Rename Window will be position
* [[SuppressWarningsSpartan]]
*/
public void rename(SmartController controller , Node node) {
// If !Controller is Locked
if (controller.isFree(true)) {
// Security Variable
controller.renameWorking = true;
// Open Window
String extension = "." + InfoTool.getFileExtension(getFilePath());
Main.renameWindow.show(getTitle(), node, "Media Renaming");
// Bind
title.bind(Main.renameWindow.inputField.textProperty());
fileName.bind(Main.renameWindow.inputField.textProperty().concat(extension));
// When the Rename Window is closed do the rename
Main.renameWindow.showingProperty().addListener(new InvalidationListener() {
/**
* [[SuppressWarningsSpartan]]
*/
@Override
public void invalidated(Observable observable) {
// Remove the Listener
Main.renameWindow.showingProperty().removeListener(this);
// !Showing
if (!Main.renameWindow.isShowing()) {
// Remove Binding
title.unbind();
fileName.unbind();
String newName = new File(getFilePath()).getParent() + File.separator + fileName.get();
// !XPressed && // Old name != New name
if (Main.renameWindow.wasAccepted() && !getFilePath().equals(newName)) {
// try (PreparedStatement elementsMatchingThisWord = Main.dbManager.connection1
// .prepareStatement("SELECT COUNT(*) FROM '" + controller.getDataBaseTableName() + "' WHERE PATH=?");) {
//
// // No duplicates allowed
// boolean canPass = true;
//
// elementsMatchingThisWord.setString(1, newName);
// ResultSet set = elementsMatchingThisWord.executeQuery(); //needs to be fixed
// int total = set.getInt(1);
// if (total > 0)
// canPass = false;
// set.close();
// // System.out.println("Total is->:" + total)
//
// } catch (SQLException ex) {
// Main.logger.log(Level.WARNING, "", ex);
// setFilePath(filePath.get());
// ActionTool.showNotification("Error Message", "Failed to rename the File:/n" + ex.getMessage(), Duration.millis(1500),
// NotificationType.ERROR);
// }
try {
// if can pass
//if (canPass) {
// Check if that file already exists
if (new File(newName).exists()) {
setFilePath(filePath.get());
ActionTool.showNotification("Rename Failed",
"The action can not been completed:\nA file with that name already exists.", Duration.millis(1500),
NotificationType.WARNING);
controller.renameWorking = false;
return;
}
// Check if it can be renamed
if (!new File(getFilePath()).renameTo(new File(newName))) {
setFilePath(filePath.get());
ActionTool.showNotification("Rename Failed",
"The action can not been completed(Possible Reasons):\n1) The file is opened by a program,close it and try again.\n2)It doesn't exist anymore..",
Duration.millis(1500), NotificationType.WARNING);
controller.renameWorking = false;
return;
}
//Inform all Libraries SmartControllers
Main.libraryMode.teamViewer.getViewer().getItemsObservableList().stream().map(Library::getSmartController)
.forEach(controller1 -> {
//if (controller1 != controller) // we already renamed on this controller
try (PreparedStatement dataRename = Main.dbManager.getConnection().prepareStatement(
"UPDATE '" + controller1.getDataBaseTableName() + "' SET PATH=? WHERE PATH=?")) {
// Prepare Statement
dataRename.setString(1, newName);
dataRename.setString(2, getFilePath());
int i = dataRename.executeUpdate();
if (i > 0) //Check
controller1.loadService.startService(false, false, true);
} catch (SQLException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
});
//Inform all XPlayers SmartControllers
Main.xPlayersList.getList().stream()
.map(xPlayerController -> xPlayerController.getxPlayerPlayList().getSmartController())
.forEach(controller1 -> {
//if (controller1 != controller) // we already renamed on this controller
try (PreparedStatement dataRename = Main.dbManager.getConnection().prepareStatement(
"UPDATE '" + controller1.getDataBaseTableName() + "' SET PATH=? WHERE PATH=?")) {
// Prepare Statement
dataRename.setString(1, newName);
dataRename.setString(2, getFilePath());
int i = dataRename.executeUpdate();
if (i > 0) //Check
controller1.loadService.startService(false, false, true);
} catch (SQLException ex) {
Main.logger.log(Level.WARNING, "", ex);
}
});
Main.dbManager.commit();
// Rename it in playedSong if...
Main.playedSongs.renameMedia(getFilePath(), newName);
// change the file path
setFilePath(newName);
// } else { // canPass==false
// setFilePath(filePath.get());
// ActionTool.showNotification("Dublicate Name",
// "The action can not been completed because :\nA file with that name already exists.",
// Duration.millis(1500), NotificationType.INFORMATION);
// }
// Exception occurred
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
setFilePath(filePath.get());
ActionTool.showNotification("Error Message", "Failed to rename the File:/n" + ex.getMessage(), Duration.millis(1500),
NotificationType.ERROR);
}
} else // X is pressed by user || // Old name == New
// name
setFilePath(filePath.get());
// Security Variable
controller.renameWorking = false;
} // RenameWindow is still showing
}// invalidated
});
}
}
/**
* Evaluate the Media File using stars.
*
* @param controller
* the controller
* @param node
* The node based on which the Rename Window will be position
*/
public void updateStars(SmartController controller , Node node) {
// Show the Window
Main.starWindow.show(stars.get(), node);
// Keep in memory stars ...
final double previousStars = stars.get();
stars.bind(Main.starWindow.starsProperty());
// Listener
Main.starWindow.getWindow().showingProperty().addListener(new InvalidationListener() {
/**
* [[SuppressWarningsSpartan]]
*/
@Override
public void invalidated(Observable o) {
// Remove the listener
Main.starWindow.getWindow().showingProperty().removeListener(this);
// !showing?
if (!Main.starWindow.getWindow().isShowing()) {
// unbind stars property
stars.unbind();
// Accepted?
if (Main.starWindow.wasAccepted()) {
//Inform all Libraries SmartControllers
Main.libraryMode.teamViewer.getViewer().getItemsObservableList().stream().map(Library::getSmartController)
.forEach(controller1 -> {
//Do it bro!
try (PreparedStatement preparedUStars = Main.dbManager.getConnection()
.prepareStatement("UPDATE '" + controller1.getDataBaseTableName() + "' SET STARS=? WHERE PATH=?")) {
// Prepare Statement
preparedUStars.setDouble(1, getStars());
preparedUStars.setString(2, getFilePath());
int i = preparedUStars.executeUpdate();
if (i > 0) //Check
controller1.loadService.startService(false, false, true);
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
// ActionTool.showNotification("Error Message", "Failed to update the stars:/n" + ex.getMessage(),
// Duration.millis(1500), NotificationType.ERROR);
}
});
//Inform all XPlayers SmartControllers
Main.xPlayersList.getList().stream().map(xPlayerController -> xPlayerController.getxPlayerPlayList().getSmartController())
.forEach(controller1 -> {
//Do it bro!
try (PreparedStatement preparedUStars = Main.dbManager.getConnection()
.prepareStatement("UPDATE '" + controller1.getDataBaseTableName() + "' SET STARS=? WHERE PATH=?")) {
// Prepare Statement
preparedUStars.setDouble(1, getStars());
preparedUStars.setString(2, getFilePath());
int i = preparedUStars.executeUpdate();
if (i > 0) //Check
controller1.loadService.startService(false, false, true);
} catch (Exception ex) {
Main.logger.log(Level.WARNING, "", ex);
// ActionTool.showNotification("Error Message", "Failed to update the stars:/n" + ex.getMessage(),
// Duration.millis(1500), NotificationType.ERROR);
}
});
//Commit
Main.dbManager.commit();
} else
stars.set(previousStars);
}
}
});
}
// --------GETTERS------------------------------------------------------------------------------------
/**
* Gets the title.
*
* @return the title
*/
public String getTitle() {
return title.get();
}
/**
* Gets the drive.
*
* @return the drive
*/
public String getDrive() {
return drive.get();
}
/**
* Gets the file path.
*
* @return the file path
*/
public String getFilePath() {
return filePath.get();
}
/**
* Gets the file name.
*
* @return the file name
*/
public String getFileName() {
return fileName.get();
}
/**
* Gets the file type.
*
* @return the file type
*/
public String getFileType() {
return fileType.get();
}
/**
* Gets the file size.
*
* @return the file type
*/
public String getFileSize() {
return fileSize.get();
}
/**
* Gets the duration.
*
* @return the duration
*/
public int getDuration() {
return duration.get();
}
/**
* Gets the stars.
*
* @return the stars
*/
public double getStars() {
return stars.get();
}
/**
* Gets the times played.
*
* @return the times played
*/
public int getTimesPlayed() {
return timesPlayed.get();
}
/**
* Gets the hour imported.
*
* @return the hour imported
*/
public String getHourImported() {
return hourImported.get();
}
/**
* Gets the date imported.
*
* @return the date imported
*/
public String getDateImported() {
return dateImported.get();
}
/**
* Gets The date that the File was created
*
* @return The date that the File was created
*/
public String getDateFileCreated() {
return dateFileCreated.get();
}
/**
* Gets The date that the File was last modified
*
* @return The date that the File was last modified
*/
public String getDateFileModified() {
return dateFileModified.get();
}
/**
* Gets the genre.
*
* @return the genre
*/
public Genre getGenre() {
return genre;
}
// --------SETTERS------------------------------------------------------------------------------------
/**
* Sets the file path.
*
* @param path
* the new file path
*/
private void setFilePath(String path) {
this.title.set(InfoTool.getFileTitle(path));
this.drive.set(path.substring(0, 1));
this.filePath.set(path);
this.fileName.set(InfoTool.getFileName(path));
this.fileType.set(InfoTool.getFileExtension(path));
}
/**
* Sets the duration.
*
* @param duration
* the new duration
*/
public void setDuration(int duration) {
this.duration.set(duration);
}
/**
* Sets the times played.
*
* @param timesPlayed
* the times played
* @param controller
* the controller
*/
// protected void setTimesPlayed(int timesPlayed, SmartController controller) {
// this.timesPlayed.set(timesPlayed);
//
// // Update the dataBase
// try (PreparedStatement preparedUTimesPlayed = Main.dbManager.connection1.prepareStatement("UPDATE '" + controller.getDataBaseTableName() + "' SET TIMESPLAYED=? WHERE PATH=?")) {
//
// preparedUTimesPlayed.setInt(1, getTimesPlayed());
// preparedUTimesPlayed.setString(2, getFilePath());
// preparedUTimesPlayed.executeUpdate();
// Main.dbManager.commit();
//
// } catch (Exception ex) {
// Main.logger.log(Level.WARNING, "", ex);
// }
//
// }
/**
* Sets the media played.
*
* @param played
*/
public void setMediaPlayed(boolean played) {
hasBeenPlayed.get().setImage(!played ? null : InfoTool.playedImage);
}
// ------------------ABSTRACT METHODS
// ----------------------------------------------------------------------
/**
* This method is used during drag so the drag view has an image
* representing the album image of the media.
*
* @param db
* the new drag view
*/
public abstract void setDragView(Dragboard db);
/**
* Retrieves the Album Image of the Media.
*
* @return the album image
*/
public abstract Image getAlbumImage();
}