/*
* Priki - Prevalent Wiki
* Copyright (c) 2005 Priki
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*
* @author Vitor Fernando Pamplona - vitor@babaxp.org
*
*/
package org.priki.bo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.priki.utils.SortedBag;
public class Wikiword extends Element implements Serializable, Comparable<Wikiword> {
public static final long serialVersionUID= 1L;
public static final boolean DEFAULT_CASE_SENSITIVE_VALUE = true;
public static final Visibility DEFAULT_VISIBILITY = Visibility.Public;
public static enum Visibility { Public, User, Reader, Editor, Admin };
/* History of the description about this element*/
private HistoryText definition;
/* Hold an list of text that are using this element.
* SortedBag is a Set with a counter of inclusion for each word.
* We use SortedBag here for 2 purposes
* - Count how many wikiwords are duplicated and putting this in the top. Doing so
* we have the most important related words first.
* - Avoid the re-relate All when a comment is removed, because it could remove
* a related word that is also in the definition text.
**/
private SortedBag<Wikiword> related;
/* tags related to this wikiword. */
private SortedBag<Wikiword> tags;
/* comments for each Wikiword. */
private List<Text> comments;
/* Users escorting this Wikiword. */
private Set<User> escortWord;
/* if this wikiword is case sensitive */
private Boolean caseSensitive = DEFAULT_CASE_SENSITIVE_VALUE;
/* Wikiword text is visible only to a group */
private Visibility visibility = DEFAULT_VISIBILITY;
/* Creates a new Wikiword with a key. */
public Wikiword (String key) {
super(key);
}
public boolean isUsed() {
return !escortWord().isEmpty()
|| !comments().isEmpty()
|| !tags().isEmpty()
|| !related().isEmpty()
|| definition().hasCurrent();
}
public boolean isTalkingAbout(Element thisThing) {
if (!hasDefinition()) {
return false;
} else {
// Check if this page is talking about thisThing in comments
// tags or in the current text
boolean isTalkingInComments = false;
for (Text t : comments()) {
if (t.has(thisThing)) {
isTalkingInComments = true;
break;
}
}
if (getDefinition().has(thisThing)
|| getTags().contains(thisThing)
|| isTalkingInComments)
return true;
return false;
}
}
// ***************************
// Collection creators.
// ***************************
private HistoryText definition() {
if (definition == null)
definition = new HistoryText(this);
return definition;
}
private SortedBag<Wikiword> related() {
if (related == null)
related = new SortedBag<Wikiword>();
return related;
}
private SortedBag<Wikiword> tags() {
if (tags == null)
tags = new SortedBag<Wikiword>();
return tags;
}
private List<Text> comments() {
if (comments == null)
comments = new ArrayList<Text>();
return comments;
}
private Set<User> escortWord() {
if (escortWord == null)
escortWord = new HashSet<User>();
return escortWord;
}
public Set<User> getEscortWikiWord() {
return escortWord();
}
// ***************************
// Related Text
// ***************************
/**
* Called when a comment or a tag is removed.
* Causes remove elements using reference
*/
private void unrelateText(Text text) {
if (text == null) return;
for (Element e : text) {
if (e instanceof Wikiword){
((Wikiword)e).removeRelated(this);
}
}
}
/**
* Called when a comment is included.
*/
private void relateText(Text text) {
if (text == null) return;
for (Element e : text) {
if (e instanceof Wikiword){
((Wikiword)e).addRelated(this);
}
}
}
public void cleanRelated() {
unrelateText(definition.getCurrent());
for (Text t: comments()) {
unrelateText(t);
}
for (Wikiword tag: tags()) {
tag.removeRelated(this);
}
}
public void relateAll() {
relateText(definition.getCurrent());
for (Text t : comments()) {
relateText(t);
}
for (Wikiword tag : tags()) {
tag.addRelated(this);
}
}
/** sets that the text in param is using this element. */
public void addRelated(Wikiword word) {
related().add(word);
}
/** sets that the text in param is using this element. */
public void removeRelated(Wikiword word) {
related().remove(word);
}
/** Returns all Text that are using this Element. */
public SortedBag<Wikiword> getRelated() {
return related();
}
// ***************************
// Comments
// ***************************
public void addComment(Text text) {
comments().add(text);
if (text.getWhoPosted() instanceof User) {
escortWord().add((User)text.getWhoPosted());
}
relateText(text);
}
/**
* Do not remove the escorting user.
* The user must explicity do this.
*/
public Text removeComment(int index) {
Text t = comments().remove(index);
unrelateText(t);
return t;
}
public void clearComments() {
for (Text comm : comments()) {
unrelateText(comm);
}
comments = null;
}
public Date hasCommentBy(String byUser) {
for (Text comm : comments()) {
if (byUser.equals(comm.getWhoPosted().getIdentifier())) {
return comm.getPostDate();
}
}
return null;
}
public Date hasCommentAfter(Date since) {
for (Text comm : comments()) {
if (!since.after(comm.getPostDate())) {
return comm.getPostDate();
}
}
return null;
}
public List<Text> getComments() {
return comments();
}
public Date getLastCommentPostDate() {
if (comments().isEmpty()) return null;
return comments().get(comments().size()-1).getPostDate();
}
// ***************************
// Escorting
// ***************************
public void addEscortWikiword(User user) {
escortWord().add(user);
}
public void removeEscortWikiword(User user) {
escortWord().remove(user);
}
public boolean isEscorting(String user) {
if (user == null) return false;
for (User u : escortWord()) {
if (user.equals(u.getIdentifier())) {
return true;
}
}
return false;
}
// *************************
// Tags
// *************************
public void addTag(Wikiword tag) {
tags().add(tag);
tag.addRelated(this);
}
public void removeTag(Wikiword tag) {
tags().remove(tag);
tag.removeRelated(this);
}
public SortedBag<Wikiword> getTags() {
return tags();
}
public void clearTags() {
for (Wikiword w : tags()) {
w.removeRelated(this);
}
tags().clear();
}
// *************************
// Definition
// *************************
/** Gets the definition of an element */
public Text getDefinition() {
return this.definition().getCurrent();
}
/** Sets the definition of an element */
public void setDefinition(Text definition) {
this.definition().setText(definition);
if (definition.getWhoPosted() != null
&& definition.getWhoPosted() instanceof User) {
escortWord().add((User)definition.getWhoPosted());
}
}
/**
* Returns the History in descending mode.
* Index = 0 is the most actual text.
* @param index
*/
public Text getHistory(int index) {
return definition().getHistory(index);
}
/** Returns the number of definitions already posted to this Element **/
public int getHistoryCount() {
return definition().getHistoryCount();
}
/** if this element has a definition */
public boolean hasDefinition() {
return definition().hasCurrent();
}
public Date getLastDefinitionDate() {
if (!hasDefinition())
return null;
return getDefinition().getPostDate();
}
public Date getFirstDefinitionDate() {
if (!hasDefinition())
return null;
return getHistory(getHistoryCount()-1).getPostDate();
}
public String getLastDefinitionUser() {
if (!hasDefinition())
return null;
return getDefinition().getWhoPosted().getIdentifier();
}
/** Returns true if this Wikiword has a definition after the date. */
public boolean hasLastDefinitionDateAfter(Date date) {
if (!hasDefinition()) return false;
if (!getLastDefinitionDate().before(date)) {
return true;
}
return false;
}
public boolean hasFirstDefinitionDateAfter(Date date) {
if (!hasDefinition()) return false;
if (!getFirstDefinitionDate().before(date)) {
return true;
}
return false;
}
public List<Text> removeDefinitions(Date since, String byUser) {
if (!hasDefinition()) return null;
List<Text> list = new ArrayList<Text>();
for (Text comm : comments()) {
if (!since.after(comm.getPostDate())) {
if (byUser.equals(comm.getWhoPosted().getIdentifier())) {
list.add(comm);
}
}
}
for (Text comm : list) {
comments().remove(comm);
}
list.addAll(definition().removeTextByUser(since, byUser));
return list;
}
// *************************
// Copy and Clean: Rename
// *************************
public void copy(Wikiword w) {
definition = w.definition.clone(this);
comments().addAll(w.comments());
caseSensitive = w.caseSensitive;
visibility = w.visibility;
escortWord().addAll(w.escortWord());
tags = w.tags;
relateAll();
}
public void clean() {
cleanRelated();
definition = null;
caseSensitive = DEFAULT_CASE_SENSITIVE_VALUE;
comments = null;
visibility = DEFAULT_VISIBILITY;
escortWord = null;
tags = null;
}
// *************************
// Case Sensitive
// *************************
private boolean caseSensitive() {
if (caseSensitive == null) {
caseSensitive = DEFAULT_CASE_SENSITIVE_VALUE;
}
return caseSensitive;
}
public boolean isCaseSensitive() {
return caseSensitive();
}
public void setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
// *************************
// Visibility
// *************************
public Visibility getVisibility() {
if (visibility == null) {
visibility = DEFAULT_VISIBILITY;
}
return visibility;
}
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
public boolean isPublic() { return getVisibility() == Visibility.Public; }
public boolean isToUsers() { return getVisibility() == Visibility.User; }
public boolean isToReaders() { return getVisibility() == Visibility.Reader; }
public boolean isToEditors() { return getVisibility() == Visibility.Editor; }
public boolean isToAdmins() { return getVisibility() == Visibility.Admin; }
public int compareTo(Wikiword arg0) {
if (arg0 == null) return -1;
return getKeyword().compareTo(arg0.getKeyword());
}
}