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

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

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 gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.model.EntityKeyFactory;

import gov.va.med.esr.common.model.security.CapabilitySet;
import gov.va.med.esr.common.model.security.ESRRolePrincipalImpl;

import gov.va.med.esr.ui.common.beans.FieldHistoryInfo;
import gov.va.med.esr.ui.common.util.DateUtils;

public class CapabilitySetsAction extends AbstractUserProfileAction {
    
    public static final String FWD_DISPLAY_SETS = "displaySets";
    public static final String FWD_EDIT = "editSet";
    public static final String FWD_CONFIRM = "confirm";
    public static final String PAR_CAPABILITY_SET_ID = "capabilitySetId";
    public static final String ATTR_CAPABILITY_SETS = "CapabilitySets";
    public static final String ATTR_DELETED_CAPABILITY_SETS = "DeletedCapabilitySets";
    
    public static final String MSG_SET_NAME_DUPLICATE = "error.capabilitySetNameDuplicate";
    public static final String MSG_SET_REQUIRES_TWO = "error.capabilitySetrequiresTwoCapabilities";
    public static final String FIELD_NAME = "name";
    public static final String MSG_ASSIGNED_CAN_NOT_BE_DELETED = "error.capabilitySetisAssigned";
    public static final String MSG_ACTIVE_DATE_INVALID = "error.activeDate";
    public static final String FLD_ACTIVE_DATE = "activeDate";
    public static final String FLD_INACTIVE_DATE = "inactiveDate";
    
    public CapabilitySetsAction() {
        super();
    }
    /**
     * Display all capability sets
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ActionForward display(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        clearSessionData(request);
        List allCapabilitySets= getUserAdminService().getAllCapabilitySets();
        //sort the capabilities by name
        Collections.sort(allCapabilitySets);
        List deletedSets= getUserAdminService().findDeletedCapabilitySets();
        Collections.sort(deletedSets);                
        request.setAttribute(ATTR_CAPABILITY_SETS,allCapabilitySets);
        request.setAttribute(ATTR_DELETED_CAPABILITY_SETS,deletedSets);        
        return mapping.findForward(FWD_DISPLAY_SETS);
    }

    /**
     * Add new Capability Set
     */
    public ActionForward addNew(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //we don't need to reset the form as it is request scoped        
        CapabilitySetForm setForm = (CapabilitySetForm) form;
        setForm.setAvailableCapabilities(getUserAdminService().getAllCapabilities());
        return mapping.findForward(FWD_EDIT);
    }
    
    /**
     * Edit an existing Capability Set
     */
    public ActionForward edit(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //we don't need to reset the form as it is request scoped        
        String setId = request.getParameter(PAR_CAPABILITY_SET_ID);
        Validate.notNull(setId,"Capability Set Id can not be null");
        
        //Create Entity Key
        EntityKey entityKey = EntityKeyFactory.createEntityKey(new BigDecimal(setId), CapabilitySet.class);

        //Get Admin service and Retrieve the Capability Set
        CapabilitySet capabilitySet = getUserAdminService().getCapabilitySetById(entityKey);
        
        //place the pristine entity in the session
        setPristineEntity(request,capabilitySet);

        //Convert the set to from and frward to edit screen
        conversionService.convert(capabilitySet,form);
        
        return mapping.findForward(FWD_EDIT);
    }    
    
    public ActionForward add(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //Validate name for uniqueness
        String setName = ((CapabilitySetForm)form).getName().trim();
        if (getUserAdminService().getCapabilitySetByName(setName) != null) {
            addActionMessageForField(request,MSG_SET_NAME_DUPLICATE,FIELD_NAME);
            return mapping.getInputForward();
        }
        
        CapabilitySet newSet = new CapabilitySet();
        
        //convert from from to set
        conversionService.convert(form,newSet);
        setPristineEntity(request,null);
        setUpdatedEntity(request,newSet);
        
        //Check for Minimum number of required capabilities
        if (isValid(request,newSet)) {
            //Forward to confirmation page
            return confirmation(mapping,form,request,response);   
        }
        return mapping.getInputForward();     
    }
    
    public ActionForward delete(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //we don't need to reset the form as it is request scoped        
        String setId = request.getParameter(PAR_CAPABILITY_SET_ID);
        Validate.notNull(setId,"Capability Set Id can not be null");
        
        //Create Entity key from Id and get CapabilitySet from admin service
        EntityKey entityKey = EntityKeyFactory.createEntityKey(new BigDecimal(setId), CapabilitySet.class);
        CapabilitySet capabilitySet = getUserAdminService().getCapabilitySetById(entityKey);

        //Verify that Capability set is not assigned to any user
        if (Boolean.TRUE.equals(capabilitySet.isAssigned())) {
            //Set error message that it cann't be deleted
            addActionMessage(request,MSG_ASSIGNED_CAN_NOT_BE_DELETED);
            return mapping.getInputForward();            
        }
        else {
            getUserAdminService().deleteCapabilitySet(capabilitySet);
            return mapping.findForward(FWD_DISPLAY_DELETE_MSG);
        }
    }
    
    public ActionForward update(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //validate from
        CapabilitySetForm setForm = (CapabilitySetForm) form;
       
        CapabilitySet pristine = (CapabilitySet) getPristineEntity(request);
        CapabilitySet updated = (CapabilitySet) pristine.clone();
        
        //convert
        conversionService.convert(setForm, updated);
        setUpdatedEntity(request,updated);
        
        //Check for Minimum number of required capabilities
        if (isValid(request,updated)) {
            //Forward to confirmation page
            return confirmation(mapping,form,request,response);   
        }
        return mapping.getInputForward();        
    }

    public ActionForward accept(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //Get the updated capability set from the session
        CapabilitySet capabilitySet = (CapabilitySet)getUpdatedEntity(request);
        
        if (capabilitySet.getEntityKey() == null ) {
            //add
            getUserAdminService().addCapabilitySet(capabilitySet);
            return mapping.findForward(FWD_DISPLAY_ADD_MSG);
        }
        else {
            //update
            getUserAdminService().updateCapabilitySet(capabilitySet);
            return mapping.findForward(FWD_DISPLAY_UPDATE_MSG);
        }
    }
    
    public ActionForward revise(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //Retrive the capability set from the session and forward to edit screen
        CapabilitySet capabilitySet = (CapabilitySet)getUpdatedEntity(request);        
        conversionService.convert(capabilitySet,form);           
        return mapping.findForward(FWD_EDIT);
    }

    public ActionForward discard(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        //return the display list discarding all changes     
        return mapping.findForward(FWD_DISPLAY_SETS);
    }
        
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
    }
    
    protected ActionForward confirmation(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) {
        //convert to confirmation properties
        CapabilitySet pristine = (CapabilitySet) getPristineEntity(request);
        CapabilitySet current = (CapabilitySet) getUpdatedEntity(request);
                
        List propList = new ArrayList ();
        
        //User Attributes (name) and Functional Group
        propList.add(new FieldHistoryInfo("label.name",            
            (current == null ? "" : current.getName()),
            (pristine == null ? "" : pristine.getName())));
        propList.add(new FieldHistoryInfo("label.description",            
                (current == null ? "" : current.getDescription()),
                (pristine == null ? "" : pristine.getDescription())));        

        propList.add(new FieldHistoryInfo("label.activeDate",
            (current == null ? "" : DateUtils.format(current.getActiveDate(),null)),
            (pristine == null ? "" : DateUtils.format(pristine.getActiveDate(),null))));
            
        propList.add(new FieldHistoryInfo("label.inactivedate",
           (current == null ? "" : DateUtils.format(current.getInactiveDate(),null)),
           (pristine == null ? "" : DateUtils.format(pristine.getInactiveDate(),null)))); 

        List list = matchSets(current.getCapabilities(),
                pristine == null ? null : pristine.getCapabilities());
        propList.addAll(processCapabilities(list));        
        
        //setForm.setCapabilityChangeList(orderedList);
        //Set attributes on the request for action,title and mode
        request.setAttribute("changeList",propList);
        request.setAttribute("confirmationActionName","editCapabilitySet");
        request.setAttribute("confirmationEntityId",
                pristine == null ? "" : pristine.getEntityKey().getKeyValueAsString());       
        if (pristine == null) {
            request.setAttribute("confirmationTitle","label.addCapabilitySet");
        }
        else {
            request.setAttribute("confirmationTitle","label.editCapabilitySet");
        }
        
        return mapping.findForward(FWD_CONFIRM);
    }
    
    private boolean isValid(HttpServletRequest request, CapabilitySet set) {
        boolean valid = true;
        //Therer should be atleast two capabilities in the set
        if (set.getCapabilities().size() < 2) {
            addActionMessage(request,MSG_SET_REQUIRES_TWO);
            valid = false;
        }
        Date current = DateUtils.getCurrentDate();
        Date prevActiveDate = null;
        Date prevInactiveDate = null;
        if (set.getEntityKey() != null) {
        	CapabilitySet pristine = (CapabilitySet) getPristineEntity(request);
        	prevActiveDate = pristine.getActiveDate();
        	prevInactiveDate = pristine.getInactiveDate();
        }
        //date is not null and is different from previous value
        if (set.getActiveDate() != null && !set.getActiveDate().equals(prevActiveDate)) {        	
            if (set.getActiveDate().before(current)){
            	valid = false;
            	addActionMessageForField(request,ERRORS_ACTIVE_DATE_PAST,FLD_ACTIVE_DATE);   
            }
        }
        //date is not null and is different from previous value
        if (set.getInactiveDate() != null && !set.getInactiveDate().equals(prevInactiveDate)) { 
            if (set.getInactiveDate().before(current)){
            	valid = false;
            	addActionMessageForField(request,ERRORS_INACTIVE_DATE_PAST,FLD_INACTIVE_DATE);  
            }
        }        
        
        //active date should be before the inactive date
        if (set.getActiveDate() != null && set.getInactiveDate() != null &&
            set.getActiveDate().after(set.getInactiveDate())) {
            valid = false;
            addActionMessageForField(request,MSG_ACTIVE_DATE_INVALID,FLD_ACTIVE_DATE);
            addActionMessageForField(request,MSG_ACTIVE_DATE_INVALID,FLD_INACTIVE_DATE);                        
        }

        return valid;
    }
    protected Map getKeyMethodMap()
    {
        Map map = new HashMap();
        map.put("button.display", "display");
        map.put("button.add", "add");
        map.put("button.update", "update");
        map.put("button.delete", "delete");
        map.put("button.cancel", "discard");
        map.put("button.addCapabilitySet", "addNew");
        map.put("button.edit", "edit");
        map.put("button.revise", "revise");
        map.put("button.discardChanges", "discard");
        map.put("button.acceptChanges", "accept"); 
        map.put("button.returnToEdit", "returnToEdit");
        return map;
    }    
}
