package gov.va.med.esr.ui.message.action;

// Java Classes
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.mlw.vlh.ValueList;

import org.apache.commons.lang.Validate;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

import gov.va.med.esr.common.model.lookup.MessageType;
import gov.va.med.esr.common.model.messaging.ArchivedMessageLogEntry;
import gov.va.med.esr.common.model.messaging.MessageLogEntry;
import gov.va.med.esr.messaging.xml.XmlFormatter;
import gov.va.med.esr.service.MessageFormatterService;
import gov.va.med.esr.ui.ApplicationConstants;
import gov.va.med.esr.ui.common.action.AbstractAction;
import gov.va.med.fw.hl7.MessageParser;
import gov.va.med.fw.ui.struts.ValueListActionUtils;
import gov.va.med.fw.ui.valuelist.MaxRecordsExceededValueListException;
import gov.va.med.fw.util.StringUtils;
import gov.va.med.fw.util.SystemUtils;
import gov.va.med.fw.util.builder.BuilderException;

/**
 * @author Muddaiah Ranga
 * @author Andrew Pach
 * @version 3.0
 */
public class MessageAction extends AbstractAction implements MessageConstants
{
    /**
     * The maximum number of characters to fit on 1 line of a raw message.
     */
    public static final int MAX_CHARS_PER_LINE = 100;

    /**
     * The minimum number of rows that will be displayed for a raw message.
     */
    public static final int MIN_RAW_MESSAGE_ROWS = 22;

    
    private MessageFormatterService    messageFormatterService;
    
      
    
    public MessageFormatterService getMessageFormatterService() {
        return messageFormatterService;
    }

    public void setMessageFormatterService(MessageFormatterService messageFormatterService) {
        this.messageFormatterService = messageFormatterService;
    }

    /**
     * Displays transmission search screen.
     *
     * @param mapping Struts action mapping for this action
     * @param actionForm Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward display(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request,
        HttpServletResponse response) throws Exception
    {
        return mapping.findForward(DISPLAY_SEARCH);
    }

    /**
     * Clears the form.
     *
     * @param mapping Struts action mapping for this action
     * @param actionForm Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward clear(ActionMapping mapping, ActionForm actionForm,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        ((MessageSearchForm)actionForm).clear();
        return display(mapping, actionForm, request, response);
    }

    /**
     * Searches transmission log.
     *
     * @param mapping Struts action mapping for this action
     * @param actionForm Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward search(ActionMapping mapping, ActionForm actionForm,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        try
        {
            MessageSearchForm form = (MessageSearchForm)actionForm;
            // Get the value list information
            ValueList valueList =
                ValueListActionUtils.getValueList(form, request, MESSAGE_SEARCH_TABLE_ID, MESSAGE_SEARCH_ADAPTER);
            ValueListActionUtils.setValueList(request, valueList, VALUE_LIST);
            if (valueList == null || !valueList.hasNext())
            {
                addInformationMessage(request, ApplicationConstants.MessageKeys.ERRORS_SEARCH_NORESULT);
            }
        }
        catch (MaxRecordsExceededValueListException ex)
        {
            // The search exceeded the maximum number of records allowed.
            addActionMessage(request, new ActionMessage(ApplicationConstants.MessageKeys.ERRORS_MAX_RECORDS_EXCEEDED,
                new Integer(ex.getTotalRecords()), new Integer(ex.getRecordLimit())));
        }
        return display(mapping, actionForm, request, response);
    }

    /**
     * View Transmission detail.
     *
     * @param mapping Struts action mapping for this action
     * @param actionForm Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewDetail(ActionMapping mapping, ActionForm actionForm,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        request.setAttribute(SELECTED_MESSAGE, getSelectedMessage(request));
        setSelectedSiteId(request);
        return mapping.findForward(DISPLAY_DETAIL);
    }

    /**
     * Retransmit a message.
     *
     * @param mapping Struts action mapping for this action
     * @param actionForm Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward retransmit(ActionMapping mapping, ActionForm actionForm,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        String messageLogId = request.getParameter(ApplicationConstants.JSPParameters.SELECTED_MSG_ID_PARAM);
        if (StringUtils.isNotEmpty(messageLogId))
        {
            this.getMessagingService().triggerRetransmission(new BigDecimal(messageLogId));
            addInformationMessage(request, MESSAGE_RETRANSMITTED);
        }
        setSelectedSiteId(request);
        return search(mapping, actionForm, request, response);
    }
    
    /**
     * Displays the raw message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewRawMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
    	HttpSession session = request.getSession();
    	if(session.getAttribute(SELECTED_MESSAGE) != null && session.getAttribute(SELECTED_MESSAGE).getClass().equals(ArchivedMessageLogEntry.class)){
    		viewArchivedRawMessage(mapping, form, request, response);    		
    	}
    	else{
    		viewMessageLogRawMessage(mapping, form, request, response);
    	}
        // Forward to the raw message page
        return mapping.findForward(DISPLAY_RAW_MESSAGE);
    }

    /**
     * Displays the raw message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewMessageLogRawMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Get a selected message
        MessageLogEntry message = getSelectedMessage(request);

        // Get the unformatted message.  Remove the extra line separator at the end if one exists.
        String unformattedMessage = message.getBody();
        if (unformattedMessage.endsWith(MessageParser.MESSAGE_LINE_SEPARATOR))
        {
            unformattedMessage = unformattedMessage.substring(
                0, unformattedMessage.length() - MessageParser.MESSAGE_LINE_SEPARATOR.length());
        }

        // Get the formatted message
        String formattedMessage = MessageParser.getFormattedRawMessage(message.getBody(), MAX_CHARS_PER_LINE);

        // Compute the number of rows in the message and formatted message.  One extra line is to handle the fact that
        // there is one more line than return characters.  The other extra line is to ensure no vertical
        // scroll bar is added to the text area.  Internet Explorer adds the vertical scroll bar if
        // the number of rows match the text exactly - so we need to add one more.
        int unformattedMessageRows =
            StringUtils.numTimesStringPresent(unformattedMessage, MessageParser.MESSAGE_LINE_SEPARATOR) + 2;
        int formattedMessageRows = StringUtils.numTimesStringPresent(formattedMessage, SystemUtils.LINE_SEPARATOR) + 2;
        if (unformattedMessageRows < MIN_RAW_MESSAGE_ROWS)
        {
            unformattedMessageRows = MIN_RAW_MESSAGE_ROWS;
        }
        if (formattedMessageRows < MIN_RAW_MESSAGE_ROWS)
        {
            formattedMessageRows = MIN_RAW_MESSAGE_ROWS;
        }

        // Make information available to the page
        setSelectedSiteId(request);
        request.setAttribute(FORMATTED_MESSAGE, formattedMessage);
        request.setAttribute(UNFORMATTED_MESSAGE, unformattedMessage);
        request.setAttribute(FORMATTED_MESSAGE_ROWS, String.valueOf(formattedMessageRows));
        request.setAttribute(UNFORMATTED_MESSAGE_ROWS, String.valueOf(unformattedMessageRows));

        // Forward to the raw message page
        return mapping.findForward(DISPLAY_RAW_MESSAGE);
    }
    
    /**
     * Displays the parsed message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewParsedMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
    	HttpSession session = request.getSession();
    	try {
	    	if(session.getAttribute(SELECTED_MESSAGE) != null && session.getAttribute(SELECTED_MESSAGE).getClass().equals(ArchivedMessageLogEntry.class)){
	    		viewArchivedParsedMessage(mapping, form, request, response);    		
	    	}
	    	else{
	    		viewMessageLogParsedMessage(mapping, form, request, response);
	    	}
    	} catch (BuilderException be) {
//    		throw new BuilderException( "Failed to transform the message", be);
    	}
        return mapping.findForward(DISPLAY_PARSED_MESSAGE);
    }

    /**
     * Displays the parsed message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewMessageLogParsedMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        MessageLogEntry message = getSelectedMessage(request);

        //Convert the message to XML format
        //String xmlMessage = (message != null) ? message.getFormattedBody() : null;
        String xmlMessage = null;
        try {
        	xmlMessage = (message != null) ? messageFormatterService.getFormattedMessage(message): null;
        } catch(BuilderException be) {
// INC000001026716 - ESR 4.0_CodeCR3459 - hl7 message validation issue - display cause and message
// going to get cause and message for display 
        	String ac = (String)be.getCause().getCause().toString();   			// validator error 
        	String ad = (String)be.getData();									// hl7 message
        	
   		    addInformationMessage(request, ApplicationConstants.MessageKeys.ERRORS_INVALID, ac);
   		    xmlMessage = ad;
 //       	throw new BuilderException( "Failed to transform the message", be);
        }
        setSelectedSiteId(request);
        request.setAttribute(XML_FORMATTED_MESSAGE, xmlMessage);
        request.setAttribute(SELECTED_MESSAGE, message);
        return mapping.findForward(DISPLAY_PARSED_MESSAGE);
    }

    /**
     * Displays the error message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewErrorMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        setSelectedSiteId(request);
        request.setAttribute(SELECTED_MESSAGE, getSelectedMessage(request));
        return mapping.findForward(DISPLAY_ERROR_MESSAGE);
    }
    
    /**
     * Displays the raw message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewArchivedRawMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Get a selected message
        ArchivedMessageLogEntry message = getSelectedArchivedMessage(request);

        // Get the unformatted message.  Remove the extra line separator at the end if one exists.
        String unformattedMessage = message.getBody();
        if (unformattedMessage.endsWith(MessageParser.MESSAGE_LINE_SEPARATOR))
        {
            unformattedMessage = unformattedMessage.substring(
                0, unformattedMessage.length() - MessageParser.MESSAGE_LINE_SEPARATOR.length());
        }

        // Get the formatted message
        String formattedMessage = MessageParser.getFormattedRawMessage(message.getBody(), MAX_CHARS_PER_LINE);

        // Compute the number of rows in the message and formatted message.  One extra line is to handle the fact that
        // there is one more line than return characters.  The other extra line is to ensure no vertical
        // scroll bar is added to the text area.  Internet Explorer adds the vertical scroll bar if
        // the number of rows match the text exactly - so we need to add one more.
        int unformattedMessageRows =
            StringUtils.numTimesStringPresent(unformattedMessage, MessageParser.MESSAGE_LINE_SEPARATOR) + 2;
        int formattedMessageRows = StringUtils.numTimesStringPresent(formattedMessage, SystemUtils.LINE_SEPARATOR) + 2;
        if (unformattedMessageRows < MIN_RAW_MESSAGE_ROWS)
        {
            unformattedMessageRows = MIN_RAW_MESSAGE_ROWS;
        }
        if (formattedMessageRows < MIN_RAW_MESSAGE_ROWS)
        {
            formattedMessageRows = MIN_RAW_MESSAGE_ROWS;
        }

        // Make information available to the page
        setSelectedSiteId(request);
        request.setAttribute(FORMATTED_MESSAGE, formattedMessage);
        request.setAttribute(UNFORMATTED_MESSAGE, unformattedMessage);
        request.setAttribute(FORMATTED_MESSAGE_ROWS, String.valueOf(formattedMessageRows));
        request.setAttribute(UNFORMATTED_MESSAGE_ROWS, String.valueOf(unformattedMessageRows));

        // Forward to the raw message page
        return mapping.findForward(DISPLAY_RAW_MESSAGE);
    }

    /**
     * Displays the parsed message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewArchivedParsedMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        ArchivedMessageLogEntry message = getSelectedArchivedMessage(request);

        //Convert the message to XML format
        //String xmlMessage = (message != null) ? message.getFormattedBody() : null;
        String xmlMessage = null;
        try {
        	xmlMessage = (message != null) ? messageFormatterService.getFormattedMessage(message): null;
        } catch (BuilderException be) {
//        	throw new BuilderException("kkkkkk", be);
        	
        }
        setSelectedSiteId(request);
        request.setAttribute(XML_FORMATTED_MESSAGE, xmlMessage);
        request.setAttribute(SELECTED_MESSAGE, message);
        return mapping.findForward(DISPLAY_PARSED_MESSAGE);
    }

    /**
     * Displays the error message.
     *
     * @param mapping Struts action mapping for this action
     * @param form Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewArchivedErrorMessage(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        setSelectedSiteId(request);
        request.setAttribute(SELECTED_MESSAGE, getSelectedArchivedMessage(request));
        return mapping.findForward(DISPLAY_ERROR_MESSAGE);
    }
    
    /**
     * View Transmission detail.
     *
     * @param mapping Struts action mapping for this action
     * @param actionForm Struts form bean for this action
     * @param request The Http Request
     * @param response The Http Response
     *
     * @return A struts action forward for where we will go next.
     * @throws Exception If there are any errors during processing.
     */
    public ActionForward viewArchivedDetail(ActionMapping mapping, ActionForm actionForm,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        request.setAttribute(SELECTED_MESSAGE, getSelectedArchivedMessage(request));
        setSelectedSiteId(request);
        return mapping.findForward(DISPLAY_DETAIL);
    }

    public void afterPropertiesSet() throws Exception
    {
        Validate.notNull(this.getMessagingService(), "Missing required messaging service");
    }

    protected Map getKeyMethodMap()
    {
        if (keyMethodMap == null)
        {
            keyMethodMap = new HashMap();
            keyMethodMap.put("button.display", "display");
            keyMethodMap.put("button.search", "search");
            keyMethodMap.put("button.clear", "clear");
            keyMethodMap.put("buttom.retransmit", "retransmit");
            keyMethodMap.put("button.viewDetail", "viewDetail");
            keyMethodMap.put("link.viewParsedMessage", "viewParsedMessage");
            keyMethodMap.put("link.viewRawMessage", "viewRawMessage");
            keyMethodMap.put("link.viewErrorMessage", "viewErrorMessage");
            keyMethodMap.put("link.viewArchivedParsedMessage", "viewArchivedParsedMessage");
            keyMethodMap.put("link.viewArchivedRawMessage", "viewArchivedRawMessage"); 
            keyMethodMap.put("link.viewArchivedErrorMessage", "viewArchivedErrorMessage");
            keyMethodMap.put("button.viewArchivedDetail", "viewArchivedDetail");
        }
        return keyMethodMap;
    }

    /**
     * Gets the MessageLogEntry object.
     */
    private MessageLogEntry getSelectedMessage(HttpServletRequest request) throws Exception
    {
        MessageLogEntry messageLogEntry = null;
        // Get a message id selected
        String msgId = request.getParameter(ApplicationConstants.JSPParameters.SELECTED_MSG_ID_PARAM);
        if (StringUtils.isNotEmpty(msgId))
        {
            HttpSession session = request.getSession();
            messageLogEntry = (MessageLogEntry)session.getAttribute(SELECTED_MESSAGE);
            if (messageLogEntry == null ||
                !StringUtils.equals(msgId, messageLogEntry.getEntityKey().getKeyValueAsString()))
            {
                messageLogEntry = this.getMessagingService().getMessageLogEntryById(new BigDecimal(msgId));
                session.setAttribute(SELECTED_MESSAGE, messageLogEntry);
            }
        }
        return messageLogEntry;
    }
    
    /**
     * Gets the ArchivedMessageLogEntry object.
     */
    private ArchivedMessageLogEntry getSelectedArchivedMessage(HttpServletRequest request) throws Exception
    {
        ArchivedMessageLogEntry messageLogEntry = null;
        // Get a message id selected
        String msgId = request.getParameter(ApplicationConstants.JSPParameters.SELECTED_MSG_ID_PARAM);
        if (StringUtils.isNotEmpty(msgId))
        {
            HttpSession session = request.getSession();
            messageLogEntry = (ArchivedMessageLogEntry)session.getAttribute(SELECTED_MESSAGE);
            if (messageLogEntry == null ||
                !StringUtils.equals(msgId, messageLogEntry.getEntityKey().getKeyValueAsString()))
            {
                messageLogEntry = this.getArchivedMessagingService().getMessageLogEntryById(new BigDecimal(msgId));
                session.setAttribute(SELECTED_MESSAGE, messageLogEntry);
            }
        }
        return messageLogEntry;
    }

    private void setSelectedSiteId(HttpServletRequest request)
    {
        String selectedMsgId = request.getParameter(SELECTED_SITE_ID);
        if (StringUtils.isNotEmpty(selectedMsgId))
        {
            request.setAttribute(SELECTED_SITE_ID, selectedMsgId);
        }
    }
}
