/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.ui.registry.action;

import gov.va.med.esr.common.model.CommonEntityKeyFactory;
import gov.va.med.esr.common.model.lookup.RegistryType;
import gov.va.med.esr.common.model.registry.Registry;
import gov.va.med.esr.ui.common.action.AbstractAction;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

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

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

/**
 * Base action for all the registry edit classes.
 * 
 * @author Muddaiah Ranga
 * @version 3.0
 */
public abstract class RegistryEditAction extends AbstractAction implements RegistryConstants {

    public static final String FWD_REGISTRY_NO_DATA_CHANGED = "registryNoDataChanged"; // no data changed page

    /**
     * Displays the PH/POW/SHAD add 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);
    }
    
    /**
     * Displays the PH/POW/SHAD add 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 abstract ActionForward displayAdd(ActionMapping mapping, 
                                 ActionForm actionForm,
                                 HttpServletRequest request, 
                                 HttpServletResponse response) throws Exception;
    
    /**
     * Displays the PH/POW/SHAD update 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 abstract ActionForward displayUpdate(ActionMapping mapping, 
                                       ActionForm actionForm,
                                       HttpServletRequest request, 
                                       HttpServletResponse response) throws Exception;

    /**
     * Clear the PH/POW/SHAD add/update 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 reset(ActionMapping mapping, 
                               ActionForm actionForm,
                               HttpServletRequest request, 
                               HttpServletResponse response) throws Exception {
        RegistryInfoForm form = (RegistryInfoForm)actionForm;
        String pageName = form.getPageName();
        return (pageName != null && pageName.startsWith("update")) ? displayUpdate(mapping,form,request,response) : displayAdd(mapping,form,request,response);
    }
    
    /**
     * Clears the PH/POW/SHAD add 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 cancel(ActionMapping mapping, 
                                ActionForm actionForm,
                                HttpServletRequest request, 
                                HttpServletResponse response) throws Exception {
        return mapping.findForward(DISPLAY_SEARCH);
    }

    /**
     * Adds a MilitaryServiceNumber.
     * 
     * @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 addMilitaryServiceNumber(ActionMapping mapping, 
                                                  ActionForm actionForm,
                                                  HttpServletRequest request, 
                                                  HttpServletResponse response) throws Exception {
        RegistryInfoForm form  = (RegistryInfoForm)actionForm;
        form.addNewMilitaryServiceNumber();
        return (StringUtils.isEmpty(request.getParameter(REGISTRY_ID))) ? mapping.findForward(DISPLAY_ADD) : mapping.findForward(DISPLAY_UPDATE); 
    }
    
    /**
     * Displays the registry update screen back from history.
     * 
     * @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 returnFromHistory(ActionMapping mapping, 
                                           ActionForm actionForm,
                                           HttpServletRequest request, 
                                           HttpServletResponse response) throws Exception {
        RegistryInfoForm form = (RegistryInfoForm)actionForm;
        form.initialize();
        Registry registry = getRegistryFromCache(request);
        return prepareDisplayUpdate(mapping,actionForm,request,response,registry);
    }
    
    /**
     * Prepares the registry update 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.
     */
    protected ActionForward prepareDisplayUpdate(ActionMapping mapping, 
                                                 ActionForm actionForm,
                                                 HttpServletRequest request, 
                                                 HttpServletResponse response, 
                                                 Registry registry) throws Exception {
        ActionForward forward = mapping.findForward(DISPLAY_UPDATE);
        RegistryInfoForm form = (RegistryInfoForm)actionForm;
        if(registry == null) {
            forward = mapping.findForward(DISPLAY_SEARCH_WITH_REGISTRY_NOT_FOUND_MESSAGE);
        } else {
            this.setRegistryInCache(request,registry);
            this.getConversionService().convert(registry,form);
            if(form.getMilitaryServiceNumbersCount() == 0) form.addNewMilitaryServiceNumber();
            if(form instanceof RegistryPHInfoForm) {
                if(((RegistryPHInfoForm)form).getDocumentCount() == 0) ((RegistryPHInfoForm)form).addPHDocument();
            } else if(form instanceof RegistrySHADInfoForm) {
                if(((RegistrySHADInfoForm)form).getDocumentCount() == 0) ((RegistrySHADInfoForm)form).addSHADDocument();
            } else if(form instanceof RegistryPOWInfoForm) {
                if(((RegistryPOWInfoForm)form).getEpisodeCount() == 0) ((RegistryPOWInfoForm)form).addPOWEpisode();
            }
        }
        return forward;
    }
    
    /**
     * Gets the registry from the database. It also saves the retrieved registry in the session.
     * @param request the request object
     * @param registryId the registry id
     * @param registryType the registry type
     * @return
     * @throws ServiceException
     */
    protected Registry getRegistry(HttpServletRequest request, String registryId,String registryType) throws ServiceException {
        Registry registry = null;
        if(StringUtils.isNotEmpty(registryId) && registryType != null) {
            try {
                RegistryType type = (RegistryType)this.getLookupCacheService().getByCodeFromCache(RegistryType.class,registryType);

                EntityKey entityKey = null;
                if(StringUtils.equals(RegistryType.CODE_PH_REGISTRY.getCode(),registryType)) {
                    entityKey = CommonEntityKeyFactory.createPurpleHeartEntityKey(registryId);
                } if(StringUtils.equals(RegistryType.CODE_POW_REGISTRY.getCode(),registryType)) {
                    entityKey = CommonEntityKeyFactory.createPrisonerOfWarEntityKey(registryId);
                } else if(StringUtils.equals(RegistryType.CODE_SHAD_REGISTRY.getCode(),registryType)) {
                    entityKey = CommonEntityKeyFactory.createSHADEntityKey(registryId);
                }
                registry = this.getRegistryService().getRegistryById(entityKey,type);
      
            } catch(ServiceException srvEx) {
                throw srvEx;
            } catch(Exception ex) {
                throw new ServiceException(ex);
            }
        }
        return registry;
    }
    
    /**
     * Sets the registry in the cache.
     * 
     * @param request the request object
     * @param registry the registry object
     * @return
     * @throws ServiceException
     */
    protected synchronized void setRegistryInCache(HttpServletRequest request, Registry registry) throws ServiceException {
        HttpSession session = request.getSession();
        session.removeAttribute(REGISTRY);
        session.setAttribute(REGISTRY,registry);
    }
    
    /**
     * Remove the registry from the cache.
     * 
     * @param request the request object
     * @return
     * @throws ServiceException
     */
    protected synchronized void removeRegistryFromCache(HttpServletRequest request) throws ServiceException {
        HttpSession session = request.getSession();
        session.removeAttribute(REGISTRY);
    }
    
    /**
     * Gets the registry from the cache.
     * 
     * @param request the request object
     * @param registryId the registry id
     * @param registryType the registry type
     * @return
     * @throws ServiceException
     */
    protected Registry getRegistryFromCache(HttpServletRequest request, String registryId,String registryType) {
        Registry registry = getRegistryFromCache(request);
        if(registry != null) {
            String id = (registry.getEntityKey() != null) ? registry.getEntityKey().getKeyValueAsString() : null;
            RegistryType type = (registry.getRegistryTrait() != null) ? registry.getRegistryTrait().getRegistryType() : null;
            if(type != null && StringUtils.equals(id,registryId) && StringUtils.equals(type.getCode(),registryType)) {
                return registry;
            }
        }
        return null;
    }
    
    /**
     * Gets the registry from the cache.
     */
    protected Registry getRegistryFromCache(HttpServletRequest request) {
        return (Registry)request.getSession().getAttribute(REGISTRY);
    }
    
    /*
     * @see gov.va.med.esr.ui.common.action.AbstractAction#handleOptimisticLockException(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    protected ActionForward handleOptimisticLockException(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        addActionMessage(request, OPTIMISTC_LOCK_ERROR_KEY);
        return displayUpdate(mapping,form,request,response);
    }
    
    /**
     * This default implementation calls handlePersonLockedException since it's processing should be the same
     * for when an entity hasn't changed.
     *
     * @param mapping the ActionMapping
     * @param form the ActionForm
     * @param request The request
     * @param response The response
     *
     * @throws Exception If any problems are encountered.
     */
    protected ActionForward handleEntityNotChangedException(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        // Get the no data changed page
        ActionForward forward = mapping.findForward(FWD_REGISTRY_NO_DATA_CHANGED);


        // Get the input page if the oleror page is not specified
        if (forward == null)
        {
            forward = mapping.getInputForward();
        }

        return forward;
    }

    protected Map getKeyMethodMap() 
    {
        if(keyMethodMap == null) {
            keyMethodMap = new HashMap();
        
            keyMethodMap.put("button.display","display");
            keyMethodMap.put("button.registry.displayAdd","displayAdd");
            keyMethodMap.put("button.registry.displayUpdate","displayUpdate");  
            keyMethodMap.put("button.registry.returnFromHistory","returnFromHistory");
            keyMethodMap.put("button.addMilitaryServiceNumber","addMilitaryServiceNumber");
            keyMethodMap.put("button.addDocument","addDocument");
            keyMethodMap.put("button.addPOWEpisode","addPOWEpisode");
            keyMethodMap.put("button.add","add");
            keyMethodMap.put("button.update","update");           
            keyMethodMap.put("button.reset","reset");
            keyMethodMap.put("button.clear","reset");
            keyMethodMap.put("button.cancel", "cancel");    
        }
        return keyMethodMap;
    }
    
    public void afterPropertiesSet() {
        Validate.notNull(this.getConversionService(), "RegistryConversionService cannot be null");
    }
}
