/*
* Copyright (C) 2007-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.ComparisonUtil;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.util.MiscUtil;
import org.geometerplus.fbreader.formats.*;
public final class DbBook extends AbstractBook {
public final ZLFile File;
private Set<String> myVisitedHyperlinks;
DbBook(long id, ZLFile file, String title, String encoding, String language) {
super(id, title, encoding, language);
if (file == null) {
throw new IllegalArgumentException("Creating book with no file");
}
File = file;
}
DbBook(ZLFile file, FormatPlugin plugin) throws BookReadingException {
this(-1, plugin.realBookFile(file), null, null, null);
BookUtil.readMetainfo(this, plugin);
mySaveState = SaveState.NotSaved;
}
@Override
public String getPath() {
return File.getPath();
}
void loadLists(BooksDatabase database, PluginCollection pluginCollection) {
myAuthors = database.listAuthors(myId);
myTags = database.listTags(myId);
myLabels = database.listLabels(myId);
mySeriesInfo = database.getSeriesInfo(myId);
myUids = database.listUids(myId);
myProgress = database.getProgress(myId);
HasBookmark = database.hasVisibleBookmark(myId);
mySaveState = SaveState.Saved;
if (myUids == null || myUids.isEmpty()) {
try {
BookUtil.getPlugin(pluginCollection, this).readUids(this);
save(database, false);
} catch (BookReadingException e) {
}
}
}
enum WhatIsSaved {
Nothing,
Progress,
Everything;
}
WhatIsSaved save(BooksDatabase database, boolean force) {
if (force || myId == -1) {
mySaveState = SaveState.NotSaved;
}
switch (mySaveState) {
case Saved:
return WhatIsSaved.Nothing;
case ProgressNotSaved:
return saveProgress(database) ? WhatIsSaved.Progress : WhatIsSaved.Nothing;
default:
case NotSaved:
return saveFull(database) ? WhatIsSaved.Everything : WhatIsSaved.Nothing;
}
}
private boolean saveProgress(final BooksDatabase database) {
final boolean[] result = new boolean[] { false };
database.executeAsTransaction(new Runnable() {
public void run() {
if (myId != -1 && myProgress != null) {
database.saveBookProgress(myId, myProgress);
result[0] = true;
}
}
});
if (result[0]) {
mySaveState = SaveState.Saved;
return true;
} else {
return false;
}
}
private boolean saveFull(final BooksDatabase database) {
final boolean[] result = new boolean[] { true };
database.executeAsTransaction(new Runnable() {
public void run() {
if (myId >= 0) {
final FileInfoSet fileInfos = new FileInfoSet(database, File);
database.updateBookInfo(myId, fileInfos.getId(File), myEncoding, myLanguage, getTitle());
} else {
myId = database.insertBookInfo(File, myEncoding, myLanguage, getTitle());
if (myId == -1) {
result[0] = false;
return;
}
if (myVisitedHyperlinks != null) {
for (String linkId : myVisitedHyperlinks) {
database.addVisitedHyperlink(myId, linkId);
}
}
database.addBookHistoryEvent(myId, BooksDatabase.HistoryEvent.Added);
}
long index = 0;
database.deleteAllBookAuthors(myId);
for (Author author : authors()) {
database.saveBookAuthorInfo(myId, index++, author);
}
database.deleteAllBookTags(myId);
for (Tag tag : tags()) {
database.saveBookTagInfo(myId, tag);
}
final List<Label> labelsInDb = database.listLabels(myId);
for (Label label : labelsInDb) {
if (myLabels == null || !myLabels.contains(label)) {
database.removeLabel(myId, label);
}
}
if (myLabels != null) {
for (Label label : myLabels) {
database.addLabel(myId, label);
}
}
database.saveBookSeriesInfo(myId, mySeriesInfo);
database.deleteAllBookUids(myId);
for (UID uid : uids()) {
database.saveBookUid(myId, uid);
}
if (myProgress != null) {
database.saveBookProgress(myId, myProgress);
}
}
});
if (result[0]) {
mySaveState = SaveState.Saved;
return true;
} else {
return false;
}
}
private void initHyperlinkSet(BooksDatabase database) {
if (myVisitedHyperlinks == null) {
myVisitedHyperlinks = new TreeSet<String>();
if (myId != -1) {
myVisitedHyperlinks.addAll(database.loadVisitedHyperlinks(myId));
}
}
}
boolean isHyperlinkVisited(BooksDatabase database, String linkId) {
initHyperlinkSet(database);
return myVisitedHyperlinks.contains(linkId);
}
void markHyperlinkAsVisited(BooksDatabase database, String linkId) {
initHyperlinkSet(database);
if (!myVisitedHyperlinks.contains(linkId)) {
myVisitedHyperlinks.add(linkId);
if (myId != -1) {
database.addVisitedHyperlink(myId, linkId);
}
}
}
boolean hasSameMetainfoAs(DbBook other) {
return
ComparisonUtil.equal(getTitle(), other.getTitle()) &&
ComparisonUtil.equal(myEncoding, other.myEncoding) &&
ComparisonUtil.equal(myLanguage, other.myLanguage) &&
ComparisonUtil.equal(myAuthors, other.myAuthors) &&
MiscUtil.listsEquals(myTags, other.myTags) &&
ComparisonUtil.equal(mySeriesInfo, other.mySeriesInfo) &&
ComparisonUtil.equal(myUids, other.myUids);
}
void merge(DbBook other, DbBook base) {
if (!ComparisonUtil.equal(getTitle(), other.getTitle()) &&
ComparisonUtil.equal(getTitle(), base.getTitle())) {
setTitle(other.getTitle());
}
if (!ComparisonUtil.equal(myEncoding, other.myEncoding) &&
ComparisonUtil.equal(myEncoding, base.myEncoding)) {
setEncoding(other.myEncoding);
}
if (!ComparisonUtil.equal(myLanguage, other.myLanguage) &&
ComparisonUtil.equal(myLanguage, base.myLanguage)) {
setLanguage(other.myLanguage);
}
if (!MiscUtil.listsEquals(myTags, other.myTags) &&
MiscUtil.listsEquals(myTags, base.myTags)) {
myTags = other.myTags != null ? new ArrayList<Tag>(other.myTags) : null;
mySaveState = SaveState.NotSaved;
}
if (!ComparisonUtil.equal(mySeriesInfo, other.mySeriesInfo) &&
ComparisonUtil.equal(mySeriesInfo, base.mySeriesInfo)) {
mySeriesInfo = other.mySeriesInfo;
mySaveState = SaveState.NotSaved;
}
if (!MiscUtil.listsEquals(myUids, other.myUids) &&
MiscUtil.listsEquals(myUids, base.myUids)) {
myUids = other.myUids != null ? new ArrayList<UID>(other.myUids) : null;
mySaveState = SaveState.NotSaved;
}
}
@Override
public int hashCode() {
return File.getShortName().hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DbBook)) {
return false;
}
final DbBook obook = ((DbBook)o);
final ZLFile ofile = obook.File;
if (File.equals(ofile)) {
return true;
}
if (!File.getShortName().equals(ofile.getShortName())) {
return false;
}
if (myUids == null || obook.myUids == null) {
return false;
}
for (UID uid : obook.myUids) {
if (myUids.contains(uid)) {
return true;
}
}
return false;
}
}