/*
* 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.bookmodel;
import java.util.*;
import org.geometerplus.zlibrary.core.fonts.*;
import org.geometerplus.zlibrary.core.image.ZLImage;
import org.geometerplus.zlibrary.text.model.*;
import org.geometerplus.fbreader.book.Book;
import org.geometerplus.fbreader.book.BookUtil;
import org.geometerplus.fbreader.formats.*;
public final class BookModel {
public static BookModel createModel(Book book, FormatPlugin plugin) throws BookReadingException {
if (plugin instanceof BuiltinFormatPlugin) {
final BookModel model = new BookModel(book);
((BuiltinFormatPlugin)plugin).readModel(model);
return model;
}
throw new BookReadingException(
"unknownPluginType", null, new String[] { String.valueOf(plugin) }
);
}
public final Book Book;
public final TOCTree TOCTree = new TOCTree();
public final FontManager FontManager = new FontManager();
protected CachedCharStorage myInternalHyperlinks;
protected final HashMap<String,ZLImage> myImageMap = new HashMap<String,ZLImage>();
protected ZLTextModel myBookTextModel;
protected final HashMap<String,ZLTextModel> myFootnotes = new HashMap<String,ZLTextModel>();
public static final class Label {
public final String ModelId;
public final int ParagraphIndex;
public Label(String modelId, int paragraphIndex) {
ModelId = modelId;
ParagraphIndex = paragraphIndex;
}
}
protected BookModel(Book book) {
Book = book;
}
public interface LabelResolver {
List<String> getCandidates(String id);
}
private LabelResolver myResolver;
public void setLabelResolver(LabelResolver resolver) {
myResolver = resolver;
}
public Label getLabel(String id) {
Label label = getLabelInternal(id);
if (label == null && myResolver != null) {
for (String candidate : myResolver.getCandidates(id)) {
label = getLabelInternal(candidate);
if (label != null) {
break;
}
}
}
return label;
}
public void registerFontFamilyList(String[] families) {
FontManager.index(Arrays.asList(families));
}
public void registerFontEntry(String family, FontEntry entry) {
FontManager.Entries.put(family, entry);
}
public void registerFontEntry(String family, FileInfo normal, FileInfo bold, FileInfo italic, FileInfo boldItalic) {
registerFontEntry(family, new FontEntry(family, normal, bold, italic, boldItalic));
}
public ZLTextModel createTextModel(
String id, String language, int paragraphsNumber,
int[] entryIndices, int[] entryOffsets,
int[] paragraphLenghts, int[] textSizes, byte[] paragraphKinds,
String directoryName, String fileExtension, int blocksNumber
) {
return new ZLTextPlainModel(
id, language, paragraphsNumber,
entryIndices, entryOffsets,
paragraphLenghts, textSizes, paragraphKinds,
directoryName, fileExtension, blocksNumber, myImageMap, FontManager
);
}
public void setBookTextModel(ZLTextModel model) {
myBookTextModel = model;
}
public void setFootnoteModel(ZLTextModel model) {
myFootnotes.put(model.getId(), model);
}
public ZLTextModel getTextModel() {
return myBookTextModel;
}
public ZLTextModel getFootnoteModel(String id) {
return myFootnotes.get(id);
}
public void addImage(String id, ZLImage image) {
myImageMap.put(id, image);
}
public void initInternalHyperlinks(String directoryName, String fileExtension, int blocksNumber) {
myInternalHyperlinks = new CachedCharStorage(directoryName, fileExtension, blocksNumber);
}
private TOCTree myCurrentTree = TOCTree;
public void addTOCItem(String text, int reference) {
myCurrentTree = new TOCTree(myCurrentTree);
myCurrentTree.setText(text);
myCurrentTree.setReference(myBookTextModel, reference);
}
public void leaveTOCItem() {
myCurrentTree = myCurrentTree.Parent;
if (myCurrentTree == null) {
myCurrentTree = TOCTree;
}
}
private Label getLabelInternal(String id) {
final int len = id.length();
final int size = myInternalHyperlinks.size();
for (int i = 0; i < size; ++i) {
final char[] block = myInternalHyperlinks.block(i);
for (int offset = 0; offset < block.length; ) {
final int labelLength = (int)block[offset++];
if (labelLength == 0) {
break;
}
final int idLength = (int)block[offset + labelLength];
if (labelLength != len || !id.equals(new String(block, offset, labelLength))) {
offset += labelLength + idLength + 3;
continue;
}
offset += labelLength + 1;
final String modelId = (idLength > 0) ? new String(block, offset, idLength) : null;
offset += idLength;
final int paragraphNumber = (int)block[offset] + (((int)block[offset + 1]) << 16);
return new Label(modelId, paragraphNumber);
}
}
return null;
}
}