package gov.va.med.esr.webservices.client.vadir;

import gov.va.schema.militaryhistory.Activation;
import gov.va.schema.militaryhistory.BIRLS;
import gov.va.schema.militaryhistory.Deployment;
import gov.va.schema.militaryhistory.MilitaryHistory;
import gov.va.schema.militaryhistory.MilitaryPay;
import gov.va.schema.militaryhistory.PeriodOfService;
import gov.va.schema.militaryhistory.ServicePeriod;
import gov.va.schema.militaryhistory.VADIR;
import gov.va.schema.militaryhistoryservice.GetMilitaryHistory;
import gov.va.schema.militaryhistoryservice.GetMilitaryHistoryResponse;
import gov.va.schema.militaryhistoryservice.SearchCriteria;
import gov.va.viers.cdi.emis.commonservice.v1.CombatPayData;
import gov.va.viers.cdi.emis.commonservice.v1.DeploymentData;
import gov.va.viers.cdi.emis.commonservice.v1.DeploymentEligibilityData;
import gov.va.viers.cdi.emis.commonservice.v1.DeploymentLocationEligibilityData;
import gov.va.viers.cdi.emis.commonservice.v1.GuardReserveServicePeriodsEligibilityData;
import gov.va.viers.cdi.emis.commonservice.v1.KeyData;
import gov.va.viers.cdi.emis.commonservice.v1.MilitaryServiceEpisodeEligibilityData;
import gov.va.viers.cdi.emis.commonservice.v1.PurpleHeartOrMohData;
import emismilitaryinformationserivce.*;

import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import org.apache.log4j.Logger;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

/**
 * Client for JAX-WS eMIS Military Information Web Service.
 * 
 * @author DNS   surves
 */
@Component
public class EMISMilitaryInformationServiceClient {

    private static final QName SERVICE_NAME = new QName("urn:eMISMilitaryInformationSerivce", "eMISMilitaryInformationSerivcePortTypes");
    private static final Logger logger = Logger.getLogger(EMISMilitaryInformationServiceClient.class);
    public static final String EDIPI = "edipi";
    public static final String DISABILITY_PERM_TEMP_IND = "TEMP"; 
    public static final String PURPLE_HEART_CODE = "P"; 
    public static final String MEDAL_OF_HONOR_CODE = "M"; 
    public static final String YES_INDICATOR = "Y";
    public static final String NO_INDICATOR = "N";
    public static final String ICN_DELIMITER = "^";
    public static final String OEFOIF_CONFLICT_SYNADID_IND = "03";
    public static final String OEF_IND = "01";
    public static final String OIF_IND = "02";
    public static final String NINEGF = "9GF";
    public static final String UNK_OEFOIF_LOCATION = "Unkown OEF/OIF";
    
    static JAXBContext jaxbContext;
	static Marshaller jaxbMarshaller;
    static JAXBContext jaxbContextResp;
    static Marshaller jaxbMarshallerResp;
    static final HashMap<String, Boolean> GuardReserveStatuteCodes = new HashMap<String, Boolean> (){{
        put("A", false);
        put("B", false);
        put("C", false);
        put("D", false);
        put("E", false);
        put("F", true);  
        put("G", true);
        put("H", true);
        put("I", false);
        put("J", true);
        put("K", false);
        put("L", true);  
        put("M", false);
        put("N", true);
        put("O", false);
        put("P", true);
        put("Q", true);
        put("R", false);  
        put("S", false);
        put("T", false);
        put("U", false);
        put("V", false);
        put("X", false);
        put("Y", false); 
        put("Z", true);
    }};
    
    private String emisWsdlUrl;
    
    public EMISMilitaryInformationServiceClient() {
    	try {
	    	jaxbContext = JAXBContext.newInstance(GetMilitaryHistory.class);
	    	jaxbMarshaller = jaxbContext.createMarshaller();
	    	jaxbContextResp = JAXBContext.newInstance(GetMilitaryHistoryResponse.class);
	    	jaxbMarshallerResp = jaxbContextResp.createMarshaller();
    	} catch (JAXBException e) {
			log("Error occured in setting up JAXB context "+ e.getMessage());
	      }	
    }

    public void setEmisWsdlUrl(String wsdlURL) {
    	emisWsdlUrl = wsdlURL;
    }
    public String getEmisWsdlUrl() {
    	return emisWsdlUrl;
    }    
    public GetMilitaryHistoryResponse getMilitaryHistory(GetMilitaryHistory request) {
    	log("Inside getMilitaryHistory");
        URL wsdlURL = EMISMilitaryInformationSerivcePortTypes_Service.WSDL_LOCATION;

        try {        
        	String wsdlUrl = getEmisWsdlUrl();
        	logger.debug("eMISWsdlUrl="+wsdlUrl);
        	if (StringUtils.isNotEmpty(wsdlUrl)) {
        		wsdlURL = new URL(wsdlUrl);
        	}
        } catch(MalformedURLException e) {
        	e.printStackTrace();
        	logger.error("Error occured in loading eMIS wsdl URL "+e.getMessage());
        	return null;
        }
        
        GetMilitaryHistoryResponse response = new GetMilitaryHistoryResponse();
        MilitaryHistory militaryHistory = new MilitaryHistory();
        response.setGetMilitaryHistoryReturn(militaryHistory);
        
        String icn = (request != null && request.getCriteria() != null) ? request.getCriteria().getICN() : null;
        if (icn == null) {
        	logger.error("ICN is not present");
        	return response;
        }
        String edipi = null;
        String str[] = StringUtils.split(icn, ICN_DELIMITER);
        if (str != null && str.length == 2) {
        	edipi = str[1];
        }
        if (edipi == null) {
        	logger.error("EDIPI is not present");
        	return response;
        }
        EMISMilitaryInformationSerivcePortTypes_Service ss = new EMISMilitaryInformationSerivcePortTypes_Service(wsdlURL, SERVICE_NAME);
        EMISMilitaryInformationSerivcePortTypes port = ss.getEMISMilitaryInformationSerivcePort();        
        
        {
        	log("\n\nInvoking getDisabilities...");
            gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn _getDisabilities_parameter = null;
            _getDisabilities_parameter = new gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn();
    		gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn input = new gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn();
    		input.setEdipiORicnValue(edipi); //"6001010001"
    		input.setInputType(EDIPI);
            _getDisabilities_parameter.setEdipiORicn(input);
            gov.va.viers.cdi.emis.requestresponse.v1.EMISdisabilitiesResponseType _getDisabilities__return = port.getDisabilities(_getDisabilities_parameter);
            log("getDisabilities.result=" + _getDisabilities__return);
            java.util.List<gov.va.viers.cdi.emis.commonservice.v1.Disability> list = _getDisabilities__return.getDisabilities();
            log("getDisabilities returned response");
            		
            if (list != null && list.size() > 0) {
	    		log("getDisabilities Edipi=" + list.get(0).getEdipi());
	    		String permTempInd = list.get(0).getPermanentTemporaryIndicator();
	    		log("getDisabilities PermanentTemporaryIndicator=" + permTempInd);
	    		
	    		//Map eMIS to MSDS Vadir
	    		BIRLS birls = militaryHistory.getBIRLS();
	    		if (birls == null) {
	    			birls = new BIRLS();
	    		}
	    		if (DISABILITY_PERM_TEMP_IND.equalsIgnoreCase(permTempInd)) {
	    			birls.setDisabilityInd("D");
	    		} else if (StringUtils.isNotEmpty(permTempInd)) {
	    			birls.setDisabilityInd("E");
	    		}
	    		militaryHistory.setBIRLS(birls);
            }
        }

        {
            log("\n\nInvoking getRetirement...");
            gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn _getRetirement_parameter = null;
            _getRetirement_parameter = new gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn();
    		gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn input = new gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn();
    		input.setEdipiORicnValue(edipi); //"6001010001"
    		input.setInputType(EDIPI);
    		_getRetirement_parameter.setEdipiORicn(input);
            gov.va.viers.cdi.emis.requestresponse.v1.EMISretirementResponseType _getRetirement__return = port.getRetirement(_getRetirement_parameter);
            log("getRetirement.result=" + _getRetirement__return);
    		java.util.List<gov.va.viers.cdi.emis.commonservice.v1.Retirement> list = _getRetirement__return.getRetirement();
    		log("getRetirement returned response");
    		
            if (list != null && list.size() > 0) {
        		log("getRetirement Edipi=" + list.get(0).getEdipi());
	    		String persCategoryType = list.get(0).getKeyData().getPersonnelCategoryTypeCode();
        		log("getRetirement PersonnelCategoryTypeCode=" +  persCategoryType);
	    		
	    		//Map eMIS to MSDS Vadir
	    		VADIR vadir = militaryHistory.getVADIR();
	    		if (vadir == null) {
	    			vadir = new VADIR();
	    		}
	    		vadir.setRetirementStatusIndicator(persCategoryType); 	
	    		militaryHistory.setVADIR(vadir);
            }    		
        }
        
        //Populate eMIS deployments
		List<gov.va.viers.cdi.emis.commonservice.v1.Deployment> eMisDeployments = null;
        {
            log("Invoking getDeployment...");
            gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn _getDeployment_parameter = null;
            _getDeployment_parameter = new gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn();
    		gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn input = new gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn();
    		input.setEdipiORicnValue(edipi); //"6001010001"
    		input.setInputType(EDIPI);
    		_getDeployment_parameter.setEdipiORicn(input);
            gov.va.viers.cdi.emis.requestresponse.v1.EMISdeploymentResponseType _getDeployment__return = port.getDeployment(_getDeployment_parameter);
            log("getDeployment.result=" + _getDeployment__return);
            eMisDeployments = _getDeployment__return.getDeployment();
            log("getDeployment eMisDeployments=" + eMisDeployments);
        }
        
        {
        	log("\n\nInvoking getMilitaryServiceEligibilityInfo...");
            gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn _getMilitaryServiceEligibilityInfo_parameter = null;
            _getMilitaryServiceEligibilityInfo_parameter = new gov.va.viers.cdi.emis.requestresponse.v1.InputEdiPiOrIcn();
    		gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn input = new gov.va.viers.cdi.emis.commonservice.v1.InputEdipiIcn();
    		input.setEdipiORicnValue(edipi); //"6001010001"
    		input.setInputType(EDIPI);
    		_getMilitaryServiceEligibilityInfo_parameter.setEdipiORicn(input);
            gov.va.viers.cdi.emis.requestresponse.v1.EMISmilitaryServiceEligibilityResponseType _getMilitaryServiceEligibilityInfo__return = port.getMilitaryServiceEligibilityInfo(_getMilitaryServiceEligibilityInfo_parameter);
            log("getMilitaryServiceEligibilityInfo.result=" + _getMilitaryServiceEligibilityInfo__return);
    		java.util.List<gov.va.viers.cdi.emis.commonservice.v1.MilitaryServiceEligibility> list = _getMilitaryServiceEligibilityInfo__return.getMilitaryServiceEligibility();    		
    		log("getMilitaryServiceEligibilityInfo returned response");
    		
            if (list != null && list.size() > 0) {
        		log("getMilitaryServiceEligibilityInfo Edipi=" + list.get(0).getEdipi());
        		String post911Ind = list.get(0).getVeteranStatus().getPost911DeploymentIndicator();
        		log("getMilitaryServiceEligibilityInfo Post911DeploymentIndicator=" + post911Ind);
	    		
	    		//Map eMIS VADIR to MSDS Vadir
	    		VADIR vadir = militaryHistory.getVADIR();
	    		if (vadir == null) {
	    			vadir = new VADIR();
	    		}
	    		BIRLS birls = militaryHistory.getBIRLS();
	    		if (birls == null) {
	    			birls = new BIRLS();
	    		}
	    		/**
	    		 * ToDo: Check with eMIS Team 
	    		 * for mapping Y/N value of getPost911DeploymentIndicator to '03' value of setOefOifIndicator, 
	    		 * on how?
	    		 */
	    		//if (YES_INDICATOR.equalsIgnoreCase(post911Ind)) {
	    		//	vadir.setOefOifIndicator(OEFOIF_CONFLICT_SYNADID_IND);
	    		//}
	    		 		
	    		
	    		List<MilitaryServiceEpisodeEligibilityData> episodes = list.get(0).getMilitaryServiceEpisodes();
	    		if (episodes != null && episodes.size() > 0) {
	    			
	    			List<ServicePeriod> servicePeriods = vadir.getServicePeriods();
	    			List<PeriodOfService> periodOfServices = birls.getPeriodOfService();
	    			
	    			for (MilitaryServiceEpisodeEligibilityData episode : episodes) {
	    				ServicePeriod servicePeriod = new ServicePeriod();
	    				servicePeriod.setStartDate(episode.getServiceEpisodeStartDate());	    				
	    				servicePeriod.setEndDate(episode.getServiceEpisodeEndDate());
	    				servicePeriod.setBranchOfService(episode.getBranchOfServiceCode());
	    				servicePeriod.setCharacterOfService(episode.getDischargeCharacterOfServiceCode());
	    				
	    				PeriodOfService periodOfService = new PeriodOfService();
	    				periodOfService.setEnteredOnDutyDate(episode.getServiceEpisodeStartDate());	    				
	    				periodOfService.setReleasedActiveDutyDate(episode.getServiceEpisodeEndDate());
	    				periodOfService.setBranchOfService(episode.getBranchOfServiceCode());
	    				periodOfService.setCharacterOfService(episode.getDischargeCharacterOfServiceCode());
	    				periodOfService.setSeparationReason(episode.getNarrativeReasonForSeparationCode());
	    				periodOfServices.add(periodOfService);
	    				
	    				KeyData keyData = episode.getKeyData();
	    				if (keyData != null) {
	    					servicePeriod.setPersonnelCategory(keyData.getPersonnelCategoryTypeCode());
	    				}

	    				
	    				//Populate deployments
	    				List<DeploymentEligibilityData> deployments = episode.getDeployments();
	    	    		if (deployments != null && deployments.size() > 0) {
	    	    			List<Deployment> msdsDeployments = servicePeriod.getDeployments();
	    	    			for (DeploymentEligibilityData deployment : deployments) {
	    	    				Deployment msdsDeployment = new Deployment();
	    	    				msdsDeployment.setStartDate(deployment.getDeploymentStartDate());
	    	    				msdsDeployment.setEndDate(deployment.getDeploymentEndDate());
	    	    				String terminationReason = getDeploymentTerminationReason(eMisDeployments, deployment.getDeploymentSegmentIdentifier());
	    	    				msdsDeployment.setTerminationRsn(terminationReason); 
	    	    				
	    	    				String location = "";
	    	    	    		if (NINEGF.equalsIgnoreCase(deployment.getDeploymentProjectCode())) {
	    	    	    			vadir.setOefOifIndicator(OEFOIF_CONFLICT_SYNADID_IND);
	    	    	    			location = UNK_OEFOIF_LOCATION; //No need to map as oefOifIndicator value will drive this
	    	    	    		}

	    	    				List<DeploymentLocationEligibilityData> locations = deployment.getDeploymentLocation(); 
	    	    				if (locations != null && locations.size() > 0) {
	    	    					msdsDeployment.setLocation(locations.get(0).getDeploymentCountryCode());
	    	    				}

	    	    				msdsDeployments.add(msdsDeployment);
	    	    			}
	    	    		}	
	    	    		
	    	    		//Populate activations
	    				List<GuardReserveServicePeriodsEligibilityData> activations = episode.getGuardReserveActiveDuty();
	    	    		if (activations != null && activations.size() > 0) {
	    	    			List<Activation> msdsActivations = servicePeriod.getActivations();
	    	    			for (GuardReserveServicePeriodsEligibilityData activation : activations) {
	    	    				//Ignore record if training indicator is Y
	    	    				if(!YES_INDICATOR.equalsIgnoreCase(activation.getTrainingIndicatorCode())) {
	    	    					Boolean isFilterPerStatuteCode = GuardReserveStatuteCodes.get(activation.getGuardReservePeriodStatuteCode());
	    	    					//Ignore record if filter statute code is Yes -> true
	    	    					if (isFilterPerStatuteCode == null || isFilterPerStatuteCode == false) {
			    	    				Activation msdsActivation = new Activation();
			    	    				
			    	    				String location = "";
			    	    	    		if (NINEGF.equalsIgnoreCase(activation.getGuardReservePeriodProjectCode())) {
			    	    	    			vadir.setOefOifIndicator(OEFOIF_CONFLICT_SYNADID_IND);
			    	    	    			location = UNK_OEFOIF_LOCATION; //No need to map as oefOifIndicator value will drive this
			    	    	    		}
			    	    	    		
			    	    				msdsActivation.setStartDate(activation.getGuardReservePeriodStartDate());
			    	    				msdsActivation.setEndDate(activation.getGuardReservePeriodEndDate());
			    	    				//Brian confirmed its ok to use value of "C" than activation.getNarrativeReasonForSeparationCode() of invalid value "999"
			    	    				msdsActivation.setTerminationRsn("C");
			    	    				msdsActivation.setCharacterOfService(activation.getGuardReservePeriodCharacterOfServiceCode());
			    	    				msdsActivations.add(msdsActivation);
	    	    					}
	    	    				}
	    	    			}
	    	    		}	    				
	    	    		
	    	    		//Populate payments
	    				List<CombatPayData> combatpayData = episode.getCombatPay();
	    	    		if (combatpayData != null && combatpayData.size() > 0) {
	    	    			List<MilitaryPay> msdsMilitaryPays = servicePeriod.getMilitaryPayments();
	    	    			for (CombatPayData combatPay : combatpayData) {
	    	    				MilitaryPay msdsMilitaryPay = new MilitaryPay();
	    	    				msdsMilitaryPay.setStartDate(combatPay.getCombatPayBeginDate());
	    	    				msdsMilitaryPay.setEndDate(combatPay.getCombatPayEndDate());
	    	    				msdsMilitaryPay.setCombatServiceLocation(combatPay.getCombatZoneCountryCode());
	    	    				msdsMilitaryPays.add(msdsMilitaryPay);
	    	    			}
	    	    		}
	    	    		
	    				servicePeriods.add(servicePeriod);
	    			}
	    		}
	    		
	    		//Map eMIS BIRLS inds to MSDS BIRLS inds	
	    		List<PurpleHeartOrMohData> phOrHonInds = list.get(0).getPurpleHeartOrMoh();
	    		if (phOrHonInds != null && phOrHonInds.size() > 0) {
	    			for (PurpleHeartOrMohData phOrHonInd : phOrHonInds) {
	    				if (PURPLE_HEART_CODE.equalsIgnoreCase(phOrHonInd.getPurpleHeartOrMohCode())) {
	    					birls.setPurpleHeartInd(YES_INDICATOR);
	    				} else if (MEDAL_OF_HONOR_CODE.equalsIgnoreCase(phOrHonInd.getPurpleHeartOrMohCode())) {
	    					birls.setMedalOfHonorInd(YES_INDICATOR);
	    				}
	    			}
	    		}
	    		militaryHistory.setBIRLS(birls);
	    		militaryHistory.setVADIR(vadir);
            }     		

        }        
        return response;    
    }
    
    public String getDeploymentTerminationReason(List<gov.va.viers.cdi.emis.commonservice.v1.Deployment> eMisDeployments, String segmentId) {
    	String terminationReason = null;
    	if (eMisDeployments != null && eMisDeployments.size() > 0 && StringUtils.isNotEmpty(segmentId)) {
    		for (gov.va.viers.cdi.emis.commonservice.v1.Deployment eMisDeployment : eMisDeployments) {
    			DeploymentData deploymentData = eMisDeployment.getDeploymentData();
    			if (segmentId.equals(deploymentData.getDeploymentSegmentIdentifier())) {
    				terminationReason = deploymentData.getDeploymentTerminationReason();
    				break;
    			}
    			
    		}
    	}
    	return terminationReason;
    }
    
    private void log(String msg) {
    	logger.trace(msg);
    }
    
    public static void main(String[] args) throws Exception  {
    	
    	SearchCriteria searchCriteria = new SearchCriteria();
     	searchCriteria.setICN("1008593828V177944^6001010001");
    	/*
    	 * 6001010001
		 * 6000000064
		 * 6001010086 
		 * 6001010046
    	 */
    	GetMilitaryHistory request = new GetMilitaryHistory();
		request.setCriteria(searchCriteria);
    	EMISMilitaryInformationServiceClient client = new EMISMilitaryInformationServiceClient();
    	client.setEmisWsdlUrl("http://DNS   rsapp81.aac.DNS   :80/VIERSService/eMIS/v1/MilitaryInformationService");
    	GetMilitaryHistoryResponse resultObj = client.getMilitaryHistory(request);
    	System.out.println("resultObj="+resultObj);
    	client.log("eMIS request/response", request, resultObj);
    	
    	searchCriteria.setICN("1008593828V177944^6000000064");
    	request = new GetMilitaryHistory();
		request.setCriteria(searchCriteria);
    	resultObj = client.getMilitaryHistory(request);
    	System.out.println("resultObj="+resultObj);
    	client.log("eMIS request/response", request, resultObj);    	
    	
    	searchCriteria.setICN("1008593828V177944^6001010086");
    	request = new GetMilitaryHistory();
		request.setCriteria(searchCriteria);
    	resultObj = client.getMilitaryHistory(request);
    	System.out.println("resultObj="+resultObj);
    	client.log("eMIS request/response", request, resultObj);  
    	
    	searchCriteria.setICN("1008593828V177944^6001010046");
    	request = new GetMilitaryHistory();
		request.setCriteria(searchCriteria);
    	resultObj = client.getMilitaryHistory(request);
    	System.out.println("resultObj="+resultObj);
    	client.log("eMIS request/response", request, resultObj);  
    	
    	searchCriteria.setICN("1008593828V177944^6001010046666");
    	request = new GetMilitaryHistory();
		request.setCriteria(searchCriteria);
    	resultObj = client.getMilitaryHistory(request);
    	System.out.println("resultObj="+resultObj);
    	client.log("eMIS request/response", request, resultObj);     	
    }
    
	public void log(String tag, Object request, Object response) {
		logger.debug(tag);

        try {
        	if (request instanceof GetMilitaryHistory) {
        		logger.debug("Printing request");
				jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
				java.io.StringWriter sw = new StringWriter();
				jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
				jaxbMarshaller.marshal((GetMilitaryHistory)request, sw);
				logger.debug(sw.toString());
        	}
        	if (response instanceof GetMilitaryHistoryResponse) {
        		logger.debug("Printing response");
			    jaxbMarshallerResp.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			    java.io.StringWriter sw = new StringWriter();
				jaxbMarshallerResp.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
				jaxbMarshallerResp.marshal((GetMilitaryHistoryResponse)response, sw);
				logger.debug(sw.toString());
        	}

	      } catch (JAXBException e) {
	    	  log("Error occured in marshalling XML "+ e.getMessage());
	      }		
	}
}
