/*
* Copyright (C) 2009-2013 Geometer Plus <contact@geometerplus.com>
*
* 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.Comparator;
import java.util.Date;
import org.geometerplus.zlibrary.text.view.ZLTextElement;
import org.geometerplus.zlibrary.text.view.ZLTextFixedPosition;
import org.geometerplus.zlibrary.text.view.ZLTextPosition;
import org.geometerplus.zlibrary.text.view.ZLTextView;
import org.geometerplus.zlibrary.text.view.ZLTextWord;
import org.geometerplus.zlibrary.text.view.ZLTextWordCursor;
public final class Bookmark extends ZLTextFixedPosition {
public enum DateType {
Creation,
Modification,
Access,
Latest
}
private long myId;
private final long myBookId;
private final String myBookTitle;
private String myText;
private final Date myCreationDate;
private Date myModificationDate;
private Date myAccessDate;
private int myAccessCount;
private Date myLatestDate;
private ZLTextFixedPosition myEnd;
private int myLength;
private int myStyleId;
public final String ModelId;
public final boolean IsVisible;
Bookmark(
long id, long bookId, String bookTitle, String text,
Date creationDate, Date modificationDate, Date accessDate, int accessCount,
String modelId,
int start_paragraphIndex, int start_elementIndex, int start_charIndex,
int end_paragraphIndex, int end_elementIndex, int end_charIndex,
boolean isVisible,
int styleId
) {
super(start_paragraphIndex, start_elementIndex, start_charIndex);
myId = id;
myBookId = bookId;
myBookTitle = bookTitle;
myText = text;
myCreationDate = creationDate;
myModificationDate = modificationDate;
myLatestDate = (modificationDate != null) ? modificationDate : creationDate;
if (accessDate != null) {
myAccessDate = accessDate;
if (myLatestDate.compareTo(accessDate) < 0) {
myLatestDate = accessDate;
}
}
myAccessCount = accessCount;
ModelId = modelId;
IsVisible = isVisible;
if (end_charIndex >= 0) {
myEnd = new ZLTextFixedPosition(end_paragraphIndex, end_elementIndex, end_charIndex);
} else {
myLength = end_paragraphIndex;
}
myStyleId = styleId;
}
private static class Buffer {
final StringBuilder Builder = new StringBuilder();
final ZLTextWordCursor Cursor;
Buffer(ZLTextWordCursor cursor) {
Cursor = new ZLTextWordCursor(cursor);
}
boolean isEmpty() {
return Builder.length() == 0;
}
void append(Buffer buffer) {
Builder.append(buffer.Builder);
Cursor.setCursor(buffer.Cursor);
buffer.Builder.delete(0, buffer.Builder.length());
}
void append(CharSequence data) {
Builder.append(data);
}
}
public static Bookmark createBookmark(Book book, String modelId, ZLTextWordCursor startCursor, int maxWords, boolean isVisible) {
final ZLTextWordCursor cursor = new ZLTextWordCursor(startCursor);
final Buffer buffer = new Buffer(cursor);
final Buffer sentenceBuffer = new Buffer(cursor);
final Buffer phraseBuffer = new Buffer(cursor);
int wordCounter = 0;
int sentenceCounter = 0;
int storedWordCounter = 0;
boolean lineIsNonEmpty = false;
boolean appendLineBreak = false;
mainLoop:
while (wordCounter < maxWords && sentenceCounter < 3) {
while (cursor.isEndOfParagraph()) {
if (!cursor.nextParagraph()) {
break mainLoop;
}
if (!buffer.isEmpty() && cursor.getParagraphCursor().isEndOfSection()) {
break mainLoop;
}
if (!phraseBuffer.isEmpty()) {
sentenceBuffer.append(phraseBuffer);
}
if (!sentenceBuffer.isEmpty()) {
if (appendLineBreak) {
buffer.append("\n");
}
buffer.append(sentenceBuffer);
++sentenceCounter;
storedWordCounter = wordCounter;
}
lineIsNonEmpty = false;
if (!buffer.isEmpty()) {
appendLineBreak = true;
}
}
final ZLTextElement element = cursor.getElement();
if (element instanceof ZLTextWord) {
final ZLTextWord word = (ZLTextWord)element;
if (lineIsNonEmpty) {
phraseBuffer.append(" ");
}
phraseBuffer.Builder.append(word.Data, word.Offset, word.Length);
phraseBuffer.Cursor.setCursor(cursor);
phraseBuffer.Cursor.setCharIndex(word.Length);
++wordCounter;
lineIsNonEmpty = true;
switch (word.Data[word.Offset + word.Length - 1]) {
case ',':
case ':':
case ';':
case ')':
sentenceBuffer.append(phraseBuffer);
break;
case '.':
case '!':
case '?':
++sentenceCounter;
if (appendLineBreak) {
buffer.append("\n");
appendLineBreak = false;
}
sentenceBuffer.append(phraseBuffer);
buffer.append(sentenceBuffer);
storedWordCounter = wordCounter;
break;
}
}
cursor.nextWord();
}
if (storedWordCounter < 4) {
if (sentenceBuffer.isEmpty()) {
sentenceBuffer.append(phraseBuffer);
}
if (appendLineBreak) {
buffer.append("\n");
}
buffer.append(sentenceBuffer);
}
return new Bookmark(book, modelId, startCursor, buffer.Cursor, buffer.Builder.toString(), isVisible);
}
public void findEnd(ZLTextView view) {
if (myEnd != null) {
return;
}
ZLTextWordCursor cursor = view.getStartCursor();
if (cursor.isNull()) {
cursor = view.getEndCursor();
}
if (cursor.isNull()) {
return;
}
cursor = new ZLTextWordCursor(cursor);
cursor.moveTo(this);
ZLTextWord word = null;
mainLoop:
for (int count = myLength; count > 0; cursor.nextWord()) {
while (cursor.isEndOfParagraph()) {
if (!cursor.nextParagraph()) {
break mainLoop;
}
}
final ZLTextElement element = cursor.getElement();
if (element instanceof ZLTextWord) {
if (word != null) {
--count;
}
word = (ZLTextWord)element;
System.err.println(new String(word.Data, word.Offset, word.Length));
count -= word.Length;
}
}
if (word != null) {
myEnd = new ZLTextFixedPosition(
cursor.getParagraphIndex(),
cursor.getElementIndex(),
word.Length
);
}
}
public Bookmark(Book book, String modelId, ZLTextPosition start, ZLTextPosition end, String text, boolean isVisible) {
super(start);
myId = -1;
myBookId = book.getId();
myBookTitle = book.getTitle();
myText = text;
myCreationDate = new Date();
ModelId = modelId;
IsVisible = isVisible;
myEnd = new ZLTextFixedPosition(end);
myStyleId = 1;
}
public long getId() {
return myId;
}
public long getBookId() {
return myBookId;
}
public int getStyleId() {
return myStyleId;
}
public void setStyleId(int styleId) {
myStyleId = styleId;
}
public String getText() {
return myText;
}
public String getBookTitle() {
return myBookTitle;
}
public Date getDate(DateType type) {
switch (type) {
case Creation:
return myCreationDate;
case Modification:
return myModificationDate;
case Access:
return myAccessDate;
default:
case Latest:
return myLatestDate;
}
}
public int getAccessCount() {
return myAccessCount;
}
public ZLTextPosition getEnd() {
return myEnd;
}
public int getLength() {
return myLength;
}
public void setText(String text) {
if (!text.equals(myText)) {
myText = text;
myModificationDate = new Date();
myLatestDate = myModificationDate;
}
}
public void markAsAccessed() {
myAccessDate = new Date();
++myAccessCount;
myLatestDate = myAccessDate;
}
public static class ByTimeComparator implements Comparator<Bookmark> {
public int compare(Bookmark bm0, Bookmark bm1) {
final Date date0 = bm0.getDate(DateType.Latest);
final Date date1 = bm1.getDate(DateType.Latest);
if (date0 == null) {
return date1 == null ? 0 : -1;
}
return date1 == null ? 1 : date1.compareTo(date0);
}
}
void setId(long id) {
myId = id;
}
public void update(Bookmark other) {
// TODO: copy other fields (?)
if (other != null) {
myId = other.myId;
}
}
}