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

// Java Classes
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Date;
import java.io.Serializable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// Library Classes
import org.apache.commons.lang.Validate;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

// Framework Classes
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.model.EntityKeyFactory;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

// ESR Classes
import gov.va.med.esr.service.impl.ChangeEvent;
import gov.va.med.esr.service.impl.HistoricalInfo;
import gov.va.med.esr.ui.common.util.DateUtils;
import gov.va.med.esr.ui.common.util.JspUtils;
import gov.va.med.esr.ui.util.ConvertUtils;
import gov.va.med.esr.ui.util.SessionManager;

/**
 * @author DNS   KATIKM and Andrew Pach
 * @version 3.0 Generic Action class to implement history screens
 */
public class HistoryAction extends AbstractHistoryAction
{
    public static final String HISTORY = "history";
    public static final String HISTORY_CHANGE_EVENTS = "History_Change_Events";
    public static final String HISTORY_CHANGE_EVENT_KEYS = "History_Change_Event_Keys";
    public static final String HISTORY_CONFIGURATION = "History_Configuration";
    public static final String HISTORY_ACTION_NAME = "History_Action_Name";
    public static final String FWD_HISTORY = "history";
    public static final String BACK_TO_ORIGINATOR = "return";
    public static final String HISTORY_ENTITY_ID = "entityId";
    public static final String HISTORY_RETURN_PATH = "returnPath";

    public HistoryAction()
    {
        super();
    }

    /**
     * Based on the parameter passed retrives the configuration info and executes the configured service to retrive the
     * ChangeSets. Then selectes the first ChangeSet and forwards the request to display the change set info
     *
     * @param mapping the action mapping.
     * @param form the action form.
     * @param request the HttpServletRequest
     * @param response The HttpServletResponse
     *
     * @return The ActionForward
     * @throws Exception if any problems were encountered.
     */
    public ActionForward display(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        HistoryForm historyForm = (HistoryForm)form;
        Validate.notNull(historyForm);

        // Get the configuration details
        String cfgName = request.getParameter(HISTORY);
        String returnPath = request.getParameter(HISTORY_RETURN_PATH);
        Validate.notNull(cfgName);
        historyForm.setHistoryConfigName(cfgName);
        HistoryConfiguration histConfig = getHistoryConfiguration(cfgName);
        histConfig.setReturnPath(returnPath);// action specific return path
        historyForm.setActionName(histConfig.getActionName());
        historyForm.setReturnLinkMessageKey(histConfig.getReturnLinkMessageKey());
        historyForm.setTitle(histConfig.getTitle());
        request.getSession().setAttribute(HISTORY_CONFIGURATION, histConfig);

        boolean isAddAPerson = false;
        isAddAPerson = SessionManager.isAddAPerson(request);

        Set changeEvents = null;
        
        if (!isAddAPerson) {
	        EntityKey entityKey = getEntityKey(request, histConfig.getEntityClassName());
	
	        // Get request and session parameters
	        histConfig = updateParameterValues(request, histConfig);
	
	        // Invoke Service to get the Change Sets
	        changeEvents = getChangeEvents(histConfig, entityKey);
        }
        
        if (changeEvents == null || changeEvents.size() == 0)
        {
            request.getSession().setAttribute(HISTORY_CHANGE_EVENTS, null);
            request.getSession().setAttribute(HISTORY_CHANGE_EVENT_KEYS, null);
        }
        else
        {
            // Comparator specific to ChangeEvent defined as in inner class
            Comparator comparator = new Comparator()
            {
                public int compare(Object pObject1, Object pObject2)
                {
                    ChangeEvent event1 = (ChangeEvent)pObject1;
                    ChangeEvent event2 = (ChangeEvent)pObject2;
                    if (event1 == null || event1.getTimeStamp() == null) return -1;
                    if (event2 == null || event2.getTimeStamp() == null) return 1;
                    return (event2.getTimeStamp().compareTo(event1.getTimeStamp()));
                }
            };

            List orderedChangeEvents = new ArrayList(changeEvents);
            Collections.sort(orderedChangeEvents, comparator);

            request.getSession().setAttribute(HISTORY_CHANGE_EVENTS, orderedChangeEvents);
            List eventKeys = new ArrayList();

            for (Iterator iter = orderedChangeEvents.iterator(); iter.hasNext();)
            {
                Timestamp time = ((ChangeEvent)iter.next()).getTimeStamp();
                eventKeys.add(DateUtils.formatWithTime(time, null));
            }

            // Event Keys (formatted timestamps)
            request.getSession().setAttribute(HISTORY_CHANGE_EVENT_KEYS, eventKeys);

            // Get the first change event to display the data
            ChangeEvent changeEvent = (ChangeEvent)orderedChangeEvents.iterator().next();
            String key = DateUtils.formatWithTime(changeEvent.getTimeStamp(), null);
            historyForm.setChangeEventKey(key);
            return displayChangeEvent(mapping, form, request, response);
        }

        return mapping.findForward(FWD_HISTORY);
    }

    /**
     * Return the entity key that is needed to get history on.  This entity key will be passed into the history service
     * method to get a list of change times.  If no entity key is required, null should be returned. Other
     * HistoryActions that require a special type of EntityKey (e.g. PersonHistoryAction) should override this method.
     *
     * @param request The HttpServletRequest
     * @param className ClassName specified in the configuration
     *
     * @return null.
     * @throws Exception never.
     */
    public EntityKey getEntityKey(HttpServletRequest request, String className) throws Exception
    {
        // Get the entity id from request parameters
        String entityId = request.getParameter(HISTORY_ENTITY_ID);
        if (entityId != null && className != null)
        {
            Class clazz = Class.forName(className);

            // Get the entity key to return
            EntityKey returnKey = null;
            try
            {
                // Assume the entity key is a BigDecimal
                returnKey = EntityKeyFactory.createEntityKey(new BigDecimal(entityId), clazz);
            }
            catch (Exception ex)
            {
                // If the entity key isn't a BigDecimal, then create one as a general Serializable.
                returnKey = EntityKeyFactory.createEntityKey((Serializable)entityId, clazz);
            }

            return returnKey;
        }
        else
        {
            return null;
        }
    }

    /**
     * Returns false.
     *
     * @return false.
     */
    protected boolean requiresSelectedPerson()
    {
        return false;
    }

    /**
     * Display History information for the selected Change Event
     *
     * @param mapping the action mapping.
     * @param form the action form.
     * @param request the HttpServletRequest
     * @param response The HttpServletResponse
     *
     * @return The ActionForward
     * @throws Exception if any problems were encountered.
     */
    public ActionForward displayChangeEvent(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Get change events from session
        List changeEvents = (List)request.getSession().getAttribute(HISTORY_CHANGE_EVENTS);

        // Get the selected change event key from the form
        HistoryForm historyActionForm = (HistoryForm)form;
        String key = historyActionForm.getChangeEventKey();

        // Get the configuration from the history
        HistoryConfiguration histConfig = (HistoryConfiguration)
            request.getSession().getAttribute(HISTORY_CONFIGURATION);
        historyActionForm.setActionName(histConfig.getActionName());
        historyActionForm.setReturnLinkMessageKey(histConfig.getReturnLinkMessageKey());
        historyActionForm.setTitle(histConfig.getTitle());

        if (changeEvents == null || changeEvents.size() == 0 || StringUtils.isEmpty(key))
        {
            if (logger.isDebugEnabled())
            {
                logger.debug("ChangeEvents Empty or Selected Key is Empty");
            }
            return mapping.findForward(FWD_HISTORY);
        }

        // Get the selected change event
        for (Iterator iter = changeEvents.iterator(); iter.hasNext();)
        {
            ChangeEvent selectedEvent = (ChangeEvent)iter.next();
            if (key.equals(DateUtils.formatWithTime(selectedEvent.getTimeStamp(), null)))
            {
                if (iter.hasNext()){
                    selectedEvent.setPrevousChangeEvent((ChangeEvent)iter.next());
                }
                //Get the history information for the selected event
                HistoricalInfo historicalInfo = getHistoricalInfo(request, histConfig, selectedEvent);

                //convert data into history form
                List list = convert(request, histConfig, historicalInfo);
                historyActionForm.setHistoricalInfo(list);
                break;
            }
        }

        return mapping.findForward(FWD_HISTORY);
    }

    /**
     * Return link to the Originator
     *
     * @param mapping the action mapping.
     * @param form the action form.
     * @param request the HttpServletRequest
     * @param response The HttpServletResponse
     *
     * @return The ActionForward
     * @throws Exception if any problems were encountered.
     */
    public ActionForward returnToOriginator(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        HistoryConfiguration histConfig =
            (HistoryConfiguration)request.getSession().getAttribute(HISTORY_CONFIGURATION);
        if (histConfig != null)
        {
            // Clean up the session
            request.getSession().setAttribute(HISTORY_CONFIGURATION, null);

            // Sepecific return parameter is specified forward to that link
            // else forward to the return path defined in the configuration
            if (StringUtils.isNotEmpty(histConfig.getReturnPath()))
            {
                return mapping.findForward(histConfig.getReturnPath());
            }
            else
            {
                if (StringUtils.isNotEmpty(histConfig.getReturnActionForward()))
                {
                    return mapping.findForward(histConfig.getReturnActionForward());
                }
                else
                {
                    ActionForward forward = mapping.findForward(BACK_TO_ORIGINATOR);
                    if (forward != null) return forward;
                }
            }
        }

        // Go back to the default screen
        return mapping.findForward(FWD_HISTORY);
    }

    protected HistoricalInfo getHistoricalInfo(HttpServletRequest request, HistoryConfiguration histConfig,
        ChangeEvent changeEvent) throws ServiceException
    {
        return super.getHistoricalInfo(histConfig, changeEvent);
    }

    protected Set getChangeEvents(HistoryConfiguration histConfig, EntityKey key)
        throws ServiceException
    {
        return super.getChangeEvents(histConfig, key);
    }

    /**
     * Initialize and get the Struts lookup dispatch method map hashmap.
     *
     * @return the method map
     * @see org.apache.struts.actions.LookupDispatchAction#getKeyMethodMap()
     */
    protected Map getKeyMethodMap()
    {
        Map map = new HashMap();
        map.put("button.viewData", "displayChangeEvent");
        map.put("button.display", "display");
        map.put("button.return", "returnToOriginator");
        return map;
    }

    public void afterPropertiesSet() throws Exception
    {
        //services are retrieved dynamically based on the passed configuration
    }

    public String formatSSN(String ssn)
    {
        return (StringUtils.isNotEmpty(ssn)) ? JspUtils.displaySSN(ssn) : "";
    }

    public String formatDateTime(Date date)
    {
        return DateUtils.formatWithTime(date, DateUtils.MMDDYYYYHHMMSS);
    }
    
    public String convertBoolean(Boolean bool){
    	
    	return ConvertUtils.convertYesNoNoDataString(bool);
    	
    	
    }
}
