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

// Java classes
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

import net.mlw.vlh.ValueList;
import net.mlw.vlh.ValueListInfo;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

import gov.va.med.fw.model.lookup.Lookup;
import gov.va.med.fw.security.UserPrincipal;
import gov.va.med.fw.service.EntityNotChangedException;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.service.ServiceOptimisticLockException;
import gov.va.med.fw.ui.struts.ValueListActionUtils;
import gov.va.med.fw.ui.valuelist.SelectableResult;

import gov.va.med.esr.common.model.cases.WorkflowCase;
import gov.va.med.esr.common.model.lookup.Capability;
import gov.va.med.esr.common.model.lookup.FunctionalGroup;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.security.ESRUserPrincipalImpl;

import gov.va.med.esr.service.WorkflowSearchResultBean;

import gov.va.med.esr.ui.ApplicationConstants;
import gov.va.med.esr.ui.common.action.PersonAbstractAction;

public class WorkflowAction extends PersonAbstractAction
{
    public static final String WORKFLOW_SEARCH_TABLE_ID = "workflowSearchTableId";
    public static final String WORKFLOW_SEARCH_ADAPTER = "workflowSearchAdapter";
    public static final String WORKFLOW_VALUELIST_REQUEST_KEY = "vlhlist";
    public static final String WORKFLOW_ASSIGNED_TO_LIST = "workflowAssignedToList";
    
    public static final String WORKFLOW_CURRENT_TAB = "workflowCurrentTab";
            
    public static String FWD_MY_CASES = "myCases";
    public static String FWD_ASSIGNED_CASES = "assignedCases";
    public static String FWD_UNASSIGNED_CASES = "unassignedCases";
    public static String FWD_OPEN_CASES = "openCases";
    public static String FWD_SEARCH_RESULTS = "searchResults";    
    
    public static final String FWD_DISPLAY = "display";
    public static final String FWD_CLEAR = "clear";
    public static final String FWD_RESULTS= "results";
    public static final String FWD_OVERVIEW = "overview";

    public static String[] WORKLIST_SUPERVISOR_CAPABILITIES = 
        {Capability.TRANSFER_WORK_ITEMS.getName(),
        Capability.ASSIGN_WORK_ITEMS_TO_OTHERS.getName()};
    
    public static String[] WORKLIST_ASSIGN_CAPABILITIES = {
    	Capability.ASSIGN_WORK_ITEMS_TO_SELF.getName(),
    	Capability.TRANSFER_WORK_ITEMS.getName(),
	    Capability.ASSIGN_WORK_ITEMS_TO_OTHERS.getName()};
    
    public WorkflowAction()
    {
        super();
    }

    /**
     * Get Cases assigned to the curent logged in user
     * @param request
     * @throws Exception
     */
    protected void getMyCases(HttpServletRequest request,WorklistForm form) throws Exception {
        UserPrincipal user = getLoggedInUser();
       
        //create new form
        WorkflowSearchForm searchForm = new WorkflowSearchForm(form);
        searchForm.setAssignedTo(user.getName());
        searchForm.setOpenItems(true);
        getCases(request, searchForm);
    }
    /**
     * Get all assigned Cases with in the Functinal Group
     * @param request
     * @throws Exception
     */
    protected void getAssignedCases(HttpServletRequest request,WorklistForm form) throws Exception {
        //create new form
        WorkflowSearchForm searchForm = new WorkflowSearchForm(form);
        searchForm.setAssignedItems(true);
        searchForm.setOpenItems(true);
        FunctionalGroup fg = getFunctionalGroup();        
        searchForm.setFunctionalGroup(fg==null ? FunctionalGroup.EE.getName() : fg.getCode());        
        getCases(request, searchForm);
    }
    /**
     * Get all unassigned cases with in the Functinal Group
     * @param request
     * @throws Exception
     */
    protected void getUnassignedCases(HttpServletRequest request,WorklistForm form) throws Exception {
        WorkflowSearchForm searchForm = new WorkflowSearchForm(form);
        searchForm.setUnassignedItems(true);
        searchForm.setOpenItems(true);
        FunctionalGroup fg = getFunctionalGroup();        
        searchForm.setFunctionalGroup(fg==null ? FunctionalGroup.EE.getName() : fg.getCode());
        getCases(request, searchForm);
    }
    
    /**
     * Get All Open Cases for the current veteran
     * @param request
     * @throws Exception
     */
    protected void getOpenCases(HttpServletRequest request,WorklistForm form) throws Exception {
        //get current veteran (personid)
        Person selectedPerson = (Person)getSandboxEntry(request,
                ApplicationConstants.SessionData.SELECTED_PERSON);
        //we should never come here if veteran is not selected
        if (selectedPerson != null) {            
            WorkflowSearchForm searchForm = new WorkflowSearchForm(form);        
            searchForm.setOpenItems(true);
            searchForm.setPersonId(selectedPerson.getEntityKey().getKeyValueAsString());
            getCases(request, searchForm);            
        }
    }
    
    /**
     * Get Selected Cases from the display list
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     */
    protected List getSelectedCases(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) {
        // Get the value list information
       ValueList valueList = ValueListActionUtils.getSelectableResultValuleList(form,
            request, WORKFLOW_SEARCH_TABLE_ID, WORKFLOW_SEARCH_ADAPTER, null);

        // Backup the ValueListInfo into session and store the resultant ValueList on the request
        //ValueListActionUtils
        //    .setValueList(request, valueList, WORKFLOW_VALUELIST_REQUEST_KEY);

        //Get selectedResults from Session instead of from ValueList, which is a SubList
        List selectedResults = ValueListActionUtils.getSelectedResultsFromPreviousPage(
                    request, WORKFLOW_SEARCH_TABLE_ID, new Boolean(true));

        ArrayList selectedCases = new ArrayList();
        
        // Check if the user selected any items
        if ((selectedResults != null) && (selectedResults.size() > 0)) {
            for (Iterator iterator = selectedResults.iterator(); iterator.hasNext();)
            {
                SelectableResult selectableResult = (SelectableResult)iterator.next();
                WorkflowSearchResultBean workflowSearchResultBean =
                    (WorkflowSearchResultBean)selectableResult.getResult();
                selectedCases.add(workflowSearchResultBean.getWorkflowCaseID());
            }
        }

        // Process the selected entries
        return selectedCases;
    }    
    
    /**
     * Generic Search method to search cases
     * @param request
     * @param searchForm
     */
    protected void getCases(HttpServletRequest request, WorkflowSearchForm searchForm){
        
        // Get the value list information
        ValueList valueList = ValueListActionUtils.getValueList(searchForm,
            request, WORKFLOW_SEARCH_TABLE_ID, WORKFLOW_SEARCH_ADAPTER);

        // Check if any results were found
        ValueListInfo info = valueList.getValueListInfo();
        if (info.getTotalNumberOfEntries() > 0)
        {
            // Backup the ValueListInfo into session and store the resultant ValueList on the request
            ValueListActionUtils
                .setValueList(request, valueList, WORKFLOW_VALUELIST_REQUEST_KEY);
        }        
    }
    
    protected String getCurrentTab(HttpServletRequest request) {
        return (String) request.getSession().getAttribute(WORKFLOW_CURRENT_TAB);
    }
    protected void setCurrentTab(HttpServletRequest request, String tabName) {
        request.getSession().setAttribute(WORKFLOW_CURRENT_TAB, tabName);
    }
    protected void clearCachedResults(HttpServletRequest request) {
    	ValueListActionUtils.clearCachedResults(request.getSession(), WORKFLOW_SEARCH_TABLE_ID);
    }
    protected FunctionalGroup getFunctionalGroup() {
    	ESRUserPrincipalImpl currentUser = (ESRUserPrincipalImpl)getLoggedInUser();
    	return currentUser.getFunctionalGroup();        
    }
    
    /**
     * Update assignedotUserlist based user's Capabilities
     * @param request
     * @throws Exception
     */
    protected void updateAssignedToUserList(HttpServletRequest request) throws Exception{
    	
    	//Refresh the assign to list
    	if (request.getSession().getAttribute(WORKFLOW_ASSIGNED_TO_LIST) != null) {
    		return;
    	}
    	
    	if (isAnyPermissionGranted(WORKLIST_ASSIGN_CAPABILITIES)) {
	    	List users = new ArrayList ();
	    	ESRUserPrincipalImpl currentUser = (ESRUserPrincipalImpl)getLoggedInUser();
	    	FunctionalGroup functionalGroup = currentUser.getFunctionalGroup();
	    	
	    	//Get users from userAdmin service based on the current logged in user's Capabilities
	    	if (functionalGroup != null) {
	    		if (functionalGroup.getCode().equals(FunctionalGroup.EE.getName())) {
		    		//Get all the users from the same functional Group with EE LAS role
    	    		//Assign items to others
    		    	if (isPermissionGranted(Capability.ASSIGN_WORK_ITEMS_TO_OTHERS.getCode())){	    			
    		    		users.addAll(getEEUsers(functionalGroup));
    		    	}
    		    	if (isPermissionGranted(Capability.TRANSFER_WORK_ITEMS.getCode())) {    		    		
    		    		users.addAll(getDQManagers());
    		    	}
	    		}
	    		else if (functionalGroup.getCode().equals(FunctionalGroup.DQ.getName())){
    	    		//Assign to others
    		    	if (isPermissionGranted(Capability.ASSIGN_WORK_ITEMS_TO_OTHERS.getCode())){	    			
    		    		users.addAll(getDQUsers(functionalGroup));
    		    	}
    		    	
    		    	if (isPermissionGranted(Capability.TRANSFER_WORK_ITEMS.getCode())) {
    	    			//get EE Supervisors
    	    			users.addAll(getEEManagers());
    		    	}
	    		}
		    	//Assign to self	
		    	if (isPermissionGranted(Capability.ASSIGN_WORK_ITEMS_TO_SELF.getCode())){
		    		Lookup curUser = getUserAdminService().getByCode(currentUser.getName());
		    		users.add(curUser);
		    	}
	    	}
	    		
	    	//Remove duplicates and sort by user name
	    	Map map = new HashMap ();
	    	List uniqueList = new ArrayList ();
	    	for (Iterator i=users.iterator(); i.hasNext();){
	    		Lookup user = (Lookup) i.next();
	    		if (!map.containsKey(user.getCode())){
	    			map.put(user.getCode(),null);
	    			uniqueList.add(user);
	    		}    		
	    	}
	    	
	    	Collections.sort(uniqueList);	    	
	    	request.getSession().setAttribute(WORKFLOW_ASSIGNED_TO_LIST,uniqueList);
    	}
    	else {
    		request.getSession().setAttribute(WORKFLOW_ASSIGNED_TO_LIST,new ArrayList());
    	}    	
    }
    /**
     * Get DQ Managers and unassigned pool user (dummy)
     * @return
     * @throws Exception
     */
    protected List getDQManagers() throws Exception{
    	List users = new ArrayList ();
		List otherGroupSuprvisors = 
			getUserAdminService().findUsersByRoleName(Capability.DQ_MANAGER.getCode());
		users.addAll(otherGroupSuprvisors);
		
		//create dq unassigned pool user
    	ESRUserPrincipalImpl user = new ESRUserPrincipalImpl(
    			Capability.DQ_UNASSIGNED_POOL.getName()); //userid
        user.setFullName(Capability.DQ_UNASSIGNED_POOL.getName());
        users.add(user);
        return users;
    }
    /**
     * get EE Managers
     * @return
     * @throws Exception
     */
    protected List getEEManagers() throws Exception{
		//get EE Supervisors
		List otherGroupSuprvisors = 
			getUserAdminService().findUsersByRoleName(Capability.EE_SUPERVISOR.getCode());
        List otherGroupManagers = 
            getUserAdminService().findUsersByRoleName(Capability.EE_MANAGER.getCode());
        otherGroupSuprvisors.addAll(otherGroupManagers);
		return otherGroupSuprvisors;
    }
    /**
     * Get EE Users
     * @param functionalGroup
     * @return
     * @throws Exception
     */
    protected List getEEUsers(FunctionalGroup functionalGroup) throws Exception{
    	List users = new ArrayList ();
		List groupUsers = 
			getUserAdminService().findUsersByRoleAndFunctionalGroup(
					functionalGroup, Capability.EE_LAS.getCode());
		users.addAll(groupUsers);
		List groupManagers = 
			getUserAdminService().findUsersByRoleAndFunctionalGroup(
					functionalGroup, Capability.EE_MANAGER.getCode());
		users.addAll(groupManagers);	
		return users;
    }
    
    /**
     * Get DQ Users
     * @param functionalGroup
     * @return
     * @throws Exception
     */
    protected List getDQUsers(FunctionalGroup functionalGroup) throws Exception {
    	List users = new ArrayList ();
		List groupUsers = 
			getUserAdminService().findUsersByRoleAndFunctionalGroup(
					functionalGroup, Capability.DQ_ANALYST.getCode());
		users.addAll(groupUsers);
		List groupManagers = 
			getUserAdminService().findUsersByRoleAndFunctionalGroup(
					functionalGroup, Capability.DQ_MANAGER.getCode());
		users.addAll(groupManagers);
		List groupSpecialists = 
			getUserAdminService().findUsersByRoleAndFunctionalGroup(
					functionalGroup, Capability.DQ_SPECIALIST.getCode());
		users.addAll(groupSpecialists);
		return users;
    }
    
    /**
     * Person is not required for most of the workflow operations
     */
    protected boolean requiresSelectedPerson()
    {
        return false;
    }    
    protected void updateHeader(HttpServletRequest request)
    {
        //updated open cases count of the selected peson is not null
        Person person = getSelectedPerson(request);
        if (person != null) {
            try {
                int caseCount = getWorkflowService().getOpenCasesCount(person.getPersonEntityKey());
                person.setOpenCasesCount(caseCount);
                super.updateHeader(request);
            }catch (ServiceException e){}
        }
    }
    protected void processOptimisticLockException(HttpServletRequest request,
            ServiceOptimisticLockException ex) throws Exception
    {
        // Add the generic error message
        addActionMessage(request,OPTIMISTC_LOCK_ERROR_KEY);
    }
    
    protected void processEntityNotChangedException(HttpServletRequest request, EntityNotChangedException ex) throws Exception
    {
        // Add information message
        addInformationMessage(request, DATA_NOT_CHANGED_MESSAGE_KEY);
    }
    
    public void afterPropertiesSet()
    {
    }
}
