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

import java.util.Date;
import java.util.HashMap;
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.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

import gov.va.med.fw.model.lookup.Lookup;
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.esr.common.model.lookup.Capability;
import gov.va.med.esr.common.model.lookup.FunctionalGroup;
import gov.va.med.esr.common.model.lookup.WkfCaseStatusType;
import gov.va.med.esr.common.model.lookup.WkfCaseType;
import gov.va.med.esr.common.model.person.id.VPIDEntityKeyImpl;

import gov.va.med.esr.service.UnknownLookupCodeException;
import gov.va.med.esr.service.UnknownLookupTypeException;

import gov.va.med.esr.ui.ApplicationConstants;
import gov.va.med.esr.ui.common.beans.WorkflowSearchType;
import gov.va.med.esr.ui.common.util.DateUtils;
import gov.va.med.esr.ui.common.util.EdbStrutsValidator;

public class WorkflowSearchAction extends WorkflowAction {
            
    public static final String MSG_SEARCH_CRITERIA_EMPTY = "error.searchCriteriaEmpty";
    public static final String MSG_SEARCH_TYPE_AND_VALUE_REQUIRED = "error.searchTypeAndValueRequired";
    
    public static final String  MSG_INVALID_FG = "error.invalidFunctionalGroup";
    public static final String  MSG_INAVLID_CASE_TYPE = "error.invalidCaseType";
    public static final String  MSG_INVALID_CASE_STATUS = "error.invalidCaseStatus";
    
    public WorkflowSearchAction () {
        super();
    }
    
    public ActionForward display(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
       //Verify whther we have search results in session if yes display results
       clearCachedResults(request);
       setCurrentTab(request,FWD_SEARCH_RESULTS);
       return mapping.findForward(FWD_DISPLAY);        
    }

    /**
     * Perform simple search
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ActionForward simpleSearch(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {        
       //build search criteria from the user entered data
       WorkflowSearchForm searchForm = (WorkflowSearchForm)form;
       
       //clear cached results
       clearCachedResults(request);
         	
       //Update search fields based on the search type selection
       if (updateSearchFieldsForSimpleSearch(request,searchForm)) {
    	   return advancedSearch(mapping, searchForm, request,response);
       }else {
    	   return mapping.getInputForward();
       }
    }
    
    /**
     * Perform advanced search and retrieve results
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ActionForward advancedSearch(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        WorkflowSearchForm searchForm = (WorkflowSearchForm)form;
        clearCachedResults(request);
        if (!searchForm.isSelectAll() && searchForm.isEmpty()) {
            addActionMessage(request,MSG_SEARCH_CRITERIA_EMPTY);
            return mapping.getInputForward();
        }
        
        ActionForward forward = null;
        
        //TODO validate date ranges if provided 
       //build search criteria from the user entered data              
        try
        {
            // 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)
            {
                // No results were found so generate an error and forward to the
                // failure page
                addActionMessage(request, new ActionMessage(
                    ApplicationConstants.MessageKeys.ERRORS_SEARCH_NORESULT));
                forward = mapping.findForward(FWD_DISPLAY);
            }
            else
            {
                // Backup the ValueListInfo into session and store the resultant ValueList on the request
                ValueListActionUtils
                    .setValueList(request, valueList, WORKFLOW_VALUELIST_REQUEST_KEY);

                // Forward to the search results page.
                forward = mapping.findForward(FWD_RESULTS);
            }
        }
        catch (MaxRecordsExceededValueListException ex)
        {
            // The search exceeded the maximum number of records allowed so generate the appropriate
            // error message.
            if ((ex.getTotalRecords() > 0) && (ex.getRecordLimit() > 0))
            {
                // We know both the total number of records that would have been returned as well
                // as the configured limit.
                addActionMessage(request, new ActionMessage(
                    ApplicationConstants.MessageKeys.ERRORS_MAX_RECORDS_EXCEEDED,
                    new Integer(ex.getTotalRecords()), new Integer(ex
                    .getRecordLimit())));
            }
            else
            {
                // We only know the configured limit
                if (ex.getRecordLimit() > 0)
                {
                    addActionMessage(request, new ActionMessage("error.personSearchExccededLimit",
                        new Integer(ex.getRecordLimit())));
                }
                else
                {
                    // Provide a generic message
                    addActionMessage(request, new ActionMessage(
                        ApplicationConstants.MessageKeys.ERRORS_MAX_RECORDS_EXCEEDED_NO_PARAMS));
                }
            }
            forward = mapping.findForward(FWD_DISPLAY);
        }
        setCurrentTab(request,FWD_SEARCH_RESULTS);
        // Return the forward
        return forward;               
    }
    /**
     * Clear form values
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ActionForward clear(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        form.reset(mapping,request);
       return mapping.findForward(FWD_DISPLAY);        
    }
    /**
     * Fetech and set lookup code value based on the selection type
     * @param searchForm
     */
    protected boolean updateSearchFieldsForSimpleSearch(HttpServletRequest request, WorkflowSearchForm searchForm) throws Exception{    
    	
        String searchField = searchForm.getSearchField();
        String searchValue = searchForm.getSearchValue();

        //search type is required
    	if (StringUtils.isEmpty(searchField)){
            addActionMessage(request,MSG_SEARCH_CRITERIA_EMPTY);
            return false;
    	}
    	//if all items is not selected, value is required
    	else if (!WorkflowSearchType.CODE_ALL_ITEMS.getName().equals(searchField) &&
    		StringUtils.isEmpty(searchValue)){
            addActionMessage(request,MSG_SEARCH_TYPE_AND_VALUE_REQUIRED);
            return false;
    	}
    	//validate dates
        else if (WorkflowSearchType.CODE_ASSIGNED_DATE.getName().equals(searchField) || 
        	WorkflowSearchType.CODE_CREATE_DATE.getName().equals(searchField)){
        	Date date = null;
        	try{
        		date = DateUtils.getDate(searchValue);
        	}catch (Exception e) {}
        	if (date == null) {
        		addActionMessage(request,ApplicationConstants.MessageKeys.ERRORS_DATE,searchValue);
        		return false;
        	}
        }
    		   
    	if (WorkflowSearchType.CODE_ALL_ITEMS.getName().equals(searchField)){
        	searchForm.setSelectAll(true);
        }
        else if (WorkflowSearchType.CODE_FUNCTIONAL_GROUP.getName().equals(searchField)){
			String code = getCode(FunctionalGroup.class,searchValue);
			if (code == null){
				addActionMessage(request,MSG_INVALID_FG,searchValue);
				return false;
			}
			searchForm.setFunctionalGroup(code);
		}    		
        else if (WorkflowSearchType.CODE_ITEM_STATUS.getName().equals(searchField)){
        	String code = getCode(WkfCaseStatusType.class,searchValue);
			if (code == null){
				addActionMessage(request,MSG_INVALID_CASE_STATUS,searchValue);
				return false;
			}
			searchForm.setItemStatus(code);				        
        }
        else if (WorkflowSearchType.CODE_ITEM_TYPE.getName().equals(searchField)){
        	String code = getCode(WkfCaseType.class,searchValue);
			if (code == null){
				addActionMessage(request,MSG_INAVLID_CASE_TYPE,searchValue);
				return false;
			}
        	searchForm.setItemType(code);
        }
        else if (WorkflowSearchType.CODE_ASSIGNED_TO.getName().equals(searchField)){
        	searchForm.setAssignedTo(getUserName(searchValue));
        }
        else if (WorkflowSearchType.CODE_ASSIGNED_DATE.getName().equals(searchField)){
        	searchForm.setAssignedDateFrom(searchValue);
        	searchForm.setAssignedDateTo(searchValue);
        	searchForm.setAssignedItems(true);
        }
        else if (WorkflowSearchType.CODE_CREATE_DATE.getName().equals(searchField)){
        	searchForm.setCreateDateTo(searchValue);
        	searchForm.setCreateDateFrom(searchValue);
        }
        else if (WorkflowSearchType.CODE_SSN.getName().equals(searchField)){
        	if (searchValue.matches(EdbStrutsValidator.PATTERN_SSN) || 
        			searchValue.matches(EdbStrutsValidator.PATTERN_FORMATTED_SSN)) {
        		if (isPermissionGranted(Capability.SEARCH_SSN_ONLY.getCode()))
        		{
        			searchForm.setSsn(searchValue);
        		}
        		else {
        			addActionMessage(request,ApplicationConstants.MessageKeys.ERRORS_CAPABILITY_REQUIRED,"Search By SSN");
                    return false;
        		}
        	}else {
        		addActionMessage(request,ApplicationConstants.MessageKeys.ERRORS_SSN,searchValue);
        		return false;
        	}
        }
        else if (WorkflowSearchType.CODE_VPID.getName().equals(searchField)){
            try {
                String longVPID = VPIDEntityKeyImpl.getLongVPID(searchValue);
                searchForm.setVpid(longVPID);
            }catch (Exception e){
                addActionMessage(request,ApplicationConstants.MessageKeys.ERRORS_VPID,searchValue);
                return false;
            }
        }
    	return true;
    }
    
    protected String getCode(Class clazz, String description) throws Exception{
    	Lookup lookup = null;
    	try {
    			lookup = getLookupService().getByDescription(clazz,description);
    			if (lookup != null) 
    				return lookup.getCode();
		} catch (Exception e) {} 	
        
    	//get the proper code for functional group and set
		try {
				lookup = getLookupCacheService().getByCodeFromCache(clazz,description);
    			if (lookup != null) 
    				return lookup.getCode();		
		} catch (Exception e){}
		return null;
    }
    
    protected String getUserName(String userName) throws Exception{    	
    	Lookup lookup = null;
    	try {
    			lookup = getUserAdminService().getByFullname(userName);
    			if (lookup != null) 
    				return lookup.getCode();
		} catch (UnknownLookupTypeException e) {		
		} catch (UnknownLookupCodeException e) {
		}    			
    			//get the proper code for functional group and set
		try {
				lookup = getUserAdminService().getByCode(userName);
    			if (lookup != null) 
    				return lookup.getCode();
		} catch (UnknownLookupTypeException e) {		
		} catch (UnknownLookupCodeException e) {
		}
		return userName;
    }
    
    protected Map getKeyMethodMap()
    {
        Map map = new HashMap();
        map.put("button.display", "display");
        map.put("button.search", "advancedSearch");
        map.put("button.find", "simpleSearch");
        map.put("button.clear", "clear");
        return map;
    }
}
