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


import gov.va.med.esr.common.model.lookup.EEServiceField;
import gov.va.med.esr.common.model.lookup.EEServiceFieldLite;
import gov.va.med.esr.common.model.lookup.EEServiceGroup;
import gov.va.med.esr.common.model.security.EEServiceRequest;
import gov.va.med.esr.common.model.security.EEServiceRequestField;
import gov.va.med.esr.common.model.security.EEServiceRequestLite;
import gov.va.med.esr.ui.ApplicationConstants.MessageKeys;
import gov.va.med.esr.ui.common.action.AbstractAction;
import gov.va.med.esr.ui.util.TreeNodeSelectListener;
import gov.va.med.esr.ui.util.TreeNodeUnSelectListener;
import gov.va.med.fw.model.EntityKey;
import gov.va.med.fw.model.EntityKeyFactory;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

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

import com.jenkov.prizetags.tree.impl.Tree;
import com.jenkov.prizetags.tree.impl.TreeNode;
import com.jenkov.prizetags.tree.impl.TreeUpdater;
import com.jenkov.prizetags.tree.itf.ITree;
import com.jenkov.prizetags.tree.itf.ITreeNode;



public class ServiceRequestAction extends AbstractAction{

	public static final String GROUP_TYPE = "GROUP";
	public static final String FIELD_TYPE = "FIELD";
	public static final String FORWARD_DISPLAY_EDIT = "displayEdit";
	public static final String FORWARD_DISPLAY_NEW = "displayNew";
	
	public static final String FORWARD_DISPLAY_LIST_SUCCESS = "listsuccess";
	
	public static final String REQUIRED = MessageKeys.ERRORS_REQUIRED;
	public static final String LABEL_KEY_REQNAME = "label.eeServiceRequest.header.name";
	public static final String LABEL_KEY_REQDESC = "label.eeServiceRequest.header.description";		
	public static final String FIELD_UNIQUE="error.uniquename";
	
	public static final String FIELD_REQ_NAME = "Request Name";
	public static final String FIELD_REQ_DESC = "Description";
	
	public static final String REQUEST_SAVED="message.request.saved";
	
	public static final String ROOT_GROUP = "eeSummary";
	
    public ActionForward list(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception
    {
    	List serviceRequests = getEeServiceAdminService().getEEServiceLiteRequests();
		if(serviceRequests != null && !serviceRequests.isEmpty())
			request.setAttribute("serviceRequests", serviceRequests);
		
        return mapping.findForward(FORWARD_DISPLAY_LIST_SUCCESS);
    }
    
    public ActionForward CancelSave(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return list(mapping, form, request, response); 
     } 

    public ActionForward displayNew(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    	ServiceRequestForm serviceRequestForm = (ServiceRequestForm) form;

    	
    	
    	serviceRequestForm.reset();
    	
    	EEServiceRequestLite  serviceRequest = new EEServiceRequestLite();
    	ITree tree = createTreeFromServiceRequest(serviceRequest);
    	// now convert the ServiceFields to iTree format.
    	
    	TreeUpdater treeUpdater = new TreeUpdater(request, tree );
    	treeUpdater.update();

    	request.getSession(true).setAttribute("tree.model", tree);
    	
    	
    	return mapping.findForward(FORWARD_DISPLAY_NEW);
    }   
    
    
    public ActionForward display(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    	ServiceRequestForm serviceRequestForm = (ServiceRequestForm) form;
    	String requestId = serviceRequestForm.getRequestId();
    	EntityKey key = EntityKeyFactory.createEntityKey(requestId, EEServiceRequest.class);
    	EEServiceRequestLite serviceRequest = getEeServiceAdminService().getEEserviceRequestLite(key);
    	
    	serviceRequestForm.setName(serviceRequest.getName());
    	serviceRequestForm.setDescription(serviceRequest.getDescription());

    	ITree tree = createTreeFromServiceRequest(serviceRequest);
    	// now convert the ServiceFields to iTree format.
    	
    	TreeUpdater treeUpdater = new TreeUpdater(request, tree );
    	treeUpdater.update();

    	request.getSession(true).setAttribute("tree.model", tree);
    	
    	
    	return mapping.findForward(FORWARD_DISPLAY_EDIT);
    }
    
    
    
    public ActionForward refreshTree(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    		//validateForm(mapping, form, request, response);
	    	ITree tree = (ITree) request.getSession(true).getAttribute("tree.model");
	    	TreeUpdater treeUpdater = new TreeUpdater(request, tree );
	    	treeUpdater.update();
	    	
	    	/**
	    	 * pass the form back to the view. 
	    	 */
	    	request.setAttribute("serviceRequestForm", form);
	    	
    		//just take it back to the page.
            return mapping.findForward(FORWARD_DISPLAY_EDIT);
        }

    
    public ActionForward reset(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    	
    	ServiceRequestForm serviceRequestForm = (ServiceRequestForm) form;
    	
    	String requestId = serviceRequestForm.getRequestId();
    	
    	if ( requestId == null ||requestId.trim().length() <= 0 ) {
    		// new request so go to newRequest page.
    		return displayNew(mapping, form, request, response);
    	}
    	else
    	{
    		return display(mapping, form, request, response);
    		
    	}
    	
    }
    
    public ActionForward saveRequest(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    	boolean isFormValid = validateForm(mapping, form, request, response);
    	
    	ServiceRequestForm serviceRequestForm = (ServiceRequestForm) form;

    	
    	if ( serviceRequestForm.getName() != null )
    	{
    		EEServiceRequestLite eeRequestOther = getEeServiceAdminService().getEEServicerequestLiteByName(serviceRequestForm.getName());
    		
    		if ( eeRequestOther != null )
    		{
    			if ( serviceRequestForm.getRequestId() != null ){
	    			if (!eeRequestOther.getIdentifier().toString().equals(serviceRequestForm.getRequestId())) {
	    				addActionMessageForField(request,FIELD_UNIQUE,FIELD_REQ_NAME);
	    				isFormValid = false;
	    			}
    			} else {
    				addActionMessageForField(request,FIELD_UNIQUE,FIELD_REQ_NAME);
    				isFormValid = false;
    				
    			}
    			
    		}
    	}
    	
    	if ( ! isFormValid ) {
    		return mapping.findForward(FORWARD_DISPLAY_EDIT);
    	}
    	
    	String requestId = serviceRequestForm.getRequestId();
    	
    	EEServiceRequest eeRequest = null;
    	if ( requestId != null && requestId.trim().length() > 0 ) {
    		EntityKey key = EntityKeyFactory.createEntityKey(serviceRequestForm.getRequestId(), EEServiceRequest.class);
    		eeRequest = getEeServiceAdminService().getEEserviceRequest(key);
    	}else {
    		eeRequest = new EEServiceRequest();
    	}
    	
    	eeRequest.setName(serviceRequestForm.getName().trim());
    	eeRequest.setDescription(serviceRequestForm.getDescription().trim());
    	
    	ITree tree = (ITree) request.getSession(true).getAttribute("tree.model");
    	
    	Set selectedNodes = tree.getSelectedNodes();

    	/**
    	 * Create the set of selected fields.
    	 */
    	Set newFields = new HashSet();
    	if ( selectedNodes != null && selectedNodes.size() > 0 ) {
    		Iterator nodeItr = selectedNodes.iterator();
    		
    		while (nodeItr.hasNext())
    		{
    			ITreeNode node = (ITreeNode) nodeItr.next();
    			if ( node.getType().equals(FIELD_TYPE)) {
    				EEServiceRequestField reqField = new EEServiceRequestField();
    				
    				EEServiceFieldLite field = (EEServiceFieldLite)getLookupCacheService().getByCodeFromCache(EEServiceFieldLite.class, node.getName());
    				reqField.setEeServiceField(field);
    				newFields.add(reqField);
    			}
    		}
    		
    	}
    		
    	/**
    	 * remove the existing fields if they are not in the new selection.
    	 */
    	Set existingFields = eeRequest.getEeServiceFields();
    	
    	Set removeFields = new HashSet();
    	if (existingFields != null && existingFields.size() > 0 ) {
    		Iterator existingFieldsitr = existingFields.iterator();
    		while (existingFieldsitr.hasNext()) {
    			EEServiceRequestField existingReqField = (EEServiceRequestField) existingFieldsitr.next();
    			if ( ! newFields.contains(existingReqField)) {
    				//eeRequest.removeField(existingReqField);
    				removeFields.add(existingReqField);
    			}
    		}
    	}
    	eeRequest.removeFields(removeFields);
    	
    	
    	/**
    	 * Add all the selected fields to the list. This way we are not changing the 
    	 * already selected field.
    	 */
    	if (newFields != null && newFields.size() > 0 ) {
    		Iterator newFieldsitr = newFields.iterator();
    		while (newFieldsitr.hasNext()) {
    			EEServiceRequestField newField = (EEServiceRequestField) newFieldsitr.next();
    				eeRequest.addField(newField);
    		}
    	}
    	
    	
    	getEeServiceAdminService().saveEEServiceRequest(eeRequest);
    	addInformationMessage(request,REQUEST_SAVED);
    	return list(mapping, form, request, response);
    }
   
    
    private boolean validateForm(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
    	ServiceRequestForm serviceRequestForm = (ServiceRequestForm) form;
    	
    	boolean valid = true;
    	if ( serviceRequestForm.getName() == null || serviceRequestForm.getName().length() <= 0 ) {
    		addActionMessage(request,REQUIRED,FIELD_REQ_NAME );
    		valid = false;
    	}

    	if ( serviceRequestForm.getDescription() == null || serviceRequestForm.getDescription().length() <= 0 ) {
    		addActionMessage(request,REQUIRED,FIELD_REQ_DESC);
    		valid = false;
    	}
    	return valid;
    }
    
    private ITree createTreeFromServiceRequest(EEServiceRequestLite serviceRequest)
    				throws  Exception	{
    	EEServiceGroup rootGroup =  (EEServiceGroup)getLookupCacheService().getByCodeFromCache(EEServiceGroup.class, ROOT_GROUP);
    	Set selectedFields = new HashSet();
    	if ( serviceRequest.getEntityKey() != null ) {
    		selectedFields = getEeServiceAdminService().getEEServiceRequestFieldsByRequest(serviceRequest.getEntityKey());
    	}

    	ITree tree = new Tree();
    	ITreeNode root = new TreeNode(rootGroup.getCode() , rootGroup.getCode() , GROUP_TYPE);
    	root.setToolTip(rootGroup.getDescription());
    	tree.setRoot(root);
    	
    	boolean allGroupsSelected = addChildGroups(rootGroup.getChildGroups(), root, selectedFields, tree);
    	boolean allFieldsSelected =  addFields(rootGroup.getFields(), root, selectedFields, tree);
    	
    	if ( allGroupsSelected && allFieldsSelected)
    	{
    		tree.select(root.getId());
    	}
    	
    	tree.addSelectListener(new TreeNodeSelectListener());
    	tree.addUnSelectListener(new TreeNodeUnSelectListener());
    	return tree;
    }
    
    private boolean addFields(Set fields, ITreeNode treeNode, Set selectedFields, ITree tree ) {
    	if ( fields == null ) return true;
    	
    	Iterator itr = fields.iterator();
    	
    	boolean allSelected = true;
    	
    	while ( itr != null && itr.hasNext())
    	{
    		EEServiceField serviceField = (EEServiceField) itr.next();
    		ITreeNode fieldNode = new TreeNode(serviceField.getCode(),serviceField.getCode(),FIELD_TYPE );
    		fieldNode.setToolTip(serviceField.getDescription());
    		treeNode.addChild(fieldNode);
    		
    		if ( selectedFields != null )
    		{
    			//If this field is selected then mark it as selected
    			if ( selectedFields.contains(serviceField.getCode())) {
    				tree.select(fieldNode.getId());
    			}
    			else
    			{
    				allSelected = false;
    			}
    		}
    		
    		
    	}
    	return allSelected;
    }
    
    private boolean addChildGroups(Set childGroups, ITreeNode treeNode, Set selectedFields, ITree tree) {
    	
    	if (childGroups == null  )  return true;
    	
    	Iterator itr = childGroups.iterator();
    	
    	boolean allSelected = true;
    	
    	while (itr != null && itr.hasNext()) {
    		EEServiceGroup childGroup = (EEServiceGroup)itr.next();
    		ITreeNode childGroupNode = new TreeNode(childGroup.getCode(),childGroup.getCode(),GROUP_TYPE );
    		
    		childGroupNode.setToolTip(childGroup.getDescription());
    		
    		boolean fieldsSlected = addFields(childGroup.getFields(), childGroupNode,selectedFields, tree);
    		boolean groupsSlected = addChildGroups(childGroup.getChildGroups(), childGroupNode,selectedFields, tree);
    		
    		// If all the fields and groups in this field are selected and at least one of group list or field list idnot empty 
    		// then mark this group as selected. 
    		if (fieldsSlected && groupsSlected && (
    				childGroup.getChildGroups() != null && childGroup.getChildGroups().size() > 0 ||
    				childGroup.getFields() != null && childGroup.getFields().size() > 0 )
    				)	{
    			tree.select(childGroupNode.getId());
    		}
    		
    		if ( fieldsSlected == false || groupsSlected == false) {
    			allSelected = false;
    		}
    		
    		
    		treeNode.addChild(childGroupNode);
    	}
    	
    	
    	return allSelected;
    }
    
    
	/**
	 * 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.eeservicerequest.save", "saveRequest");
		map.put("button.eeservicerequest.add", "saveRequest");
		map.put("button.eeservicerequest.update", "saveRequest");
		map.put("button.eeservicerequest.Cancel", "CancelSave");
		map.put("button.eeservicerequest.list", "list");
		map.put("button.eeservicerequest.display", "display");
		map.put("button.eeservicerequest.displayNew", "displayNew");
		map.put("button.eeservicerequest.refreshTree", "refreshTree");
		map.put("button.eeservicerequest.reset", "reset");
		return map;
	}

    
    public void afterPropertiesSet() throws Exception
    {
        // Nothing to do        
    }
}
