/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.model.entity;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.jtalks.common.model.entity.Entity;
import org.jtalks.jcommune.model.validation.annotations.PollItemsNamesLength;
import org.jtalks.jcommune.model.validation.annotations.PollItemsNotEmptyIfTitleFilled;
import org.jtalks.jcommune.model.validation.annotations.PollItemsSize;
import org.jtalks.jcommune.model.validation.annotations.PollItemsWithoutDuplicates;
import org.jtalks.jcommune.model.validation.annotations.PollTitleNotBlankIfItemsFilled;
import org.springframework.util.CollectionUtils;
import com.google.common.base.Joiner;
import javax.validation.constraints.Future;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static ch.lambdaj.Lambda.forEach;
import static ch.lambdaj.Lambda.sumFrom;
/**
* Represents the poll of the topic. Contains the list of related {@link PollItem}.
* Poll may be either "single type" or "multiple type" also topic may have an end date.
* Poll is tied to the life cycle of the topic({@link Topic}).
*
* @author Anuar Nurmakanov
* @author Andrey Ivanov
*/
@PollTitleNotBlankIfItemsFilled
@PollItemsNotEmptyIfTitleFilled
public class Poll extends Entity {
private static final String SEPARATOR = System.getProperty("line.separator");
public static final int MIN_TITLE_LENGTH = 3;
public static final int MAX_TITLE_LENGTH = 120;
public static final int MIN_ITEMS_NUMBER = 2;
public static final int MAX_ITEMS_NUMBER = 50;
@Size(min = Poll.MIN_TITLE_LENGTH, max = Poll.MAX_TITLE_LENGTH)
private String title;
private boolean multipleAnswer;
@Future
private DateTime endingDate;
@PollItemsSize
@PollItemsNamesLength
@PollItemsWithoutDuplicates
private List<PollItem> pollItems = new ArrayList<>();
private Topic topic;
//transient fields
private String pollItemsValue;
/**
* Used only by Hibernate.
*/
public Poll() {
}
/**
* Creates the Poll instance with required fields.
* Poll is "single answer type" by default.
*
* @param title the poll title
*/
public Poll(String title) {
this.title = title;
}
/**
* Get the poll title.
*
* @return the poll title
*/
public String getTitle() {
return title;
}
/**
* Set the the poll title.
*
* @param title the poll title
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Poll may be either "single answer type" or "multiple answer type".
*
* @return <tt>false</tt> if the poll is "single answer type",
* <tt>true</tt> if the poll is "multiple answer type"
*/
public boolean isMultipleAnswer() {
return multipleAnswer;
}
/**
* Set the poll type. Poll may be either "single answer type"
* or "multiple answer type".
*
* @param multipleAnswer <tt>false</tt> if the poll is "single answer type",
* <tt>true</tt> if the poll is "multiple answer type"
*/
public void setMultipleAnswer(boolean multipleAnswer) {
this.multipleAnswer = multipleAnswer;
}
/**
* Get the poll ending date.
*
* @return the poll ending date
*/
public DateTime getEndingDate() {
return endingDate;
}
/**
* Set the poll ending date.
*
* @param endingDate poll ending date
*/
public void setEndingDate(DateTime endingDate) {
this.endingDate = endingDate;
}
/**
* Get the list of poll options.
*
* @return the list of poll options
*/
public List<PollItem> getPollItems() {
return pollItems;
}
/**
* Set the list of poll options.
*
* @param pollItems the list of poll options
*/
public void setPollItems(List<PollItem> pollItems) {
this.pollItems = pollItems;
}
/**
* Get the topic that contains this poll.
*
* @return the topic that contains this poll
*/
public Topic getTopic() {
return topic;
}
/**
* Get the topic that contains this poll.
*
* @param topic the topic that contains this poll
*/
public void setTopic(Topic topic) {
this.topic = topic;
}
/**
* Add the poll options to this poll.
*
* @param options the poll option
*/
public void addPollOptions(PollItem... options) {
addPollOptions(Arrays.asList(options));
}
/**
* Add the list of poll options to this poll.
*
* @param options the list of poll options to this poll
*/
public void addPollOptions(List<PollItem> options) {
pollItems.addAll(options);
forEach(options).setPoll(this);
}
/**
* Counts the total count of votes in the poll.
*
* @return the total count of votes in the poll
*/
public int getTotalVotesCount() {
return sumFrom(pollItems, PollItem.class).getVotesCount();
}
/**
* Evaluates the current activity of poll.
*
* @return <tt>true</tt> if the poll is active
* <tt>false</tt> if the poll is inactive
*/
public boolean isActive() {
return endingDate == null || endingDate.isAfterNow();
}
/**
* Determines a existence the poll in the topic.
*
* @return <tt>true</tt> if the poll exists
* <tt>false</tt> if the poll doesn't exist
*/
public boolean isHasPoll() {
return StringUtils.isNotBlank(getTitle()) &&
!CollectionUtils.isEmpty(pollItems);
}
/**
* Set string representation of poll options. Parse this string and fill
* poll items list.
*
* @param pollItemsValue poll options in string representation
*/
public void setPollItemsValue(String pollItemsValue) {
if (StringUtils.isNotBlank(pollItemsValue)) {
this.pollItemsValue = pollItemsValue;
this.setPollItems(parseItems(pollItemsValue));
}
}
/**
* @return poll options in string representation.
*/
public String getPollItemsValue() {
if (StringUtils.isBlank(pollItemsValue) && !CollectionUtils.isEmpty(pollItems)) {
pollItemsValue = Joiner.on(SEPARATOR).join(pollItems);
}
return pollItemsValue;
}
/**
* Prepare poll items list from string. Removes empty lines from.
*
* @param pollItems user input
* @return processed poll items list
*/
private List<PollItem> parseItems(String pollItems) {
List<PollItem> result = new ArrayList<>();
if (pollItems == null) {
return result;
}
String[] items = StringUtils.split(pollItems, SEPARATOR);
for (String item : items) {
// If user entered empty lines these lines are ignoring from
// validation.
// Only meaningful lines are processed and user get processed output
if (StringUtils.isNotBlank(item)) {
item = item.trim();
PollItem pollItem = new PollItem(item);
result.add(pollItem);
}
}
return result;
}
}