package net.sf.egonet.persistence;
import java.util.List;
import java.util.Set;
import net.sf.egonet.model.Expression;
import net.sf.egonet.model.Question;
import net.sf.egonet.model.QuestionOption;
import net.sf.egonet.model.Question.QuestionType;
import net.sf.functionalj.tuple.Triple;
import org.hibernate.Query;
import org.hibernate.Session;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
public class Questions {
public static void delete(Session session, final Question question) {
for(Question dbQuestion : matchingQuestionsFor(session,question)) {
deleteSimpleExpressionsFor(session,dbQuestion);
deleteAllAnswersForQuestion(session, question.getId());
deleteOptionsFor(session,dbQuestion);
removeReferencesInCountingExpressionsFor(session,dbQuestion);
DB.delete(session, dbQuestion);
}
}
public static void delete(final Question question) {
DB.withTx(new Function<Session,Object>(){
public Object apply(Session session) {
delete(session,question);
return null;
}
});
}
private static void removeReferencesInCountingExpressionsFor(
Session session, Question dbQuestion)
{
for(Expression expression : Expressions.forStudy(session,dbQuestion.getStudyId())) {
if(expression.getType().equals(Expression.Type.Counting)) {
Triple<Integer,List<Long>,List<Long>> numberExprsQuests =
(Triple<Integer,List<Long>,List<Long>>) expression.getValue();
if(numberExprsQuests.getSecond().contains(dbQuestion.getId())) {
List<Long> newQuests = Lists.newArrayList();
for(Long quest : numberExprsQuests.getThird()) {
if(! quest.equals(dbQuestion.getId())) {
newQuests.add(quest);
}
}
expression.setValue(new Triple<Integer,List<Long>,List<Long>>(
numberExprsQuests.getFirst(),
numberExprsQuests.getSecond(),
newQuests));
DB.save(session, expression);
}
}
}
}
private static void deleteAllAnswersForQuestion(Session session, final Long questionId) {
session.createQuery("update Answer a set active = 0 where a.questionId = :questionId")
.setParameter("questionId", questionId)
.executeUpdate();
}
@SuppressWarnings("unchecked")
public static List<Question> matchingQuestionsFor(Session session, final Question question) {
return
session.createQuery("from Question where id = :id and title = :title and studyId = :studyId and active = 1")
.setParameter("id", question.getId())
.setParameter("title", question.getTitle())
.setParameter("studyId", question.getStudyId())
.list();
}
public static void deleteOptionsFor(final Question question) {
new DB.Action<Object>() {
public Object get() {
deleteOptionsFor(session,question);
return null;
}
}.execute();
}
public static void deleteOptionsFor(Session session, final Question question) {
for(Question dbQuestion : matchingQuestionsFor(session,question)) {
for(QuestionOption option : Options.getOptionsForQuestion(session, dbQuestion.getId())) {
DB.delete(option);
}
}
}
public static void deleteSimpleExpressionsFor(Session session, final Question question) {
for(Question dbQuestion : matchingQuestionsFor(session,question)) {
for(Expression expression : Expressions.getSimpleExpressionsForQuestion(session, dbQuestion.getId())) {
Expressions.delete(session, expression);
}
}
}
public static Question getQuestion(Session session, final Long id) {
// Yes, this is different from session.load(Study.class, id),
// which triggers a lazy initialization exception when any
// field of Study is requested after the session is closed.
return (Question) session.createQuery("from Question where id = :id and active = 1")
.setParameter("id", id).list().get(0);
}
public static Question getQuestion(final Long id) {
return DB.withTx(new Function<Session,Question>(){
public Question apply(Session session) {
return getQuestion(session, id);
}
});
}
@SuppressWarnings("unchecked")
public static List<Question> getQuestionsForStudy(
Session session, final Long studyId, final QuestionType type)
{
try {
Query query = session.createQuery("from Question q where q.active = 1 and q.studyId = :studyId " +
(type == null ? "" : "and q.typeDB = :type")+ " order by q.ordering")
.setLong("studyId", studyId);
if(type != null) {
query.setString("type", Question.typeDB(type));
}
return query.list();
} catch(Exception ex) {
throw new RuntimeException(
"Unable to getQuestionsForStudy("+studyId+","+type+")",
ex);
}
}
public static List<Question> getQuestionsForStudy(final Long studyId, final QuestionType type) {
return DB.withTx(new Function<Session,List<Question>>() {
public List<Question> apply(Session session) {
return getQuestionsForStudy(session,studyId,type);
}
});
}
public static void moveEarlier(Session session, final Question question) {
List<Question> questions = getQuestionsForStudy(session,question.getStudyId(),question.getType());
Integer i = null;
for(Integer j = 0; j < questions.size(); j++) {
if(questions.get(j).getId().equals(question.getId())) {
i = j;
}
}
if(i != null && i > 0) {
Question swap = questions.get(i);
questions.set(i, questions.get(i-1));
questions.set(i-1, swap);
}
for(Integer j = 0; j < questions.size(); j++) {
questions.get(j).setOrdering(j);
DB.save(questions.get(j));
}
}
public static void moveEarlier(final Question question) {
DB.withTx(new Function<Session,Object>() {
public Object apply(Session session) {
moveEarlier(session,question);
return null;
}
});
}
public static void pull(Session session, Question target, Set<Question> selectedQuestions) {
List<Question> questions =
getQuestionsForStudy(session,target.getStudyId(),target.getType());
List<Question> newOrder = Lists.newArrayList();
for(Question question : questions) {
boolean afterTarget = question.getOrdering() > target.getOrdering();
boolean selected = selectedQuestions.contains(question);
if(! (afterTarget || selected)) {
newOrder.add(question);
}
}
for(Question question : questions) {
boolean selected = selectedQuestions.contains(question);
if(selected) {
newOrder.add(question);
}
}
for(Question question : questions) {
boolean afterTarget = question.getOrdering() > target.getOrdering();
boolean selected = selectedQuestions.contains(question);
if(afterTarget && ! selected) {
newOrder.add(question);
}
}
for(Integer j = 0; j < newOrder.size(); j++) {
newOrder.get(j).setOrdering(j);
DB.save(newOrder.get(j));
}
}
public static void pull(final Question target, final Set<Question> selectedQuestions) {
DB.withTx(new Function<Session,Object>() {
public Object apply(Session session) {
pull(session,target,selectedQuestions);
return null;
}
});
}
/**
* given the title of the question, retrieve the question
* @param session database session object
* @param title - String Uniquely identifying the question
* @param iType - the 'section' ( EGO_ID, EGO, ALTER, ALTER_PAIR ) we are looking at.
* note that it is possible this will be different than the type of the 'original'
* question. That is, when used with variable substitution we may be looking for
* a question with a given title in a different section.
* @return
*/
@SuppressWarnings("unchecked")
public static Question getQuestionUsingTitleAndTypeAndStudy(Session session,
final String title, final Question.QuestionType iType, final Long studyId) {
// Yes, this is different from session.load(Study.class, id),
// which triggers a lazy initialization exception when any
// field of Study is requested after the session is closed.
List<Question> questionList;
questionList = session.createQuery("from Question where title = :title and typeDB = :typeDB and studyId = :studyId and active = 1")
.setParameter("title", title)
.setParameter("typeDB", iType.toString())
.setParameter("studyId", studyId)
.list();
if ( questionList!=null && !questionList.isEmpty())
return questionList.get(0);
return(null);
}
/**
* given the title of the question, retrieve the question
* @param title - String Uniquely identifying the question
* @return
*/
public static Question getQuestionUsingTitleAndTypeAndStudy(final String title,
final Question.QuestionType iType, final Long studyId) {
return DB.withTx(new Function<Session,Question>(){
public Question apply(Session session) {
return getQuestionUsingTitleAndTypeAndStudy(session, title, iType, studyId);
}
});
}
/**
* next couple of functions are specific to the
* Export 'Other/Specify' text file option, which
* will export all the questions with the other/specify
* flag set, and answers to them
* @param session
* @param studyId
* @return
*/
@SuppressWarnings("unchecked")
public static List<Question> getQuestionsWithOtherSpecifyForStudy(
Session session, final Long studyId)
{
try {
Query query = session.createQuery("from Question q where q.active = 1 and q.studyId = :studyId " +
"and q.otherSpecify = :otherSpecify order by q.ordering")
.setLong("studyId", studyId)
.setBoolean("otherSpecify", true);
return query.list();
} catch(Exception ex) {
throw new RuntimeException(
"Unable to getQuestionsForStudy("+studyId+")",
ex);
}
}
public static List<Question> getQuestionsWithOtherSpecifyForStudy(final Long studyId) {
return DB.withTx(new Function<Session,List<Question>>() {
public List<Question> apply(Session session) {
return getQuestionsWithOtherSpecifyForStudy(session,studyId);
}
});
}
}