001/*
002 *  Copyright 2011 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.survey.generators;
017
018import java.io.IOException;
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.HashMap;
022import java.util.HashSet;
023import java.util.Map;
024import java.util.Set;
025
026import org.apache.avalon.framework.parameters.ParameterException;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.ProcessingException;
030import org.apache.cocoon.generation.ServiceableGenerator;
031import org.apache.cocoon.xml.AttributesImpl;
032import org.apache.cocoon.xml.XMLUtils;
033import org.apache.commons.lang.StringUtils;
034import org.joda.time.DateTime;
035import org.joda.time.format.ISODateTimeFormat;
036import org.xml.sax.SAXException;
037
038import org.ametys.core.user.UserIdentity;
039import org.ametys.plugins.repository.AmetysObjectResolver;
040import org.ametys.plugins.survey.data.SurveyAnswer;
041import org.ametys.plugins.survey.data.SurveyAnswerDao;
042import org.ametys.plugins.survey.data.SurveySession;
043import org.ametys.plugins.survey.repository.Survey;
044import org.ametys.plugins.survey.repository.SurveyQuestion;
045
046/**
047 * Generates a specific survey user session from its ID.
048 */
049public class SurveySessionGenerator extends ServiceableGenerator
050{
051
052    /** The ametys object resolver. */
053    protected AmetysObjectResolver _resolver;
054    
055    /** The survey data DAO. */
056    protected SurveyAnswerDao _surveyDao;
057    
058    @Override
059    public void service(ServiceManager serviceManager) throws ServiceException
060    {
061        super.service(serviceManager);
062        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
063        _surveyDao = (SurveyAnswerDao) serviceManager.lookup(SurveyAnswerDao.ROLE);
064    }
065    
066    @Override
067    public void generate() throws IOException, SAXException, ProcessingException
068    {
069//        Request request = ObjectModelHelper.getRequest(objectModel);
070        
071        // Get the session ID.
072        int sessionId;
073        try
074        {
075            sessionId = parameters.getParameterAsInteger("id");
076        }
077        catch (ParameterException e)
078        {
079            throw new ProcessingException("Session ID is mandatory.", e);
080        }
081        
082        // Retrieve the corresponding session from the database.
083        SurveySession surveySession = _surveyDao.getSessionWithAnswers(sessionId);
084        
085        // Resolve the corresponding survey.
086        Survey survey = _resolver.resolveById(surveySession.getSurveyId());
087        
088        contentHandler.startDocument();
089        
090        // Generate the session and its answers.
091        saxSession(surveySession, survey, true);
092        
093        contentHandler.endDocument();
094    }
095    
096    /**
097     * Generate the data of a survey user session.
098     * @param surveySession the survey session.
099     * @param survey the survey.
100     * @param withAnswers true to generate answers along, false otherwise.
101     * @throws SAXException if an error occurs while saxing the session
102     */
103    protected void saxSession(SurveySession surveySession, Survey survey, boolean withAnswers) throws SAXException
104    {
105        DateTime submittedAt = new DateTime(surveySession.getSubmittedAt().getTime());
106        
107        AttributesImpl attrs = new AttributesImpl();
108        attrs.addCDATAAttribute("id", Integer.toString(surveySession.getId()));
109        attrs.addCDATAAttribute("submittedAt", ISODateTimeFormat.dateTime().print(submittedAt));
110        UserIdentity user = surveySession.getUser();
111        if (user != null)
112        {
113            attrs.addCDATAAttribute("user", UserIdentity.userIdentityToString(user));
114        }
115        
116        XMLUtils.startElement(contentHandler, "session", attrs);
117        
118        if (withAnswers)
119        {
120            saxAnswers(surveySession, survey);
121        }
122        
123        XMLUtils.endElement(contentHandler, "session");
124    }
125
126    /**
127     * Generate the answers of a given session.
128     * @param surveySession the survey session.
129     * @param survey the survey.
130     * @throws SAXException if an error occurs while saxing the answers
131     */
132    protected void saxAnswers(SurveySession surveySession, Survey survey) throws SAXException
133    {
134        AttributesImpl attrs = new AttributesImpl();
135        
136        Map<String, SurveyAnswer> answerMap = getAnswerMap(surveySession);
137        
138        for (SurveyQuestion question : survey.getQuestions())
139        {
140            SurveyAnswer answer = answerMap.get(question.getName());
141            
142            attrs.clear();
143            attrs.addCDATAAttribute("name", question.getName());
144            attrs.addCDATAAttribute("title", question.getTitle());
145            attrs.addCDATAAttribute("type", question.getType().toString());
146            attrs.addCDATAAttribute("mandatory", Boolean.toString(question.isMandatory()));
147            XMLUtils.startElement(contentHandler, "question", attrs);
148            
149            if (answer != null)
150            {
151                Map<String, Set<String>> values = getValueMap(question, answer.getValue());
152                
153                for (String option : values.keySet())
154                {
155                    attrs.clear();
156                    attrs.addCDATAAttribute("name", option);
157                    XMLUtils.startElement(contentHandler, "option", attrs);
158                    
159                    for (String value : values.get(option))
160                    {
161                        attrs.clear();
162                        attrs.addCDATAAttribute("value", value);
163                        XMLUtils.createElement(contentHandler, "answer", attrs);
164                    }
165                    
166                    XMLUtils.endElement(contentHandler, "option");
167                }
168            }
169            
170            XMLUtils.endElement(contentHandler, "question");
171        }
172    }
173    
174    /**
175     * Get the answers of a survey session as a Map, indexed by question ID.
176     * @param surveySession the survey session.
177     * @return the answers as a Map, indexed by question ID. 
178     */
179    protected Map<String, SurveyAnswer> getAnswerMap(SurveySession surveySession)
180    {
181        Map<String, SurveyAnswer> answerMap = new HashMap<>();
182        
183        for (SurveyAnswer answer : surveySession.getAnswers())
184        {
185            answerMap.put(answer.getQuestionId(), answer);
186        }
187        
188        return answerMap;
189    }
190    
191    /**
192     * Get the user-input value as a Map from the database value, which is a single serialized string.
193     * @param question the question.
194     * @param value the value from the database.
195     * @return the value as a Map.
196     */
197    protected Map<String, Set<String>> getValueMap(SurveyQuestion question, String value)
198    {
199        Map<String, Set<String>> values = new HashMap<>();
200        
201        if (value != null)
202        {
203            switch (question.getType())
204            {
205                case SINGLE_MATRIX:
206                case MULTIPLE_MATRIX:
207                    String[] entries = StringUtils.split(value, ';');
208                    for (String entry : entries)
209                    {
210                        String[] keyValue = StringUtils.split(entry, ':');
211                        if (keyValue.length == 2 && StringUtils.isNotEmpty(keyValue[0]))
212                        {
213                            Set<String> valueSet = new HashSet<>(Arrays.asList(StringUtils.split(keyValue[1], ',')));
214                            
215                            values.put(keyValue[0], valueSet);
216                        }
217                    }
218                    break;
219                case SINGLE_CHOICE:
220                case MULTIPLE_CHOICE:
221                    Set<String> valueSet = new HashSet<>(Arrays.asList(StringUtils.split(value, ',')));
222                    values.put("values", valueSet);
223                    break;
224                case FREE_TEXT:
225                case MULTILINE_FREE_TEXT:
226                default:
227                    values.put("values", Collections.singleton(value));
228                    break;
229            }
230        }
231        
232        return values;
233    }
234
235}