/* * Copyright (C) 2009-2015 FBReader.ORG Limited <contact@fbreader.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ package org.geometerplus.fbreader.book; import java.util.*; import org.fbreader.util.Pair; import org.geometerplus.zlibrary.core.filesystem.*; public final class FileInfoSet { private final HashMap<ZLFile,FileInfo> myInfosByFile = new HashMap<ZLFile,FileInfo>(); private final HashMap<FileInfo,ZLFile> myFilesByInfo = new HashMap<FileInfo,ZLFile>(); private final HashMap<Pair<String,FileInfo>,FileInfo> myInfosByPair = new HashMap<Pair<String,FileInfo>,FileInfo>(); private final HashMap<Long,FileInfo> myInfosById = new HashMap<Long,FileInfo>(); private final LinkedHashSet<FileInfo> myInfosToSave = new LinkedHashSet<FileInfo>(); private final LinkedHashSet<FileInfo> myInfosToRemove = new LinkedHashSet<FileInfo>(); private final BooksDatabase myDatabase; public FileInfoSet(BooksDatabase database) { myDatabase = database; load(database.loadFileInfos()); } public FileInfoSet(BooksDatabase database, ZLFile file) { myDatabase = database; load(database.loadFileInfos(file)); } FileInfoSet(BooksDatabase database, long fileId) { myDatabase = database; load(database.loadFileInfos(fileId)); } private void load(Collection<FileInfo> infos) { for (FileInfo info : infos) { myInfosByPair.put(new Pair(info.Name, info.Parent), info); myInfosById.put(info.Id, info); } } public void save() { myDatabase.executeAsTransaction(new Runnable() { public void run() { for (FileInfo info : myInfosToRemove) { myDatabase.removeFileInfo(info.Id); myInfosByPair.remove(new Pair(info.Name, info.Parent)); } myInfosToRemove.clear(); for (FileInfo info : myInfosToSave) { myDatabase.saveFileInfo(info); } myInfosToSave.clear(); } }); } public boolean check(ZLPhysicalFile file, boolean processChildren) { if (file == null) { return true; } final long fileSize = file.size(); FileInfo info = get(file); if (info.FileSize == fileSize) { return true; } else { info.FileSize = fileSize; if (processChildren && !"epub".equals(file.getExtension())) { removeChildren(info); myInfosToSave.add(info); addChildren(file); } else { myInfosToSave.add(info); } return false; } } public List<ZLFile> archiveEntries(ZLFile file) { final FileInfo info = get(file); if (!info.hasChildren()) { return Collections.emptyList(); } final LinkedList<ZLFile> entries = new LinkedList<ZLFile>(); for (FileInfo child : info.subtrees()) { if (!myInfosToRemove.contains(child)) { entries.add(ZLArchiveEntryFile.createArchiveEntryFile(file, child.Name)); } } return entries; } private FileInfo get(String name, FileInfo parent) { final Pair pair = new Pair(name, parent); FileInfo info = myInfosByPair.get(pair); if (info == null) { info = new FileInfo(name, parent); myInfosByPair.put(pair, info); myInfosToSave.add(info); } return info; } private FileInfo get(ZLFile file) { if (file == null) { return null; } FileInfo info = myInfosByFile.get(file); if (info == null) { info = get(file.getLongName(), get(file.getParent())); myInfosByFile.put(file, info); } return info; } public long getId(ZLFile file) { final FileInfo info = get(file); if (info == null) { return -1; } if (info.Id == -1) { save(); } return info.Id; } private ZLFile getFile(FileInfo info) { if (info == null) { return null; } ZLFile file = myFilesByInfo.get(info); if (file == null) { file = ZLFile.createFile(getFile(info.Parent), info.Name); myFilesByInfo.put(info, file); } return file; } public ZLFile getFile(long id) { return getFile(myInfosById.get(id)); } private void removeChildren(FileInfo info) { for (FileInfo child : info.subtrees()) { if (myInfosToSave.contains(child)) { myInfosToSave.remove(child); } else { myInfosToRemove.add(child); } removeChildren(child); } } private void addChildren(ZLFile file) { for (ZLFile child : file.children()) { final FileInfo info = get(child); if (myInfosToRemove.contains(info)) { myInfosToRemove.remove(info); } else { myInfosToSave.add(info); } addChildren(child); } } }