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

//Java imports
import gov.va.med.esr.common.model.comms.BatchRequestFacility;
import gov.va.med.esr.common.model.comms.BatchRequestPriortyGroup;
import gov.va.med.esr.common.model.comms.HandBookBatchRequest;
import gov.va.med.esr.common.model.lookup.EnrollmentPriorityGroup;
import gov.va.med.esr.common.model.lookup.EnrollmentPrioritySubGroup;
import gov.va.med.esr.common.model.lookup.HandBookReleaseControl;
import gov.va.med.esr.common.model.lookup.HandBookRequestStatusType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.PreferredFacility;
import gov.va.med.esr.service.PreferredFacilityService;
import gov.va.med.esr.ui.common.util.DateUtils;
import gov.va.med.esr.ui.conversion.UIConversionServiceImpl;
import gov.va.med.esr.ui.registry.action.RegistryInfoForm;
import gov.va.med.fw.conversion.ConversionServiceException;
import gov.va.med.fw.model.lookup.Lookup;
import gov.va.med.fw.service.ServiceException;
import gov.va.med.fw.util.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 * Conversion service for report actions.
 * 
 *
 * @author Muddaiah Ranga
 * @version 1.0
 */
public class HandBookBatchRequestConversionService extends UIConversionServiceImpl  {

	public static final String ALL = "all";
	public static final String COMMA = ",";
	private PreferredFacilityService preferredFacilityService;
	
	private static final String[][] availablePriorityGroupCodes = { 
		{"1", null},
		{"2", null},
		{"3", null},
		{"4", null},
		{"5", null},
		{"6", null},
		{"7", "1"},
		{"7", "3"},
		{"8", "1"},
		{"8", "2"},
		{"8", "3"},
		{"8", "4"}
	};
	
	private static TreeSet<BatchRequestPriortyGroup> avaialblePriorityGroups = null;
	                                                                                  
	public Object convert(Object source, Class targetClass)
	throws ConversionServiceException {
		return null;
	}

	protected void convertBean(Object source, Object target)
	throws ConversionServiceException {
		// Convert ReportInfoForm to ReportSetup
		if(target instanceof HandBookBatchRequest && source instanceof HandBookBatchRequestForm) {
			this.convertFormToHandBookBatchRequest((HandBookBatchRequestForm)source,(HandBookBatchRequest)target);
		}
	}

	private void convertFormToHandBookBatchRequest( HandBookBatchRequestForm handBookBatchRequestForm,HandBookBatchRequest handBookBatchRequest)
	throws ConversionServiceException {

		handBookBatchRequest.setBatchReleaseDate(DateUtils.getDate(handBookBatchRequestForm.getReleaseDate()));
		//handBookBatchRequest.setHandBookReleaseControl(handBookBatchRequestForm.getReleaseCtl());
		handBookBatchRequest.setMaxPerJobNumber(Integer.toString(handBookBatchRequestForm.getMaxRecord()));
		handBookBatchRequest.setRequestNote(handBookBatchRequestForm.getReleaseNote());

//		Populate priority groups.
//		handBookBatchRequest.removeAllEnrollmentPriorityGroups();
		this.setEnrollmentPriorityGroups(handBookBatchRequestForm.getPriorityGroup(),  handBookBatchRequest);
		//	handBookBatchRequest.removeALLbatchRequestFacility();	
		Set facilities = this.getFacilitiesForSite(handBookBatchRequestForm.getVisnVamc());
		if(facilities !=null && facilities.size()>0){
			this.setFacilities(facilities, handBookBatchRequest);
		}

		String reaseControl=handBookBatchRequestForm.getReleaseCtl();
		HandBookReleaseControl handBookReleaseControl=(HandBookReleaseControl)this.getLookup(HandBookReleaseControl.class, reaseControl);
		handBookBatchRequest.setHandBookReleaseControl(handBookReleaseControl);

		HandBookRequestStatusType statusType=(HandBookRequestStatusType)this.getLookup(HandBookRequestStatusType.class,HandBookRequestStatusType.NEW.getCode());

		handBookBatchRequest.setHandBookRequestStatus(statusType);
		// setting to 0 this will be updated latter.
		handBookBatchRequest.setBatchReleaseSize("0");
	}

	private void setEnrollmentPriorityGroups(String code, HandBookBatchRequest handBookBatchRequest) throws ConversionServiceException {
		
		// CCR#12746 modified original logic, split the logic into two parts
		// first, original logic that creates the priority groups based on original user selections
		BatchRequestPriortyGroup userSelection = getUserSelectedPriorityGroup(code);

		// next, create a list of priority groups such that all priority groups with higher priority are included as well.
		// For example, if PG 4 is selected, then we include 1,2,3 as well.  If user selected multiple priority groups, the 
		// higher numbered PG is used (e.g. if both 3 and 5 were chosen, then we take 5, and then include 1,2,3,4,5).
		// Insert the these PGs into the Batch request priority gorup table as search criteria
		setBatchRequestPriorityGroupCriteria(userSelection, handBookBatchRequest);
	}
	
	private BatchRequestPriortyGroup getUserSelectedPriorityGroup(String code) throws ConversionServiceException {
		
		if(StringUtils.isEmpty(code)) return null;
		
		BatchRequestPriortyGroup userSelection = null;
		
		try {
			
			String[] codes = StringUtils.split(code,COMMA);
			String priorityCode = null;
			String prioritySubCode = null;
		
			priorityCode = codes[0];
			prioritySubCode = (codes.length > 1) ? codes[1] : null;
			
			if(StringUtils.contains(code,ALL)) {
				priorityCode = availablePriorityGroupCodes[availablePriorityGroupCodes.length-1][0];
				prioritySubCode = availablePriorityGroupCodes[availablePriorityGroupCodes.length-1][1];
			}

			EnrollmentPriorityGroup priorityGroupLookup = (EnrollmentPriorityGroup)this.getLookup(EnrollmentPriorityGroup.class,priorityCode);

			if(priorityGroupLookup != null) {
				userSelection = new BatchRequestPriortyGroup();
				userSelection.setPriorityGroup(priorityGroupLookup);
				EnrollmentPrioritySubGroup prioritySubGroupLookup = (EnrollmentPrioritySubGroup)this.getLookup(EnrollmentPrioritySubGroup.class,prioritySubCode);
				if(prioritySubGroupLookup != null) {
					userSelection.setPrioritySubGroup(prioritySubGroupLookup);
				}
			}
		} catch(Exception ex) {
			throw new ConversionServiceException("Error while creating EnrollmentPriorityGroup",ex);
		}
		return userSelection;
	}

	private void setBatchRequestPriorityGroupCriteria(BatchRequestPriortyGroup userSelection, HandBookBatchRequest handBookBatchRequest) 
		throws ConversionServiceException
	{
		// Take all PGs from 1,2... through (including) the user selection (determined from above line) as the priority group criteria				
		Set<BatchRequestPriortyGroup> priorityGroupCriteriaList = getAvaiablePriorityGroups().headSet(userSelection, true);

		// Finally add the evaluated priority groups to the batch request priority group table
		for (BatchRequestPriortyGroup availablePriorityGroupItem : priorityGroupCriteriaList) {
			BatchRequestPriortyGroup batchRequestPriorityGroupRecord = new BatchRequestPriortyGroup();
			batchRequestPriorityGroupRecord.setPriorityGroup(availablePriorityGroupItem.getPriorityGroup());
			if (availablePriorityGroupItem.getPrioritySubGroup() != null) {
				batchRequestPriorityGroupRecord.setPrioritySubGroup(availablePriorityGroupItem.getPrioritySubGroup());
			}
			handBookBatchRequest.addBatchRequestPriortyGroup(batchRequestPriorityGroupRecord);
		}
		
	}
	
	private TreeSet<BatchRequestPriortyGroup> getAvaiablePriorityGroups() throws ConversionServiceException {
		if (avaialblePriorityGroups == null) {
			avaialblePriorityGroups = new TreeSet<BatchRequestPriortyGroup>();
			for (String[] priorityCodes : availablePriorityGroupCodes) {
				BatchRequestPriortyGroup newPriorityGrp = new BatchRequestPriortyGroup();
				newPriorityGrp.setPriorityGroup((EnrollmentPriorityGroup)this.getLookup(EnrollmentPriorityGroup.class,priorityCodes[0]));
				if (priorityCodes[1] != null) {
					newPriorityGrp.setPrioritySubGroup((EnrollmentPrioritySubGroup)this.getLookup(EnrollmentPrioritySubGroup.class,priorityCodes[1]));
				}
				avaialblePriorityGroups.add(newPriorityGrp);
			}
		}
		return avaialblePriorityGroups;
	}
	
	public Lookup getLookup(Class clazz,String code)
	throws ConversionServiceException {
		Lookup lookup = null;
		try {
			if(StringUtils.isNotEmpty(code)) {
				lookup = getLookupCacheService().getByCodeFromCache(clazz,code);
			}
		} catch(Exception ex) {
			StringBuffer buffer = new StringBuffer();
			buffer.append("Error while getting lookup object for ");
			buffer.append(" type = " + clazz.getName());
			buffer.append(" code = " + code);
			throw new ConversionServiceException(buffer.toString(),ex);
		}
		return lookup;
	}
	private void setFacilities(Set siteStats ,HandBookBatchRequest handBookBatchRequest) throws ConversionServiceException {
		for (Iterator iter = siteStats.iterator(); iter.hasNext();) {
			//BatchRequestFacility batchRequestFacility=new BatchRequestFacility();
			VAFacility facility = (VAFacility) iter.next();
			List pfList=new ArrayList();
			pfList.add(facility);
			try{
				Set childSite= getChildFacilities(pfList);
				for (Iterator childIter = childSite.iterator(); childIter.hasNext();) {
					
					BatchRequestFacility batchRequestFacility=new BatchRequestFacility();
					
					VAFacility childVAFacility = (VAFacility) childIter.next();

					batchRequestFacility.setRequestSite(childVAFacility);

					batchRequestFacility.setParentSite(facility);
					handBookBatchRequest.addbatchRequestFacility(batchRequestFacility);
				}
			}
			catch(Exception ex) {
				logger.error("eeror in finding child VA Facilities", ex.getCause());
			}

			//batchRequestFacility.setParentSite(facility);

		//	handBookBatchRequest.addbatchRequestFacility(batchRequestFacility);

		}
	}
	private Set getFacilitiesForSite(String[] code) throws ConversionServiceException {
		Set facilities = null;
		if(code != null && code.length > 0) {
			if(StringUtils.contains(code,ALL)) {
				facilities = new HashSet();
			} else {
				facilities = this.getLookups(VAFacility.class,code);
			}
		}
		return facilities;
	}
	private Set getLookups(Class clazz,String[] code) throws ConversionServiceException {
		Set lookups = null;
		try {
			if(code != null && code.length > 0) {
				if(StringUtils.contains(code,ALL)) {
					lookups  = new HashSet(this.getLookupCacheService().getFromCache(clazz.getName()));
				} else {
					lookups = new HashSet();
					Lookup lookup = null;
					for(int i=0; i<code.length; i++) {
						lookup = this.getLookup(clazz,code[i]);
						if(lookup != null) lookups.add(this.getLookup(clazz,code[i]));
					}
				}
			}
		} catch(Exception ex) {
			throw new ConversionServiceException("Error while getting lookup object for type = " + clazz.getName() + " code = " + code,ex);
		}
		return lookups;
	}

	private Lookup getLookupByName(Class clazz,String name)
	throws ConversionServiceException {
		Lookup lookup = null;
		try {
			if(StringUtils.isNotEmpty(name)) {
				lookup = this.getLookupCacheService().getLookupService().getByName(clazz,name);
			}
		} catch(Exception ex) {
			StringBuffer buffer = new StringBuffer();
			buffer.append("Error while getting lookup object for ");
			buffer.append(" type = " + clazz.getName());
			buffer.append(" name = " + name);
			throw new ConversionServiceException(buffer.toString(),ex);
		}
		return lookup;
	}

	private Integer getInteger(String value) {
		return StringUtils.isNotEmpty(value) ? new Integer(value) : null;
	}

	private boolean getTrueFalse(String flag) {
		return StringUtils.equals(flag,RegistryInfoForm.Y) ? true : false;
	}

	protected static void setPrivateFieldData(Object obj,Class clazz, String methodName, Object data) {
		try {
			final Method[] methods = clazz.getDeclaredMethods();

			for (int i=0; i<methods.length; i++) {
				if (methods[i].getName().equals(methodName)) {
					final Object params[] = new Object[1];
					params[0] = data;
					methods[i].setAccessible(true);
					methods[i].invoke(obj,params);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String[] merge(String[] setOne, String[] SetTwo){
		Set newSet = new HashSet();

		if (setOne != null && setOne.length > 0){
			for (int i=0; i<setOne.length; i++){
				newSet.add(setOne[i]);
			}
		}

		if (SetTwo != null && SetTwo.length > 0){
			for (int i=0; i<SetTwo.length; i++){
				newSet.add(SetTwo[i]);
			}
		}

		return getStringArrayFromSet(newSet);
	}

	private String[] getStringArrayFromSet(Set set) {
		if(set == null || set.isEmpty()) return null;
		String[] code = new String[set.size()];
		int i = 0;
		for(Iterator iter=set.iterator(); iter.hasNext();) {
			String string = (String)iter.next();
			if(StringUtils.isNotEmpty(string)) {
				code[i] = string;
				i = i + 1;
			}
		}
		return code;
	}
	public Set getChildFacilities(List pfList) throws ServiceException {
		Set childFacilities = new HashSet();
		PreferredFacility pf = null;
		List siteList=null;
		while(pfList.size()>0){
		for (Iterator iter = pfList.iterator(); iter.hasNext();) {
				siteList= new ArrayList();
				VAFacility facility = (VAFacility) iter.next();
				childFacilities.add(facility);
				siteList.add(facility.getIdentifier());
				//pfList=preferredFacilityService.getChildVAFacility(siteList);
				
			}
		pfList=preferredFacilityService.getChildVAFacility(siteList);
	}

		return childFacilities;
	}

	public PreferredFacilityService getPreferredFacilityService() {
		return preferredFacilityService;
	}

	public void setPreferredFacilityService(
			PreferredFacilityService preferredFacilityService) {
		this.preferredFacilityService = preferredFacilityService;
	}
}