/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

====================================================================== */

package org.bodington.assessment;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.bodington.assessment.QuestionnaireFacility.QuestionnaireRenderer;
import org.bodington.database.PrimaryKey;
import org.bodington.server.BuildingContext;
import org.bodington.server.BuildingServerException;
import org.bodington.server.realm.User;
import org.bodington.servlet.Request;

/**
 * Class for rendering questionnaires in the <em>view</em> and <em>review</em>
 * states. For the <em>view</em> state, this class is used to render the
 * questions themselves and, where appropriate, the current user's existing
 * responses to the questionnaire in a non-editable form. For the
 * <em>review</em> state, this can be used to render an individual
 * questionnaire result (specified to it via the
 * {@link ViewQuestionnaireRenderer#ViewQuestionnaireRenderer(PrimaryKey)}
 * constructor).
 * @author Alexis O'Connor
 */
class ViewQuestionnaireRenderer extends AbstractQuestionnaireRenderer
    {
    PrimaryKey questionnaireResultID;
    
    /**
     * Create an instance to view the implicit questionnaire result.
     */
    ViewQuestionnaireRenderer()
    {
    }
    
    /**
     * Create an instance to view the specified questionnaire result.
     * @param questionnaireResultID the ID of the questionnaire result you wish
     * to view.
     * @see QuestionnaireResult#getQuestionnaireResultId()
     */
    ViewQuestionnaireRenderer(PrimaryKey questionnaireResultID) 
    {
    this.questionnaireResultID = questionnaireResultID;
    }
    
    public void paperToHTML( Request request, PrintWriter out,
        QuestionnaireSession session ) throws IOException,
        BuildingServerException
        {
        if ( isReview() && !session.isReviewable() )
            {
            out.println( "<P><strong>The result can not currently be "
                + "reviewed.</strong> The most likely reason for this is that "
                + "the questionnaire is a partially anonymous one and the "
                + "submission deadline has not yet been reached.</P>" );
            return;
            }
        
        List questions_in_order;
        Questionnaire questionnaire = null;
        QuestionnaireQuestion question;
        QuestionnaireResult result = null;
        QuestionnaireResponse response = null;
        Map responses = null;

        questionnaire = session.getQuestionnaire();
        questions_in_order = session.getQuestionnaireQuestionsInOrder();

        if ( !isReview() ) // get 'implicit' result
            {
            result = session.getQuestionnaireResult();
            // NOTE: we may null the result so that it is not rendered.
            result = questionnaire.isHideAnswersOnSubmit() ? null : result;
            }
        else // get result specified via ID from constructor:
            {
            result = QuestionnaireResult.findQuestionnaireResult( 
                questionnaireResultID );
            }
        
        responses = result != null ? result.getQuestionnaireResponses() : null;
        
        // What's this questionnaire all about?
        out.println( questionnaire.getIntroduction() );

        if ( !isReview() )
            {
            /*
             * Messages to the user about the questionnaire.
             */
            List messages = getMessages( questionnaire, result );
            if ( messages.size() > 0 )
                {
                out.println("<p><em>NOTE: you should read the following points "
                    + "about this questionnaire.</em>");
                out.print("<ul>");
                Iterator iter = messages.iterator();
                while (iter.hasNext())
                    out.println( "<li>" + iter.next() + "</li>");
                out.print("</ul>");
                }
            }
        else
            {
            /*
             * Who submitted this response?
             */
            String userName = "Undisclosed";
            if ( !questionnaire.isAnonymous()
                && !questionnaire.isPartiallyAnonymous() )
                {
                User user = User.findUser( result.getUserId() );
                userName = user.getName();
                }
            out.println( "<p>(Respondent:&nbsp;<I>" + userName + "</I>)");
            }
        
        for (int i = 0; i < questions_in_order.size(); i++ )
            {
            question = (QuestionnaireQuestion)questions_in_order.get( i );
            response = (responses != null) 
                ? (QuestionnaireResponse)responses.get( 
                    question.getQuestionnaireQuestionId() ) : null;

            String identifier = "Q" + question.getQuestionnaireQuestionId();
            out.println( "<HR><TABLE id=" + identifier 
                + "><TR><TD COLSPAN=3><H4>Question " + (i + 1)
                + "</H4></TD></TR>" );

            questionToHTML( question, response, out );

            out.println( "</TABLE>" );
            }

        if ( questions_in_order.size() == 0 )
            {
            out.println( "<P>There are currently no questions in this " 
                         + "questionnaire.</P>" );
            }

        // "Close" link:
        String closeLink = !isReview() 
            ? "<a href=\".\" target=\"_top\">Close</a>"
            : "<a href=\"../bs_template_qitemize.html\">Back to results</a>";                
        out.println( "<p>" ); 
        out.println( "<div style=\"padding-left: 5px\">" ); 
        out.println( "<p>" + closeLink );
        out.println( "</div>" );
        out.println( "</p>" );
        }

    public void questionToHTML( QuestionnaireQuestion question,
        QuestionnaireResponse response, PrintWriter out ) throws IOException,
        BuildingServerException
        {
        out.println( "<TR><TD COLSPAN=3>" );
        out.println( question.getIntroduction() );
        out.println( "</TD></TR>" );

        int[] indices = question.getValidStatementIndices();
        for ( int i = 0; i < indices.length; i++ )
            {
            char letter = (char)('A' + i);
            out.println( "<TR><TD VALIGN=TOP WIDTH=20><B>" );
            out.println( letter );
            out.println( "</B></TD>" );
            out.println( "<TD VALIGN=TOP WIDTH=1000>" );
            out.println( question.getStatement( indices[i] ) );
            out.println( "</TD></TR>" );
            }

        // Indicate whether the question allows for a comment:
        if ( question.isCanComment() && response == null )
            {
            out.println( "<TR><TD COLSPAN=3 "
                + "style=\"font-size: smaller; font-style: italic\">"
                + "~ This question allows for a free text comment ~"
                + "</TD></TR>" );
            }

        if ( response != null )
            {
            out.print( "<TR><TD COLSPAN=3>" );
            if ( indices.length > 0 )
                {
                Collection selection = selection( question, response );
                if ( !selection.isEmpty() )
                    out.println( "You selected "
                        + selectionToString( selection ) + "." );
                else
                    out.println( "You haven't selected any item for this "
                        + "question." );
                }
            if ( question.isCanComment() && response.getComment() != null
                && response.getComment().length() > 0 )
                {
                out.println( "You entered this comment;<BLOCKQUOTE>" );
                out.print( response.getComment() );
                out.println( "</BLOCKQUOTE>" );
                }
            }
        }

    protected List getMessages( Questionnaire questionnaire, 
        QuestionnaireResult result )
        {
        List messages = super.getMessages( questionnaire, result );
        messages.add(0, "You can only view the questions at this time.");
        return messages;
        }
    
    /**
     * Indicates whether this renderer is intended for review style. If this
     * class was specified a questionnaire result ID via the
     * {@link #ViewQuestionnaireRenderer(PrimaryKey)}, then it is assumed that
     * this renderer is intended to render the paper in review style. 
     * @return <code>true</code> if this renderer is intended for review, 
     * otherwise <code>false</code>.
     * @see #ViewQuestionnaireRenderer(PrimaryKey)
     */
    private boolean isReview()
        {
        return questionnaireResultID != null;
        }
    
    private String selectionToString( Collection selection )
        {
        Iterator responses = selection.iterator();
        StringBuffer sb = new StringBuffer();
        while ( responses.hasNext() )
            {
            sb.append( (char)('A' + ((Integer)responses.next()).intValue()) );
            if ( responses.hasNext() )
                sb.append( ", " );
            }

        return sb.toString();
        }
    }
