package org.rr.jeborker.gui.action;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.rr.commons.log.LoggerFactory;
import org.rr.commons.mufs.IResourceHandler;
import org.rr.commons.mufs.ResourceHandlerFactory;
import org.rr.commons.mufs.ResourceHandlerUtils;
import org.rr.commons.mufs.ResourceNameFilter;
import org.rr.jeborker.app.preferences.APreferenceStore;
import org.rr.jeborker.app.preferences.PreferenceStoreFactory;
import org.rr.jeborker.db.DefaultDBManager;
import org.rr.jeborker.db.item.EbookPropertyItem;
import org.rr.jeborker.db.item.EbookPropertyItemUtils;
import org.rr.jeborker.gui.MainController;
import org.rr.jeborker.gui.MainMonitor;
import org.rr.jeborker.gui.resources.ImageResourceBundle;
/**
* Add a folder action.
*/
class RefreshBasePathAction extends AbstractAction {
private static final long serialVersionUID = -9066575818229620987L;
private static final String REFRESH_ALL = "refreshAll";
private String path;
RefreshBasePathAction(String text) {
super();
putValue(Action.NAME, text);
if(REFRESH_ALL.equals(text)) {
path = text;
putValue(Action.NAME, Bundle.getString("RefreshBasePathAction.refreshAll.name"));
} else if(ResourceHandlerFactory.hasResourceHandler(text)) {
path = text;
}
putValue(Action.SMALL_ICON, ImageResourceBundle.getResourceAsImageIcon("refresh_16.png"));
putValue(Action.LARGE_ICON_KEY, ImageResourceBundle.getResourceAsImageIcon("refresh_22.png"));
}
@Override
public void actionPerformed(ActionEvent e) {
final APreferenceStore preferenceStore = PreferenceStoreFactory.getPreferenceStore(PreferenceStoreFactory.DB_STORE);
final MainController controller = MainController.getController();
controller.getProgressMonitor().monitorProgressStart(Bundle.getString("AddBasePathAction.message"));
String messageFinished = Bundle.getString("RefreshBasePathAction.finished");
try {
if(REFRESH_ALL.equals(path)) {
final List<String> basePaths = preferenceStore.getBasePath();
for (String basePath : basePaths) {
if(ResourceHandlerFactory.getResourceHandler(basePath).isDirectoryResource()) {
doRefreshBasePath(basePath, e, controller.getProgressMonitor());
}
}
} else if(path != null && path.length() > 0) {
if(!ResourceHandlerFactory.getResourceHandler(path).isDirectoryResource()) {
messageFinished = "The folder " + path + " did not exists.";
} else {
doRefreshBasePath(path, e, controller.getProgressMonitor());
}
}
} catch (Throwable ex) {
LoggerFactory.log(Level.WARNING, this, "Path " + path, ex);
} finally {
controller.getEbookTableHandler().refreshTable();
controller.getProgressMonitor().monitorProgressStop(messageFinished);
}
System.gc();
}
private void doRefreshBasePath(String path, ActionEvent e, MainMonitor monitor) {
IResourceHandler resourceLoader = ResourceHandlerFactory.getResourceHandler(path);
removeDeletedFiles(resourceLoader);
refreshEbookFiles(resourceLoader);
MainController.getController().getEbookTableHandler().refreshTable();
}
/**
* Removes all deleted files from the database.
* @param basePath The folder to be processed.
*/
private static void removeDeletedFiles(final IResourceHandler basePath) {
final DefaultDBManager db = DefaultDBManager.getInstance();
final ArrayList<EbookPropertyItem> itemsToTest = RemoveBasePathAction.getItemsByBasePath(basePath.toString());
for(EbookPropertyItem item : itemsToTest) {
final IResourceHandler itemResourceHandler = item.getResourceHandler();
if(!itemResourceHandler.exists()) {
db.deleteObject(item);
}
}
}
/**
* Read all ebook files recursive and stores them directly to the database.
* @param basePath The folder where the ebook search should be started.
*/
private void refreshEbookFiles(final IResourceHandler basePath) {
final DefaultDBManager db = DefaultDBManager.getInstance();
final HashSet<String> path = new HashSet<>();
final Collection<String> oldPathElements = EbookPropertyItemUtils.fetchPathElements();
ResourceHandlerUtils.readAllFilesFromBasePath(basePath, new ResourceNameFilter() {
@Override
public boolean accept(IResourceHandler resourceLoader) {
if(resourceLoader.isFileResource() && ActionUtils.isSupportedEbookFormat(resourceLoader, true)) {
try {
List<EbookPropertyItem> ebookPropertyItems = EbookPropertyItemUtils.getEbookPropertyItemByResource(resourceLoader);
if(!ebookPropertyItems.isEmpty()) {
for(EbookPropertyItem item : ebookPropertyItems) {
long fileTimeStamp = resourceLoader.getModifiedAt().getTime();
if(item.getTimestamp() == 0 || item.getTimestamp() != fileTimeStamp) {
//file has changed
EbookPropertyItemUtils.refreshEbookPropertyItem(item, resourceLoader, true);
db.updateObject(item);
}
}
} else {
//new ebook
final EbookPropertyItem item = EbookPropertyItemUtils.createEbookPropertyItem(resourceLoader, basePath);
db.storeObject(item);
}
path.add(resourceLoader.getParentResource().toString());
return true;
} catch(Throwable e) {
LoggerFactory.getLogger(this).log(Level.SEVERE, "Failed adding resource " + resourceLoader, e);
}
}
return false;
}
});
EbookPropertyItemUtils.storePathElements(path);
reloadBasePathTree(path, oldPathElements);
}
/**
* Reloads the base path tree if there are any new entries in <code>pathElements</code>
* @param pathElements Elements to test for new path elements.
* @param oldPathElements The old path list which is used to evaluate which entry is new.
*/
private void reloadBasePathTree(final Collection<String> pathElements, final Collection<String> oldPathElements) {
for(String newPathElement : pathElements) {
if(!oldPathElements.contains(newPathElement)) {
MainController.getController().getMainTreeHandler().refreshBasePathTree();
break;
}
}
}
}